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 : : #include <stdio.h>
28 : : #include <string.h>
29 : : #include <stdlib.h>
30 : : #include <stdio.h>
31 : : #include <errno.h>
32 : : #include <math.h>
33 : :
34 : : #include <pulse/timeval.h>
35 : :
36 : : #include <pulsecore/log.h>
37 : : #include <pulsecore/core-error.h>
38 : : #include <pulsecore/macro.h>
39 : : #include <pulsecore/g711.h>
40 : : #include <pulsecore/core-util.h>
41 : : #include <pulsecore/endianmacros.h>
42 : :
43 : : #include "sample-util.h"
44 : :
45 : : #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
46 : :
47 : 0 : pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
48 : : void *data;
49 : :
50 [ # # ]: 0 : pa_assert(b);
51 [ # # ]: 0 : pa_assert(spec);
52 : :
53 : 0 : data = pa_memblock_acquire(b);
54 : 0 : pa_silence_memory(data, pa_memblock_get_length(b), spec);
55 : 0 : pa_memblock_release(b);
56 : :
57 : 0 : return b;
58 : : }
59 : :
60 : 0 : pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
61 : : void *data;
62 : :
63 [ # # ]: 0 : pa_assert(c);
64 [ # # ]: 0 : pa_assert(c->memblock);
65 [ # # ]: 0 : pa_assert(spec);
66 : :
67 : 0 : data = pa_memblock_acquire(c->memblock);
68 : 0 : pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
69 : 0 : pa_memblock_release(c->memblock);
70 : :
71 : 0 : return c;
72 : : }
73 : :
74 : : static uint8_t silence_byte(pa_sample_format_t format) {
75 [ # # # # : 0 : switch (format) {
# ]
76 : : case PA_SAMPLE_U8:
77 : : return 0x80;
78 : : case PA_SAMPLE_S16LE:
79 : : case PA_SAMPLE_S16BE:
80 : : case PA_SAMPLE_S32LE:
81 : : case PA_SAMPLE_S32BE:
82 : : case PA_SAMPLE_FLOAT32LE:
83 : : case PA_SAMPLE_FLOAT32BE:
84 : : case PA_SAMPLE_S24LE:
85 : : case PA_SAMPLE_S24BE:
86 : : case PA_SAMPLE_S24_32LE:
87 : : case PA_SAMPLE_S24_32BE:
88 : : return 0;
89 : : case PA_SAMPLE_ALAW:
90 : : return 0xd5;
91 : : case PA_SAMPLE_ULAW:
92 : : return 0xff;
93 : : default:
94 : 0 : pa_assert_not_reached();
95 : : }
96 : : }
97 : :
98 : 0 : void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
99 [ # # ]: 0 : pa_assert(p);
100 [ # # ]: 0 : pa_assert(length > 0);
101 [ # # ]: 0 : pa_assert(spec);
102 : :
103 : 0 : memset(p, silence_byte(spec->format), length);
104 : 0 : return p;
105 : : }
106 : :
107 : : #define VOLUME_PADDING 32
108 : :
109 : 11 : static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
110 : : unsigned channel, nchannels, padding;
111 : :
112 [ - + ]: 11 : pa_assert(linear);
113 [ - + ]: 11 : pa_assert(volume);
114 : :
115 : 11 : nchannels = volume->channels;
116 : :
117 [ + + ]: 22 : for (channel = 0; channel < nchannels; channel++)
118 : 11 : linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
119 : :
120 [ + + ]: 363 : for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
121 : 352 : linear[channel] = linear[padding];
122 : 11 : }
123 : :
124 : 15 : static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
125 : : unsigned channel, nchannels, padding;
126 : :
127 [ - + ]: 15 : pa_assert(linear);
128 [ - + ]: 15 : pa_assert(volume);
129 : :
130 : 15 : nchannels = volume->channels;
131 : :
132 [ + + ]: 30 : for (channel = 0; channel < nchannels; channel++)
133 : 15 : linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]);
134 : :
135 [ + + ]: 495 : for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
136 : 480 : linear[channel] = linear[padding];
137 : 15 : }
138 : :
139 : 11 : static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
140 : : unsigned k, channel;
141 : : float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
142 : :
143 [ - + ]: 11 : pa_assert(streams);
144 [ - + ]: 11 : pa_assert(spec);
145 [ - + ]: 11 : pa_assert(volume);
146 : :
147 : 11 : calc_linear_float_volume(linear, volume);
148 : :
149 [ + + ]: 33 : for (k = 0; k < nstreams; k++) {
150 : :
151 [ + + ]: 44 : for (channel = 0; channel < spec->channels; channel++) {
152 : 22 : pa_mix_info *m = streams + k;
153 : 22 : m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000);
154 : : }
155 : : }
156 : 11 : }
157 : :
158 : 2 : static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
159 : : unsigned k, channel;
160 : : float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
161 : :
162 [ - + ]: 2 : pa_assert(streams);
163 [ - + ]: 2 : pa_assert(spec);
164 [ - + ]: 2 : pa_assert(volume);
165 : :
166 : 2 : calc_linear_float_volume(linear, volume);
167 : :
168 [ + + ]: 6 : for (k = 0; k < nstreams; k++) {
169 : :
170 [ + + ]: 8 : for (channel = 0; channel < spec->channels; channel++) {
171 : 4 : pa_mix_info *m = streams + k;
172 : 4 : m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]);
173 : : }
174 : : }
175 : 2 : }
176 : :
177 : 13 : size_t pa_mix(
178 : : pa_mix_info streams[],
179 : : unsigned nstreams,
180 : : void *data,
181 : : size_t length,
182 : : const pa_sample_spec *spec,
183 : : const pa_cvolume *volume,
184 : : pa_bool_t mute) {
185 : :
186 : : pa_cvolume full_volume;
187 : : unsigned k;
188 : : unsigned z;
189 : : void *end;
190 : :
191 [ - + ]: 13 : pa_assert(streams);
192 [ - + ]: 13 : pa_assert(data);
193 [ - + ]: 13 : pa_assert(length);
194 [ - + ]: 13 : pa_assert(spec);
195 : :
196 [ + - ]: 13 : if (!volume)
197 : 13 : volume = pa_cvolume_reset(&full_volume, spec->channels);
198 : :
199 [ + - ][ + - ]: 13 : if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
200 : 0 : pa_silence_memory(data, length, spec);
201 : 0 : return length;
202 : : }
203 : :
204 [ + + ]: 39 : for (k = 0; k < nstreams; k++)
205 : 26 : streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
206 : :
207 [ + + ]: 39 : for (z = 0; z < nstreams; z++)
208 [ - + ]: 26 : if (length > streams[z].chunk.length)
209 : 0 : length = streams[z].chunk.length;
210 : :
211 : 13 : end = (uint8_t*) data + length;
212 : :
213 [ + + + + : 13 : switch (spec->format) {
+ + + + +
+ + + +
- ]
214 : :
215 : : case PA_SAMPLE_S16NE:{
216 : 1 : unsigned channel = 0;
217 : :
218 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
219 : :
220 [ + + ]: 11 : while (data < end) {
221 : : int32_t sum = 0;
222 : : unsigned i;
223 : :
224 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
225 : 20 : pa_mix_info *m = streams + i;
226 : 20 : int32_t v, lo, hi, cv = m->linear[channel].i;
227 : :
228 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
229 : :
230 : : /* Multiplying the 32bit volume factor with the
231 : : * 16bit sample might result in an 48bit value. We
232 : : * want to do without 64 bit integers and hence do
233 : : * the multiplication independently for the HI and
234 : : * LO part of the volume. */
235 : :
236 : 20 : hi = cv >> 16;
237 : 20 : lo = cv & 0xFFFF;
238 : :
239 : 20 : v = *((int16_t*) m->ptr);
240 : 20 : v = ((v * lo) >> 16) + (v * hi);
241 : 20 : sum += v;
242 : : }
243 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
244 : : }
245 : :
246 [ + + ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
247 : 10 : *((int16_t*) data) = (int16_t) sum;
248 : :
249 : 10 : data = (uint8_t*) data + sizeof(int16_t);
250 : :
251 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
252 : 10 : channel = 0;
253 : : }
254 : :
255 : : break;
256 : : }
257 : :
258 : : case PA_SAMPLE_S16RE:{
259 : 1 : unsigned channel = 0;
260 : :
261 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
262 : :
263 [ + + ]: 23 : while (data < end) {
264 : : int32_t sum = 0;
265 : : unsigned i;
266 : :
267 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
268 : 20 : pa_mix_info *m = streams + i;
269 : 20 : int32_t v, lo, hi, cv = m->linear[channel].i;
270 : :
271 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
272 : :
273 : 20 : hi = cv >> 16;
274 : 20 : lo = cv & 0xFFFF;
275 : :
276 [ - + ]: 20 : v = PA_INT16_SWAP(*((int16_t*) m->ptr));
277 : 20 : v = ((v * lo) >> 16) + (v * hi);
278 : 20 : sum += v;
279 : : }
280 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
281 : : }
282 : :
283 [ + - ][ + - ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
284 [ - + ]: 10 : *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
285 : :
286 : 10 : data = (uint8_t*) data + sizeof(int16_t);
287 : :
288 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
289 : 10 : channel = 0;
290 : : }
291 : :
292 : : break;
293 : : }
294 : :
295 : : case PA_SAMPLE_S32NE:{
296 : 1 : unsigned channel = 0;
297 : :
298 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
299 : :
300 [ + + ]: 11 : while (data < end) {
301 : : int64_t sum = 0;
302 : : unsigned i;
303 : :
304 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
305 : 20 : pa_mix_info *m = streams + i;
306 : 20 : int32_t cv = m->linear[channel].i;
307 : : int64_t v;
308 : :
309 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
310 : :
311 : 20 : v = *((int32_t*) m->ptr);
312 : 20 : v = (v * cv) >> 16;
313 : 20 : sum += v;
314 : : }
315 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
316 : : }
317 : :
318 [ + + ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
319 : 10 : *((int32_t*) data) = (int32_t) sum;
320 : :
321 : 10 : data = (uint8_t*) data + sizeof(int32_t);
322 : :
323 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
324 : 10 : channel = 0;
325 : : }
326 : :
327 : : break;
328 : : }
329 : :
330 : : case PA_SAMPLE_S32RE:{
331 : 1 : unsigned channel = 0;
332 : :
333 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
334 : :
335 [ + + ]: 11 : while (data < end) {
336 : : int64_t sum = 0;
337 : : unsigned i;
338 : :
339 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
340 : 20 : pa_mix_info *m = streams + i;
341 : 20 : int32_t cv = m->linear[channel].i;
342 : : int64_t v;
343 : :
344 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
345 : :
346 [ - + ]: 20 : v = PA_INT32_SWAP(*((int32_t*) m->ptr));
347 : 20 : v = (v * cv) >> 16;
348 : 20 : sum += v;
349 : : }
350 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
351 : : }
352 : :
353 [ + - ][ + - ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
354 [ - + ]: 10 : *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
355 : :
356 : 10 : data = (uint8_t*) data + sizeof(int32_t);
357 : :
358 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
359 : 10 : channel = 0;
360 : : }
361 : :
362 : : break;
363 : : }
364 : :
365 : : case PA_SAMPLE_S24NE: {
366 : 1 : unsigned channel = 0;
367 : :
368 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
369 : :
370 [ + + ]: 11 : while (data < end) {
371 : : int64_t sum = 0;
372 : : unsigned i;
373 : :
374 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
375 : 20 : pa_mix_info *m = streams + i;
376 : 20 : int32_t cv = m->linear[channel].i;
377 : : int64_t v;
378 : :
379 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
380 : :
381 : 40 : v = (int32_t) (PA_READ24NE(m->ptr) << 8);
382 : 20 : v = (v * cv) >> 16;
383 : 20 : sum += v;
384 : : }
385 : 20 : m->ptr = (uint8_t*) m->ptr + 3;
386 : : }
387 : :
388 [ + - ][ + - ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
389 : 10 : PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
390 : :
391 : 10 : data = (uint8_t*) data + 3;
392 : :
393 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
394 : 10 : channel = 0;
395 : : }
396 : :
397 : : break;
398 : : }
399 : :
400 : : case PA_SAMPLE_S24RE: {
401 : 1 : unsigned channel = 0;
402 : :
403 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
404 : :
405 [ + + ]: 11 : while (data < end) {
406 : : int64_t sum = 0;
407 : : unsigned i;
408 : :
409 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
410 : 20 : pa_mix_info *m = streams + i;
411 : 20 : int32_t cv = m->linear[channel].i;
412 : : int64_t v;
413 : :
414 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
415 : :
416 : 40 : v = (int32_t) (PA_READ24RE(m->ptr) << 8);
417 : 20 : v = (v * cv) >> 16;
418 : 20 : sum += v;
419 : : }
420 : 20 : m->ptr = (uint8_t*) m->ptr + 3;
421 : : }
422 : :
423 [ + + ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
424 : 10 : PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
425 : :
426 : 10 : data = (uint8_t*) data + 3;
427 : :
428 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
429 : 10 : channel = 0;
430 : : }
431 : :
432 : : break;
433 : : }
434 : :
435 : : case PA_SAMPLE_S24_32NE: {
436 : 1 : unsigned channel = 0;
437 : :
438 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
439 : :
440 [ + + ]: 11 : while (data < end) {
441 : : int64_t sum = 0;
442 : : unsigned i;
443 : :
444 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
445 : 20 : pa_mix_info *m = streams + i;
446 : 20 : int32_t cv = m->linear[channel].i;
447 : : int64_t v;
448 : :
449 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
450 : :
451 : 20 : v = (int32_t) (*((uint32_t*)m->ptr) << 8);
452 : 20 : v = (v * cv) >> 16;
453 : 20 : sum += v;
454 : : }
455 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
456 : : }
457 : :
458 [ + - ][ + - ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
459 : 10 : *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
460 : :
461 : 10 : data = (uint8_t*) data + sizeof(uint32_t);
462 : :
463 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
464 : 10 : channel = 0;
465 : : }
466 : :
467 : : break;
468 : : }
469 : :
470 : : case PA_SAMPLE_S24_32RE: {
471 : 1 : unsigned channel = 0;
472 : :
473 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
474 : :
475 [ + + ]: 11 : while (data < end) {
476 : : int64_t sum = 0;
477 : : unsigned i;
478 : :
479 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
480 : 20 : pa_mix_info *m = streams + i;
481 : 20 : int32_t cv = m->linear[channel].i;
482 : : int64_t v;
483 : :
484 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
485 : :
486 [ - + ]: 20 : v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
487 : 20 : v = (v * cv) >> 16;
488 : 20 : sum += v;
489 : : }
490 : 20 : m->ptr = (uint8_t*) m->ptr + 3;
491 : : }
492 : :
493 [ + - ][ + - ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
494 [ - + ]: 10 : *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
495 : :
496 : 10 : data = (uint8_t*) data + sizeof(uint32_t);
497 : :
498 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
499 : 10 : channel = 0;
500 : : }
501 : :
502 : : break;
503 : : }
504 : :
505 : : case PA_SAMPLE_U8: {
506 : 1 : unsigned channel = 0;
507 : :
508 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
509 : :
510 [ + + ]: 11 : while (data < end) {
511 : : int32_t sum = 0;
512 : : unsigned i;
513 : :
514 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
515 : 20 : pa_mix_info *m = streams + i;
516 : 20 : int32_t v, cv = m->linear[channel].i;
517 : :
518 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
519 : :
520 : 20 : v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
521 : 20 : v = (v * cv) >> 16;
522 : 20 : sum += v;
523 : : }
524 : 20 : m->ptr = (uint8_t*) m->ptr + 1;
525 : : }
526 : :
527 [ + + ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
528 : 10 : *((uint8_t*) data) = (uint8_t) (sum + 0x80);
529 : :
530 : 10 : data = (uint8_t*) data + 1;
531 : :
532 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
533 : 10 : channel = 0;
534 : : }
535 : :
536 : : break;
537 : : }
538 : :
539 : : case PA_SAMPLE_ULAW: {
540 : 1 : unsigned channel = 0;
541 : :
542 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
543 : :
544 [ + + ]: 11 : while (data < end) {
545 : : int32_t sum = 0;
546 : : unsigned i;
547 : :
548 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
549 : 20 : pa_mix_info *m = streams + i;
550 : 20 : int32_t v, hi, lo, cv = m->linear[channel].i;
551 : :
552 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
553 : :
554 : 20 : hi = cv >> 16;
555 : 20 : lo = cv & 0xFFFF;
556 : :
557 : 20 : v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
558 : 20 : v = ((v * lo) >> 16) + (v * hi);
559 : 20 : sum += v;
560 : : }
561 : 20 : m->ptr = (uint8_t*) m->ptr + 1;
562 : : }
563 : :
564 [ + + ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
565 : 10 : *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
566 : :
567 : 10 : data = (uint8_t*) data + 1;
568 : :
569 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
570 : 10 : channel = 0;
571 : : }
572 : :
573 : : break;
574 : : }
575 : :
576 : : case PA_SAMPLE_ALAW: {
577 : 1 : unsigned channel = 0;
578 : :
579 : 1 : calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
580 : :
581 [ + + ]: 11 : while (data < end) {
582 : : int32_t sum = 0;
583 : : unsigned i;
584 : :
585 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
586 : 20 : pa_mix_info *m = streams + i;
587 : 20 : int32_t v, hi, lo, cv = m->linear[channel].i;
588 : :
589 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
590 : :
591 : 20 : hi = cv >> 16;
592 : 20 : lo = cv & 0xFFFF;
593 : :
594 : 20 : v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
595 : 20 : v = ((v * lo) >> 16) + (v * hi);
596 : 20 : sum += v;
597 : : }
598 : 20 : m->ptr = (uint8_t*) m->ptr + 1;
599 : : }
600 : :
601 [ + - ][ + + ]: 10 : sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
602 : 10 : *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
603 : :
604 : 10 : data = (uint8_t*) data + 1;
605 : :
606 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
607 : 10 : channel = 0;
608 : : }
609 : :
610 : : break;
611 : : }
612 : :
613 : : case PA_SAMPLE_FLOAT32NE: {
614 : 1 : unsigned channel = 0;
615 : :
616 : 1 : calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
617 : :
618 [ + + ]: 11 : while (data < end) {
619 : : float sum = 0;
620 : : unsigned i;
621 : :
622 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
623 : 20 : pa_mix_info *m = streams + i;
624 : 20 : float v, cv = m->linear[channel].f;
625 : :
626 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
627 : :
628 : 20 : v = *((float*) m->ptr);
629 : 20 : v *= cv;
630 : 20 : sum += v;
631 : : }
632 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(float);
633 : : }
634 : :
635 : 10 : *((float*) data) = sum;
636 : :
637 : 10 : data = (uint8_t*) data + sizeof(float);
638 : :
639 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
640 : 10 : channel = 0;
641 : : }
642 : :
643 : : break;
644 : : }
645 : :
646 : : case PA_SAMPLE_FLOAT32RE: {
647 : 1 : unsigned channel = 0;
648 : :
649 : 1 : calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
650 : :
651 [ + + ]: 11 : while (data < end) {
652 : : float sum = 0;
653 : : unsigned i;
654 : :
655 [ + + ]: 30 : for (i = 0; i < nstreams; i++) {
656 : 20 : pa_mix_info *m = streams + i;
657 : 20 : float v, cv = m->linear[channel].f;
658 : :
659 [ + - ]: 20 : if (PA_LIKELY(cv > 0)) {
660 : :
661 : 40 : v = PA_FLOAT32_SWAP(*(float*) m->ptr);
662 : 20 : v *= cv;
663 : 20 : sum += v;
664 : : }
665 : 20 : m->ptr = (uint8_t*) m->ptr + sizeof(float);
666 : : }
667 : :
668 : 10 : *((float*) data) = PA_FLOAT32_SWAP(sum);
669 : :
670 : 10 : data = (uint8_t*) data + sizeof(float);
671 : :
672 [ + - ]: 10 : if (PA_UNLIKELY(++channel >= spec->channels))
673 : 10 : channel = 0;
674 : : }
675 : :
676 : : break;
677 : : }
678 : :
679 : : default:
680 : 0 : pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
681 : 0 : pa_assert_not_reached();
682 : : }
683 : :
684 [ + + ]: 39 : for (k = 0; k < nstreams; k++)
685 : 26 : pa_memblock_release(streams[k].chunk.memblock);
686 : :
687 : : return length;
688 : : }
689 : :
690 : : typedef union {
691 : : float f;
692 : : uint32_t i;
693 : : } volume_val;
694 : :
695 : : typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
696 : :
697 : : static const pa_calc_volume_func_t calc_volume_table[] = {
698 : : [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume,
699 : : [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
700 : : [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
701 : : [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
702 : : [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
703 : : [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
704 : : [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
705 : : [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
706 : : [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
707 : : [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
708 : : [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
709 : : [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
710 : : [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume
711 : : };
712 : :
713 : 13 : void pa_volume_memchunk(
714 : : pa_memchunk*c,
715 : : const pa_sample_spec *spec,
716 : : const pa_cvolume *volume) {
717 : :
718 : : void *ptr;
719 : : volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
720 : : pa_do_volume_func_t do_volume;
721 : :
722 [ - + ]: 13 : pa_assert(c);
723 [ - + ]: 13 : pa_assert(spec);
724 [ - + ]: 13 : pa_assert(pa_sample_spec_valid(spec));
725 [ - + ]: 13 : pa_assert(pa_frame_aligned(c->length, spec));
726 [ - + ]: 13 : pa_assert(volume);
727 : :
728 [ + - ]: 13 : if (pa_memblock_is_silence(c->memblock))
729 : : return;
730 : :
731 [ + - ]: 13 : if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
732 : : return;
733 : :
734 [ - + ]: 13 : if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
735 : 0 : pa_silence_memchunk(c, spec);
736 : 0 : return;
737 : : }
738 : :
739 : 13 : do_volume = pa_get_volume_func(spec->format);
740 [ - + ]: 13 : pa_assert(do_volume);
741 : :
742 : 13 : calc_volume_table[spec->format] ((void *)linear, volume);
743 : :
744 : 13 : ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
745 : :
746 : 13 : do_volume (ptr, (void *)linear, spec->channels, c->length);
747 : :
748 : 13 : pa_memblock_release(c->memblock);
749 : : }
750 : :
751 : 0 : size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
752 : : size_t fs;
753 : :
754 [ # # ]: 0 : pa_assert(ss);
755 : :
756 : 0 : fs = pa_frame_size(ss);
757 : :
758 : 0 : return (l/fs) * fs;
759 : : }
760 : :
761 : 13 : pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
762 : : size_t fs;
763 : :
764 [ - + ]: 13 : pa_assert(ss);
765 : :
766 : 13 : fs = pa_frame_size(ss);
767 : :
768 : 13 : return l % fs == 0;
769 : : }
770 : :
771 : 0 : void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
772 : : unsigned c;
773 : : size_t fs;
774 : :
775 [ # # ]: 0 : pa_assert(src);
776 [ # # ]: 0 : pa_assert(channels > 0);
777 [ # # ]: 0 : pa_assert(dst);
778 [ # # ]: 0 : pa_assert(ss > 0);
779 [ # # ]: 0 : pa_assert(n > 0);
780 : :
781 : 0 : fs = ss * channels;
782 : :
783 [ # # ]: 0 : for (c = 0; c < channels; c++) {
784 : : unsigned j;
785 : : void *d;
786 : : const void *s;
787 : :
788 : 0 : s = src[c];
789 : 0 : d = (uint8_t*) dst + c * ss;
790 : :
791 [ # # ]: 0 : for (j = 0; j < n; j ++) {
792 : 0 : memcpy(d, s, (int) ss);
793 : 0 : s = (uint8_t*) s + ss;
794 : 0 : d = (uint8_t*) d + fs;
795 : : }
796 : : }
797 : 0 : }
798 : :
799 : 0 : void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
800 : : size_t fs;
801 : : unsigned c;
802 : :
803 [ # # ]: 0 : pa_assert(src);
804 [ # # ]: 0 : pa_assert(dst);
805 [ # # ]: 0 : pa_assert(channels > 0);
806 [ # # ]: 0 : pa_assert(ss > 0);
807 [ # # ]: 0 : pa_assert(n > 0);
808 : :
809 : 0 : fs = ss * channels;
810 : :
811 [ # # ]: 0 : for (c = 0; c < channels; c++) {
812 : : unsigned j;
813 : : const void *s;
814 : : void *d;
815 : :
816 : 0 : s = (uint8_t*) src + c * ss;
817 : 0 : d = dst[c];
818 : :
819 [ # # ]: 0 : for (j = 0; j < n; j ++) {
820 : 0 : memcpy(d, s, (int) ss);
821 : 0 : s = (uint8_t*) s + fs;
822 : 0 : d = (uint8_t*) d + ss;
823 : : }
824 : : }
825 : 0 : }
826 : :
827 : 0 : static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
828 : : pa_memblock *b;
829 : : size_t length;
830 : : void *data;
831 : :
832 [ # # ]: 0 : pa_assert(pool);
833 : :
834 : 0 : length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);
835 : :
836 : 0 : b = pa_memblock_new(pool, length);
837 : :
838 : 0 : data = pa_memblock_acquire(b);
839 : 0 : memset(data, c, length);
840 : 0 : pa_memblock_release(b);
841 : :
842 : 0 : pa_memblock_set_is_silence(b, TRUE);
843 : :
844 : 0 : return b;
845 : : }
846 : :
847 : 0 : void pa_silence_cache_init(pa_silence_cache *cache) {
848 [ # # ]: 0 : pa_assert(cache);
849 : :
850 : : memset(cache, 0, sizeof(pa_silence_cache));
851 : 0 : }
852 : :
853 : 0 : void pa_silence_cache_done(pa_silence_cache *cache) {
854 : : pa_sample_format_t f;
855 [ # # ]: 0 : pa_assert(cache);
856 : :
857 [ # # ]: 0 : for (f = 0; f < PA_SAMPLE_MAX; f++)
858 [ # # ]: 0 : if (cache->blocks[f])
859 : 0 : pa_memblock_unref(cache->blocks[f]);
860 : :
861 : : memset(cache, 0, sizeof(pa_silence_cache));
862 : 0 : }
863 : :
864 : 0 : pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length) {
865 : : pa_memblock *b;
866 : : size_t l;
867 : :
868 [ # # ]: 0 : pa_assert(cache);
869 [ # # ]: 0 : pa_assert(pa_sample_spec_valid(spec));
870 : :
871 [ # # ]: 0 : if (!(b = cache->blocks[spec->format]))
872 : :
873 [ # # # # : 0 : switch (spec->format) {
# ]
874 : : case PA_SAMPLE_U8:
875 : 0 : cache->blocks[PA_SAMPLE_U8] = b = silence_memblock_new(pool, 0x80);
876 : 0 : break;
877 : : case PA_SAMPLE_S16LE:
878 : : case PA_SAMPLE_S16BE:
879 : : case PA_SAMPLE_S32LE:
880 : : case PA_SAMPLE_S32BE:
881 : : case PA_SAMPLE_S24LE:
882 : : case PA_SAMPLE_S24BE:
883 : : case PA_SAMPLE_S24_32LE:
884 : : case PA_SAMPLE_S24_32BE:
885 : : case PA_SAMPLE_FLOAT32LE:
886 : : case PA_SAMPLE_FLOAT32BE:
887 : 0 : cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
888 : 0 : cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
889 : 0 : cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
890 : 0 : cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
891 : 0 : cache->blocks[PA_SAMPLE_S24LE] = pa_memblock_ref(b);
892 : 0 : cache->blocks[PA_SAMPLE_S24BE] = pa_memblock_ref(b);
893 : 0 : cache->blocks[PA_SAMPLE_S24_32LE] = pa_memblock_ref(b);
894 : 0 : cache->blocks[PA_SAMPLE_S24_32BE] = pa_memblock_ref(b);
895 : 0 : cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
896 : 0 : cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
897 : 0 : break;
898 : : case PA_SAMPLE_ALAW:
899 : 0 : cache->blocks[PA_SAMPLE_ALAW] = b = silence_memblock_new(pool, 0xd5);
900 : 0 : break;
901 : : case PA_SAMPLE_ULAW:
902 : 0 : cache->blocks[PA_SAMPLE_ULAW] = b = silence_memblock_new(pool, 0xff);
903 : 0 : break;
904 : : default:
905 : 0 : pa_assert_not_reached();
906 : : }
907 : :
908 [ # # ]: 0 : pa_assert(b);
909 : :
910 : 0 : ret->memblock = pa_memblock_ref(b);
911 : :
912 : 0 : l = pa_memblock_get_length(b);
913 [ # # ]: 0 : if (length > l || length == 0)
914 : 0 : length = l;
915 : :
916 : 0 : ret->length = pa_frame_align(length, spec);
917 : 0 : ret->index = 0;
918 : :
919 : 0 : return ret;
920 : : }
921 : :
922 : 0 : void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n) {
923 : : const float *s;
924 : : float *d;
925 : :
926 : 0 : s = src; d = dst;
927 : :
928 [ # # ]: 0 : if (format == PA_SAMPLE_FLOAT32NE) {
929 [ # # ]: 0 : for (; n > 0; n--) {
930 : : float f;
931 : :
932 : 0 : f = *s;
933 [ # # ][ # # ]: 0 : *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
934 : :
935 : 0 : s = (const float*) ((const uint8_t*) s + sstr);
936 : 0 : d = (float*) ((uint8_t*) d + dstr);
937 : : }
938 : : } else {
939 [ # # ]: 0 : pa_assert(format == PA_SAMPLE_FLOAT32RE);
940 : :
941 [ # # ]: 0 : for (; n > 0; n--) {
942 : : float f;
943 : :
944 : 0 : f = PA_FLOAT32_SWAP(*s);
945 [ # # ][ # # ]: 0 : f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
946 : 0 : *d = PA_FLOAT32_SWAP(f);
947 : :
948 : 0 : s = (const float*) ((const uint8_t*) s + sstr);
949 : 0 : d = (float*) ((uint8_t*) d + dstr);
950 : : }
951 : : }
952 : 0 : }
953 : :
954 : : /* Similar to pa_bytes_to_usec() but rounds up, not down */
955 : :
956 : 0 : pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec) {
957 : : size_t fs;
958 : : pa_usec_t usec;
959 : :
960 [ # # ]: 0 : pa_assert(spec);
961 : :
962 : 0 : fs = pa_frame_size(spec);
963 : 0 : length = (length + fs - 1) / fs;
964 : :
965 : 0 : usec = (pa_usec_t) length * PA_USEC_PER_SEC;
966 : :
967 : 0 : return (usec + spec->rate - 1) / spec->rate;
968 : : }
969 : :
970 : : /* Similar to pa_usec_to_bytes() but rounds up, not down */
971 : :
972 : 0 : size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec) {
973 : : uint64_t u;
974 [ # # ]: 0 : pa_assert(spec);
975 : :
976 : 0 : u = (uint64_t) t * (uint64_t) spec->rate;
977 : :
978 : 0 : u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC;
979 : :
980 : 0 : u *= pa_frame_size(spec);
981 : :
982 : 0 : return (size_t) u;
983 : : }
984 : :
985 : 0 : void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
986 : : FILE *f;
987 : : void *p;
988 : :
989 [ # # ]: 0 : pa_assert(c);
990 [ # # ]: 0 : pa_assert(fn);
991 : :
992 : : /* Only for debugging purposes */
993 : :
994 : 0 : f = pa_fopen_cloexec(fn, "a");
995 : :
996 [ # # ]: 0 : if (!f) {
997 : 0 : pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
998 : 0 : return;
999 : : }
1000 : :
1001 : 0 : p = pa_memblock_acquire(c->memblock);
1002 : :
1003 [ # # ]: 0 : if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length)
1004 : 0 : pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno));
1005 : :
1006 : 0 : pa_memblock_release(c->memblock);
1007 : :
1008 : 0 : fclose(f);
1009 : : }
1010 : :
1011 : : static void calc_sine(float *f, size_t l, double freq) {
1012 : : size_t i;
1013 : :
1014 : 0 : l /= sizeof(float);
1015 : :
1016 [ # # ]: 0 : for (i = 0; i < l; i++)
1017 : 0 : *(f++) = (float) 0.5f * sin((double) i*M_PI*2*freq / (double) l);
1018 : : }
1019 : :
1020 : 0 : void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) {
1021 : : size_t l;
1022 : : unsigned gcd, n;
1023 : : void *p;
1024 : :
1025 : 0 : pa_memchunk_reset(c);
1026 : :
1027 : 0 : gcd = pa_gcd(rate, freq);
1028 : 0 : n = rate / gcd;
1029 : :
1030 : 0 : l = pa_mempool_block_size_max(pool) / sizeof(float);
1031 : :
1032 : 0 : l /= n;
1033 [ # # ]: 0 : if (l <= 0) l = 1;
1034 : 0 : l *= n;
1035 : :
1036 : 0 : c->length = l * sizeof(float);
1037 : 0 : c->memblock = pa_memblock_new(pool, c->length);
1038 : :
1039 : 0 : p = pa_memblock_acquire(c->memblock);
1040 : 0 : calc_sine(p, c->length, freq * l / rate);
1041 : 0 : pa_memblock_release(c->memblock);
1042 : 0 : }
1043 : :
1044 : 0 : size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) {
1045 : : pa_usec_t usec;
1046 : :
1047 [ # # ]: 0 : pa_assert(from);
1048 [ # # ]: 0 : pa_assert(to);
1049 : :
1050 : 0 : usec = pa_bytes_to_usec_round_up(size, from);
1051 : 0 : return pa_usec_to_bytes_round_up(usec, to);
1052 : : }
|