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