]> code.delx.au - pulseaudio/blob - src/pulsecore/mix.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[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(pa_sample_format_valid(f));
654
655 return do_mix_table[f];
656 }
657
658 void pa_set_mix_func(pa_sample_format_t f, pa_do_mix_func_t func) {
659 pa_assert(pa_sample_format_valid(f));
660
661 do_mix_table[f] = func;
662 }
663
664 typedef union {
665 float f;
666 uint32_t i;
667 } volume_val;
668
669 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
670
671 static const pa_calc_volume_func_t calc_volume_table[] = {
672 [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume,
673 [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
674 [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
675 [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
676 [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
677 [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
678 [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
679 [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
680 [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
681 [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
682 [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
683 [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
684 [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume
685 };
686
687 void pa_volume_memchunk(
688 pa_memchunk*c,
689 const pa_sample_spec *spec,
690 const pa_cvolume *volume) {
691
692 void *ptr;
693 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
694 pa_do_volume_func_t do_volume;
695
696 pa_assert(c);
697 pa_assert(spec);
698 pa_assert(pa_sample_spec_valid(spec));
699 pa_assert(pa_frame_aligned(c->length, spec));
700 pa_assert(volume);
701
702 if (pa_memblock_is_silence(c->memblock))
703 return;
704
705 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
706 return;
707
708 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
709 pa_silence_memchunk(c, spec);
710 return;
711 }
712
713 do_volume = pa_get_volume_func(spec->format);
714 pa_assert(do_volume);
715
716 calc_volume_table[spec->format] ((void *)linear, volume);
717
718 ptr = pa_memblock_acquire_chunk(c);
719
720 do_volume(ptr, (void *)linear, spec->channels, c->length);
721
722 pa_memblock_release(c->memblock);
723 }