Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : :
28 : : #include <pulsecore/macro.h>
29 : : #include <pulsecore/g711.h>
30 : : #include <pulsecore/endianmacros.h>
31 : :
32 : : #include "sample-util.h"
33 : :
34 : 1 : static void pa_volume_u8_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
35 : : unsigned channel;
36 : :
37 [ + + ]: 11 : for (channel = 0; length; length--) {
38 : : int32_t t, hi, lo;
39 : :
40 : 10 : hi = volumes[channel] >> 16;
41 : 10 : lo = volumes[channel] & 0xFFFF;
42 : :
43 : 10 : t = (int32_t) *samples - 0x80;
44 : 10 : t = ((t * lo) >> 16) + (t * hi);
45 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
46 : 10 : *samples++ = (uint8_t) (t + 0x80);
47 : :
48 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
49 : 10 : channel = 0;
50 : : }
51 : 1 : }
52 : :
53 : 1 : static void pa_volume_alaw_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
54 : : unsigned channel;
55 : :
56 [ + + ]: 11 : for (channel = 0; length; length--) {
57 : : int32_t t, hi, lo;
58 : :
59 : 10 : hi = volumes[channel] >> 16;
60 : 10 : lo = volumes[channel] & 0xFFFF;
61 : :
62 : 10 : t = (int32_t) st_alaw2linear16(*samples);
63 : 10 : t = ((t * lo) >> 16) + (t * hi);
64 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
65 : 10 : *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3);
66 : :
67 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
68 : 10 : channel = 0;
69 : : }
70 : 1 : }
71 : :
72 : 1 : static void pa_volume_ulaw_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
73 : : unsigned channel;
74 : :
75 [ + + ]: 11 : for (channel = 0; length; length--) {
76 : : int32_t t, hi, lo;
77 : :
78 : 10 : hi = volumes[channel] >> 16;
79 : 10 : lo = volumes[channel] & 0xFFFF;
80 : :
81 : 10 : t = (int32_t) st_ulaw2linear16(*samples);
82 : 10 : t = ((t * lo) >> 16) + (t * hi);
83 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
84 : 10 : *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
85 : :
86 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
87 : 10 : channel = 0;
88 : : }
89 : 1 : }
90 : :
91 : 1 : static void pa_volume_s16ne_c(int16_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
92 : : unsigned channel;
93 : :
94 : 1 : length /= sizeof(int16_t);
95 : :
96 [ + + ]: 11 : for (channel = 0; length; length--) {
97 : : int32_t t, hi, lo;
98 : :
99 : : /* Multiplying the 32bit volume factor with the 16bit
100 : : * sample might result in an 48bit value. We want to
101 : : * do without 64 bit integers and hence do the
102 : : * multiplication independently for the HI and LO part
103 : : * of the volume. */
104 : :
105 : 10 : hi = volumes[channel] >> 16;
106 : 10 : lo = volumes[channel] & 0xFFFF;
107 : :
108 : 10 : t = (int32_t)(*samples);
109 : 10 : t = ((t * lo) >> 16) + (t * hi);
110 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
111 : 10 : *samples++ = (int16_t) t;
112 : :
113 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
114 : 10 : channel = 0;
115 : : }
116 : 1 : }
117 : :
118 : 1 : static void pa_volume_s16re_c(int16_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
119 : : unsigned channel;
120 : :
121 : 1 : length /= sizeof(int16_t);
122 : :
123 [ + + ]: 11 : for (channel = 0; length; length--) {
124 : : int32_t t, hi, lo;
125 : :
126 : 10 : hi = volumes[channel] >> 16;
127 : 10 : lo = volumes[channel] & 0xFFFF;
128 : :
129 [ - + ]: 10 : t = (int32_t) PA_INT16_SWAP(*samples);
130 : 10 : t = ((t * lo) >> 16) + (t * hi);
131 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
132 [ - + ]: 10 : *samples++ = PA_INT16_SWAP((int16_t) t);
133 : :
134 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
135 : 10 : channel = 0;
136 : : }
137 : 1 : }
138 : :
139 : 1 : static void pa_volume_float32ne_c(float *samples, const float *volumes, unsigned channels, unsigned length) {
140 : : unsigned channel;
141 : :
142 : 1 : length /= sizeof(float);
143 : :
144 [ + + ]: 11 : for (channel = 0; length; length--) {
145 : 10 : *samples++ *= volumes[channel];
146 : :
147 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
148 : 10 : channel = 0;
149 : : }
150 : 1 : }
151 : :
152 : 1 : static void pa_volume_float32re_c(float *samples, float *volumes, unsigned channels, unsigned length) {
153 : : unsigned channel;
154 : :
155 : 1 : length /= sizeof(float);
156 : :
157 [ + + ]: 11 : for (channel = 0; length; length--) {
158 : : float t;
159 : :
160 : 20 : t = PA_FLOAT32_SWAP(*samples);
161 : 10 : t *= volumes[channel];
162 : 10 : *samples++ = PA_FLOAT32_SWAP(t);
163 : :
164 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
165 : 10 : channel = 0;
166 : : }
167 : 1 : }
168 : :
169 : 1 : static void pa_volume_s32ne_c(int32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
170 : : unsigned channel;
171 : :
172 : 1 : length /= sizeof(int32_t);
173 : :
174 [ + + ]: 11 : for (channel = 0; length; length--) {
175 : : int64_t t;
176 : :
177 : 10 : t = (int64_t)(*samples);
178 : 10 : t = (t * volumes[channel]) >> 16;
179 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
180 : 10 : *samples++ = (int32_t) t;
181 : :
182 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
183 : 10 : channel = 0;
184 : : }
185 : 1 : }
186 : :
187 : 1 : static void pa_volume_s32re_c(int32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
188 : : unsigned channel;
189 : :
190 : 1 : length /= sizeof(int32_t);
191 : :
192 [ + + ]: 11 : for (channel = 0; length; length--) {
193 : : int64_t t;
194 : :
195 [ - + ]: 10 : t = (int64_t) PA_INT32_SWAP(*samples);
196 : 10 : t = (t * volumes[channel]) >> 16;
197 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
198 [ - + ]: 10 : *samples++ = PA_INT32_SWAP((int32_t) t);
199 : :
200 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
201 : 10 : channel = 0;
202 : : }
203 : 1 : }
204 : :
205 : 1 : static void pa_volume_s24ne_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
206 : : unsigned channel;
207 : : uint8_t *e;
208 : :
209 : 1 : e = samples + length;
210 : :
211 [ + + ]: 11 : for (channel = 0; samples < e; samples += 3) {
212 : : int64_t t;
213 : :
214 : 10 : t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8));
215 : 10 : t = (t * volumes[channel]) >> 16;
216 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
217 : 10 : PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8);
218 : :
219 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
220 : 10 : channel = 0;
221 : : }
222 : 1 : }
223 : :
224 : 1 : static void pa_volume_s24re_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
225 : : unsigned channel;
226 : : uint8_t *e;
227 : :
228 : 1 : e = samples + length;
229 : :
230 [ + + ]: 11 : for (channel = 0; samples < e; samples += 3) {
231 : : int64_t t;
232 : :
233 : 10 : t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8));
234 : 10 : t = (t * volumes[channel]) >> 16;
235 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
236 : 10 : PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8);
237 : :
238 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
239 : 10 : channel = 0;
240 : : }
241 : 1 : }
242 : :
243 : 1 : static void pa_volume_s24_32ne_c(uint32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
244 : : unsigned channel;
245 : :
246 : 1 : length /= sizeof(uint32_t);
247 : :
248 [ + + ]: 11 : for (channel = 0; length; length--) {
249 : : int64_t t;
250 : :
251 : 10 : t = (int64_t) ((int32_t) (*samples << 8));
252 : 10 : t = (t * volumes[channel]) >> 16;
253 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
254 : 10 : *samples++ = ((uint32_t) ((int32_t) t)) >> 8;
255 : :
256 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
257 : 10 : channel = 0;
258 : : }
259 : 1 : }
260 : :
261 : 1 : static void pa_volume_s24_32re_c(uint32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
262 : : unsigned channel;
263 : :
264 : 1 : length /= sizeof(uint32_t);
265 : :
266 [ + + ]: 11 : for (channel = 0; length; length--) {
267 : : int64_t t;
268 : :
269 [ - + ]: 10 : t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8));
270 : 10 : t = (t * volumes[channel]) >> 16;
271 [ + - ][ + - ]: 10 : t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
272 [ - + ]: 10 : *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
273 : :
274 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= channels))
275 : 10 : channel = 0;
276 : : }
277 : 1 : }
278 : :
279 : : static pa_do_volume_func_t do_volume_table[] = {
280 : : [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c,
281 : : [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c,
282 : : [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c,
283 : : [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c,
284 : : [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c,
285 : : [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c,
286 : : [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c,
287 : : [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c,
288 : : [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c,
289 : : [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c,
290 : : [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c,
291 : : [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c,
292 : : [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c
293 : : };
294 : :
295 : 13 : pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f) {
296 [ - + ]: 13 : pa_assert(f >= 0);
297 [ - + ]: 13 : pa_assert(f < PA_SAMPLE_MAX);
298 : :
299 : 13 : return do_volume_table[f];
300 : : }
301 : :
302 : 0 : void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func) {
303 [ # # ]: 0 : pa_assert(f >= 0);
304 [ # # ]: 0 : pa_assert(f < PA_SAMPLE_MAX);
305 : :
306 : 0 : do_volume_table[f] = func;
307 : 0 : }
|