]> code.delx.au - pulseaudio/blob - src/pulsecore/mix.c
Remove pa_bool_t and replace it with bool.
[pulseaudio] / src / pulsecore / mix.c
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 Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net>
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <math.h>
29
30 #include <pulsecore/sample-util.h>
31 #include <pulsecore/macro.h>
32 #include <pulsecore/g711.h>
33 #include <pulsecore/endianmacros.h>
34
35 #include "mix.h"
36
37 #define VOLUME_PADDING 32
38
39 static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
40 unsigned channel, nchannels, padding;
41
42 pa_assert(linear);
43 pa_assert(volume);
44
45 nchannels = volume->channels;
46
47 for (channel = 0; channel < nchannels; channel++)
48 linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
49
50 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
51 linear[channel] = linear[padding];
52 }
53
54 static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
55 unsigned channel, nchannels, padding;
56
57 pa_assert(linear);
58 pa_assert(volume);
59
60 nchannels = volume->channels;
61
62 for (channel = 0; channel < nchannels; channel++)
63 linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]);
64
65 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
66 linear[channel] = linear[padding];
67 }
68
69 static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
70 unsigned k, channel;
71 float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
72
73 pa_assert(streams);
74 pa_assert(spec);
75 pa_assert(volume);
76
77 calc_linear_float_volume(linear, volume);
78
79 for (k = 0; k < nstreams; k++) {
80
81 for (channel = 0; channel < spec->channels; channel++) {
82 pa_mix_info *m = streams + k;
83 m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000);
84 }
85 }
86 }
87
88 static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
89 unsigned k, channel;
90 float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
91
92 pa_assert(streams);
93 pa_assert(spec);
94 pa_assert(volume);
95
96 calc_linear_float_volume(linear, volume);
97
98 for (k = 0; k < nstreams; k++) {
99
100 for (channel = 0; channel < spec->channels; channel++) {
101 pa_mix_info *m = streams + k;
102 m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]);
103 }
104 }
105 }
106
107 typedef void (*pa_calc_stream_volumes_func_t) (pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec);
108
109 static const pa_calc_stream_volumes_func_t calc_stream_volumes_table[] = {
110 [PA_SAMPLE_U8] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
111 [PA_SAMPLE_ALAW] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
112 [PA_SAMPLE_ULAW] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
113 [PA_SAMPLE_S16LE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
114 [PA_SAMPLE_S16BE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
115 [PA_SAMPLE_FLOAT32LE] = (pa_calc_stream_volumes_func_t) calc_linear_float_stream_volumes,
116 [PA_SAMPLE_FLOAT32BE] = (pa_calc_stream_volumes_func_t) calc_linear_float_stream_volumes,
117 [PA_SAMPLE_S32LE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
118 [PA_SAMPLE_S32BE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
119 [PA_SAMPLE_S24LE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
120 [PA_SAMPLE_S24BE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
121 [PA_SAMPLE_S24_32LE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes,
122 [PA_SAMPLE_S24_32BE] = (pa_calc_stream_volumes_func_t) calc_linear_integer_stream_volumes
123 };
124
125 /* special case: mix 2 s16ne streams, 1 channel each */
126 static void pa_mix2_ch1_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
127 const int16_t *ptr0 = streams[0].ptr;
128 const int16_t *ptr1 = streams[1].ptr;
129
130 const int32_t cv0 = streams[0].linear[0].i;
131 const int32_t cv1 = streams[1].linear[0].i;
132
133 length /= sizeof(int16_t);
134
135 for (; length > 0; length--) {
136 int32_t sum;
137
138 sum = pa_mult_s16_volume(*ptr0++, cv0);
139 sum += pa_mult_s16_volume(*ptr1++, cv1);
140
141 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
142 *data++ = sum;
143 }
144 }
145
146 /* special case: mix 2 s16ne streams, 2 channels each */
147 static void pa_mix2_ch2_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
148 const int16_t *ptr0 = streams[0].ptr;
149 const int16_t *ptr1 = streams[1].ptr;
150
151 length /= sizeof(int16_t) * 2;
152
153 for (; length > 0; length--) {
154 int32_t sum;
155
156 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[0].i);
157 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[0].i);
158
159 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
160 *data++ = sum;
161
162 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[1].i);
163 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[1].i);
164
165 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
166 *data++ = sum;
167 }
168 }
169
170 /* special case: mix 2 s16ne streams */
171 static void pa_mix2_s16ne(pa_mix_info streams[], unsigned channels, int16_t *data, unsigned length) {
172 const int16_t *ptr0 = streams[0].ptr;
173 const int16_t *ptr1 = streams[1].ptr;
174 unsigned channel = 0;
175
176 length /= sizeof(int16_t);
177
178 for (; length > 0; length--) {
179 int32_t sum;
180
181 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[channel].i);
182 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[channel].i);
183
184 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
185 *data++ = sum;
186
187 if (PA_UNLIKELY(++channel >= channels))
188 channel = 0;
189 }
190 }
191
192 /* special case: mix s16ne streams, 2 channels each */
193 static void pa_mix_ch2_s16ne(pa_mix_info streams[], unsigned nstreams, int16_t *data, unsigned length) {
194
195 length /= sizeof(int16_t) * 2;
196
197 for (; length > 0; length--) {
198 int32_t sum0 = 0, sum1 = 0;
199 unsigned i;
200
201 for (i = 0; i < nstreams; i++) {
202 pa_mix_info *m = streams + i;
203 int32_t cv0 = m->linear[0].i;
204 int32_t cv1 = m->linear[1].i;
205
206 sum0 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv0);
207 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
208
209 sum1 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv1);
210 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
211 }
212
213 *data++ = PA_CLAMP_UNLIKELY(sum0, -0x8000, 0x7FFF);
214 *data++ = PA_CLAMP_UNLIKELY(sum1, -0x8000, 0x7FFF);
215 }
216 }
217
218 static void pa_mix_generic_s16ne(pa_mix_info streams[], unsigned nstreams, unsigned channels, int16_t *data, unsigned length) {
219 unsigned channel = 0;
220
221 length /= sizeof(int16_t);
222
223 for (; length > 0; length--) {
224 int32_t sum = 0;
225 unsigned i;
226
227 for (i = 0; i < nstreams; i++) {
228 pa_mix_info *m = streams + i;
229 int32_t cv = m->linear[channel].i;
230
231 if (PA_LIKELY(cv > 0))
232 sum += pa_mult_s16_volume(*((int16_t*) m->ptr), cv);
233 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
234 }
235
236 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
237 *data++ = sum;
238
239 if (PA_UNLIKELY(++channel >= channels))
240 channel = 0;
241 }
242 }
243
244 static void pa_mix_s16ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, int16_t *data, unsigned length) {
245 if (nstreams == 2 && channels == 1)
246 pa_mix2_ch1_s16ne(streams, data, length);
247 else if (nstreams == 2 && channels == 2)
248 pa_mix2_ch2_s16ne(streams, data, length);
249 else if (nstreams == 2)
250 pa_mix2_s16ne(streams, channels, data, length);
251 else if (channels == 2)
252 pa_mix_ch2_s16ne(streams, nstreams, data, length);
253 else
254 pa_mix_generic_s16ne(streams, nstreams, channels, data, length);
255 }
256
257 static void pa_mix_s16re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, int16_t *data, unsigned length) {
258 unsigned channel = 0;
259
260 length /= sizeof(int16_t);
261
262 for (; length > 0; length--, data++) {
263 int32_t sum = 0;
264 unsigned i;
265
266 for (i = 0; i < nstreams; i++) {
267 pa_mix_info *m = streams + i;
268 int32_t cv = m->linear[channel].i;
269
270 if (PA_LIKELY(cv > 0))
271 sum += pa_mult_s16_volume(PA_INT16_SWAP(*((int16_t*) m->ptr)), cv);
272 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
273 }
274
275 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
276 *data = PA_INT16_SWAP((int16_t) sum);
277
278 if (PA_UNLIKELY(++channel >= channels))
279 channel = 0;
280 }
281 }
282
283 static void pa_mix_s32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, int32_t *data, unsigned length) {
284 unsigned channel = 0;
285
286 length /= sizeof(int32_t);
287
288 for (; length > 0; length--, data++) {
289 int64_t sum = 0;
290 unsigned i;
291
292 for (i = 0; i < nstreams; i++) {
293 pa_mix_info *m = streams + i;
294 int32_t cv = m->linear[channel].i;
295 int64_t v;
296
297 if (PA_LIKELY(cv > 0)) {
298 v = *((int32_t*) m->ptr);
299 v = (v * cv) >> 16;
300 sum += v;
301 }
302 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
303 }
304
305 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
306 *data = (int32_t) sum;
307
308 if (PA_UNLIKELY(++channel >= channels))
309 channel = 0;
310 }
311 }
312
313 static void pa_mix_s32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, int32_t *data, unsigned length) {
314 unsigned channel = 0;
315
316 length /= sizeof(int32_t);
317
318 for (; length > 0; length--, data++) {
319 int64_t sum = 0;
320 unsigned i;
321
322 for (i = 0; i < nstreams; i++) {
323 pa_mix_info *m = streams + i;
324 int32_t cv = m->linear[channel].i;
325 int64_t v;
326
327 if (PA_LIKELY(cv > 0)) {
328 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
329 v = (v * cv) >> 16;
330 sum += v;
331 }
332 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
333 }
334
335 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
336 *data = PA_INT32_SWAP((int32_t) sum);
337
338 if (PA_UNLIKELY(++channel >= channels))
339 channel = 0;
340 }
341 }
342
343 static void pa_mix_s24ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint8_t *data, unsigned length) {
344 unsigned channel = 0;
345
346 for (; length > 0; length -= 3, data += 3) {
347 int64_t sum = 0;
348 unsigned i;
349
350 for (i = 0; i < nstreams; i++) {
351 pa_mix_info *m = streams + i;
352 int32_t cv = m->linear[channel].i;
353 int64_t v;
354
355 if (PA_LIKELY(cv > 0)) {
356 v = (int32_t) (PA_READ24NE(m->ptr) << 8);
357 v = (v * cv) >> 16;
358 sum += v;
359 }
360 m->ptr = (uint8_t*) m->ptr + 3;
361 }
362
363 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
364 PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
365
366 if (PA_UNLIKELY(++channel >= channels))
367 channel = 0;
368 }
369 }
370
371 static void pa_mix_s24re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint8_t *data, unsigned length) {
372 unsigned channel = 0;
373
374 for (; length > 0; length -= 3, data += 3) {
375 int64_t sum = 0;
376 unsigned i;
377
378 for (i = 0; i < nstreams; i++) {
379 pa_mix_info *m = streams + i;
380 int32_t cv = m->linear[channel].i;
381 int64_t v;
382
383 if (PA_LIKELY(cv > 0)) {
384 v = (int32_t) (PA_READ24RE(m->ptr) << 8);
385 v = (v * cv) >> 16;
386 sum += v;
387 }
388 m->ptr = (uint8_t*) m->ptr + 3;
389 }
390
391 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
392 PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
393
394 if (PA_UNLIKELY(++channel >= channels))
395 channel = 0;
396 }
397 }
398
399 static void pa_mix_s24_32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint32_t *data, unsigned length) {
400 unsigned channel = 0;
401
402 length /= sizeof(uint32_t);
403
404 for (; length > 0; length--, data++) {
405 int64_t sum = 0;
406 unsigned i;
407
408 for (i = 0; i < nstreams; i++) {
409 pa_mix_info *m = streams + i;
410 int32_t cv = m->linear[channel].i;
411 int64_t v;
412
413 if (PA_LIKELY(cv > 0)) {
414 v = (int32_t) (*((uint32_t*)m->ptr) << 8);
415 v = (v * cv) >> 16;
416 sum += v;
417 }
418 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
419 }
420
421 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
422 *data = ((uint32_t) (int32_t) sum) >> 8;
423
424 if (PA_UNLIKELY(++channel >= channels))
425 channel = 0;
426 }
427 }
428
429 static void pa_mix_s24_32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint32_t *data, unsigned length) {
430 unsigned channel = 0;
431
432 length /= sizeof(uint32_t);
433
434 for (; length > 0; length--, data++) {
435 int64_t sum = 0;
436 unsigned i;
437
438 for (i = 0; i < nstreams; i++) {
439 pa_mix_info *m = streams + i;
440 int32_t cv = m->linear[channel].i;
441 int64_t v;
442
443 if (PA_LIKELY(cv > 0)) {
444 v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
445 v = (v * cv) >> 16;
446 sum += v;
447 }
448 m->ptr = (uint8_t*) m->ptr + 3;
449 }
450
451 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
452 *data = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
453
454 if (PA_UNLIKELY(++channel >= channels))
455 channel = 0;
456 }
457 }
458
459 static void pa_mix_u8_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint8_t *data, unsigned length) {
460 unsigned channel = 0;
461
462 length /= sizeof(uint8_t);
463
464 for (; length > 0; length--, data++) {
465 int32_t sum = 0;
466 unsigned i;
467
468 for (i = 0; i < nstreams; i++) {
469 pa_mix_info *m = streams + i;
470 int32_t v, cv = m->linear[channel].i;
471
472 if (PA_LIKELY(cv > 0)) {
473 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
474 v = (v * cv) >> 16;
475 sum += v;
476 }
477 m->ptr = (uint8_t*) m->ptr + 1;
478 }
479
480 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
481 *data = (uint8_t) (sum + 0x80);
482
483 if (PA_UNLIKELY(++channel >= channels))
484 channel = 0;
485 }
486 }
487
488 static void pa_mix_ulaw_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint8_t *data, unsigned length) {
489 unsigned channel = 0;
490
491 length /= sizeof(uint8_t);
492
493 for (; length > 0; length--, data++) {
494 int32_t sum = 0;
495 unsigned i;
496
497 for (i = 0; i < nstreams; i++) {
498 pa_mix_info *m = streams + i;
499 int32_t cv = m->linear[channel].i;
500
501 if (PA_LIKELY(cv > 0))
502 sum += pa_mult_s16_volume(st_ulaw2linear16(*((uint8_t*) m->ptr)), cv);
503 m->ptr = (uint8_t*) m->ptr + 1;
504 }
505
506 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
507 *data = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
508
509 if (PA_UNLIKELY(++channel >= channels))
510 channel = 0;
511 }
512 }
513
514 static void pa_mix_alaw_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, uint8_t *data, unsigned length) {
515 unsigned channel = 0;
516
517 length /= sizeof(uint8_t);
518
519 for (; length > 0; length--, data++) {
520 int32_t sum = 0;
521 unsigned i;
522
523 for (i = 0; i < nstreams; i++) {
524 pa_mix_info *m = streams + i;
525 int32_t cv = m->linear[channel].i;
526
527 if (PA_LIKELY(cv > 0))
528 sum += pa_mult_s16_volume(st_alaw2linear16(*((uint8_t*) m->ptr)), cv);
529 m->ptr = (uint8_t*) m->ptr + 1;
530 }
531
532 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
533 *data = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
534
535 if (PA_UNLIKELY(++channel >= channels))
536 channel = 0;
537 }
538 }
539
540 static void pa_mix_float32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, float *data, unsigned length) {
541 unsigned channel = 0;
542
543 length /= sizeof(float);
544
545 for (; length > 0; length--, data++) {
546 float sum = 0;
547 unsigned i;
548
549 for (i = 0; i < nstreams; i++) {
550 pa_mix_info *m = streams + i;
551 float v, cv = m->linear[channel].f;
552
553 if (PA_LIKELY(cv > 0)) {
554 v = *((float*) m->ptr);
555 v *= cv;
556 sum += v;
557 }
558 m->ptr = (uint8_t*) m->ptr + sizeof(float);
559 }
560
561 *data = sum;
562
563 if (PA_UNLIKELY(++channel >= channels))
564 channel = 0;
565 }
566 }
567
568 static void pa_mix_float32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, float *data, unsigned length) {
569 unsigned channel = 0;
570
571 length /= sizeof(float);
572
573 for (; length > 0; length--, data++) {
574 float sum = 0;
575 unsigned i;
576
577 for (i = 0; i < nstreams; i++) {
578 pa_mix_info *m = streams + i;
579 float v, cv = m->linear[channel].f;
580
581 if (PA_LIKELY(cv > 0)) {
582 v = PA_FLOAT32_SWAP(*(float*) m->ptr);
583 v *= cv;
584 sum += v;
585 }
586 m->ptr = (uint8_t*) m->ptr + sizeof(float);
587 }
588
589 *data = PA_FLOAT32_SWAP(sum);
590
591 if (PA_UNLIKELY(++channel >= channels))
592 channel = 0;
593 }
594 }
595
596 static pa_do_mix_func_t do_mix_table[] = {
597 [PA_SAMPLE_U8] = (pa_do_mix_func_t) pa_mix_u8_c,
598 [PA_SAMPLE_ALAW] = (pa_do_mix_func_t) pa_mix_alaw_c,
599 [PA_SAMPLE_ULAW] = (pa_do_mix_func_t) pa_mix_ulaw_c,
600 [PA_SAMPLE_S16NE] = (pa_do_mix_func_t) pa_mix_s16ne_c,
601 [PA_SAMPLE_S16RE] = (pa_do_mix_func_t) pa_mix_s16re_c,
602 [PA_SAMPLE_FLOAT32NE] = (pa_do_mix_func_t) pa_mix_float32ne_c,
603 [PA_SAMPLE_FLOAT32RE] = (pa_do_mix_func_t) pa_mix_float32re_c,
604 [PA_SAMPLE_S32NE] = (pa_do_mix_func_t) pa_mix_s32ne_c,
605 [PA_SAMPLE_S32RE] = (pa_do_mix_func_t) pa_mix_s32re_c,
606 [PA_SAMPLE_S24NE] = (pa_do_mix_func_t) pa_mix_s24ne_c,
607 [PA_SAMPLE_S24RE] = (pa_do_mix_func_t) pa_mix_s24re_c,
608 [PA_SAMPLE_S24_32NE] = (pa_do_mix_func_t) pa_mix_s24_32ne_c,
609 [PA_SAMPLE_S24_32RE] = (pa_do_mix_func_t) pa_mix_s24_32re_c
610 };
611
612 size_t pa_mix(
613 pa_mix_info streams[],
614 unsigned nstreams,
615 void *data,
616 size_t length,
617 const pa_sample_spec *spec,
618 const pa_cvolume *volume,
619 bool mute) {
620
621 pa_cvolume full_volume;
622 unsigned k;
623
624 pa_assert(streams);
625 pa_assert(data);
626 pa_assert(length);
627 pa_assert(spec);
628
629 if (!volume)
630 volume = pa_cvolume_reset(&full_volume, spec->channels);
631
632 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
633 pa_silence_memory(data, length, spec);
634 return length;
635 }
636
637 for (k = 0; k < nstreams; k++) {
638 streams[k].ptr = pa_memblock_acquire_chunk(&streams[k].chunk);
639 if (length > streams[k].chunk.length)
640 length = streams[k].chunk.length;
641 }
642
643 calc_stream_volumes_table[spec->format](streams, nstreams, volume, spec);
644 do_mix_table[spec->format](streams, nstreams, spec->channels, data, length);
645
646 for (k = 0; k < nstreams; k++)
647 pa_memblock_release(streams[k].chunk.memblock);
648
649 return length;
650 }
651
652 pa_do_mix_func_t pa_get_mix_func(pa_sample_format_t f) {
653 pa_assert(f >= 0);
654 pa_assert(f < PA_SAMPLE_MAX);
655
656 return do_mix_table[f];
657 }
658
659 void pa_set_mix_func(pa_sample_format_t f, pa_do_mix_func_t func) {
660 pa_assert(f >= 0);
661 pa_assert(f < PA_SAMPLE_MAX);
662
663 do_mix_table[f] = func;
664 }
665
666 typedef union {
667 float f;
668 uint32_t i;
669 } volume_val;
670
671 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
672
673 static const pa_calc_volume_func_t calc_volume_table[] = {
674 [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume,
675 [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
676 [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
677 [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
678 [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
679 [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
680 [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
681 [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
682 [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
683 [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
684 [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
685 [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
686 [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume
687 };
688
689 void pa_volume_memchunk(
690 pa_memchunk*c,
691 const pa_sample_spec *spec,
692 const pa_cvolume *volume) {
693
694 void *ptr;
695 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
696 pa_do_volume_func_t do_volume;
697
698 pa_assert(c);
699 pa_assert(spec);
700 pa_assert(pa_sample_spec_valid(spec));
701 pa_assert(pa_frame_aligned(c->length, spec));
702 pa_assert(volume);
703
704 if (pa_memblock_is_silence(c->memblock))
705 return;
706
707 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
708 return;
709
710 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
711 pa_silence_memchunk(c, spec);
712 return;
713 }
714
715 do_volume = pa_get_volume_func(spec->format);
716 pa_assert(do_volume);
717
718 calc_volume_table[spec->format] ((void *)linear, volume);
719
720 ptr = pa_memblock_acquire_chunk(c);
721
722 do_volume(ptr, (void *)linear, spec->channels, c->length);
723
724 pa_memblock_release(c->memblock);
725 }