]> code.delx.au - pulseaudio/blob - src/pulsecore/mix.c
core: Move pa_mix() into new file mix.c
[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 size_t pa_mix(
108 pa_mix_info streams[],
109 unsigned nstreams,
110 void *data,
111 size_t length,
112 const pa_sample_spec *spec,
113 const pa_cvolume *volume,
114 pa_bool_t mute) {
115
116 pa_cvolume full_volume;
117 unsigned k;
118 unsigned z;
119 void *end;
120
121 pa_assert(streams);
122 pa_assert(data);
123 pa_assert(length);
124 pa_assert(spec);
125
126 if (!volume)
127 volume = pa_cvolume_reset(&full_volume, spec->channels);
128
129 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
130 pa_silence_memory(data, length, spec);
131 return length;
132 }
133
134 for (k = 0; k < nstreams; k++)
135 streams[k].ptr = pa_memblock_acquire_chunk(&streams[k].chunk);
136
137 for (z = 0; z < nstreams; z++)
138 if (length > streams[z].chunk.length)
139 length = streams[z].chunk.length;
140
141 end = (uint8_t*) data + length;
142
143 switch (spec->format) {
144
145 case PA_SAMPLE_S16NE:{
146 unsigned channel = 0;
147
148 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
149
150 while (data < end) {
151 int32_t sum = 0;
152 unsigned i;
153
154 for (i = 0; i < nstreams; i++) {
155 pa_mix_info *m = streams + i;
156 int32_t v, lo, hi, cv = m->linear[channel].i;
157
158 if (PA_LIKELY(cv > 0)) {
159
160 /* Multiplying the 32bit volume factor with the
161 * 16bit sample might result in an 48bit value. We
162 * want to do without 64 bit integers and hence do
163 * the multiplication independently for the HI and
164 * LO part of the volume. */
165
166 hi = cv >> 16;
167 lo = cv & 0xFFFF;
168
169 v = *((int16_t*) m->ptr);
170 v = ((v * lo) >> 16) + (v * hi);
171 sum += v;
172 }
173 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
174 }
175
176 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
177 *((int16_t*) data) = (int16_t) sum;
178
179 data = (uint8_t*) data + sizeof(int16_t);
180
181 if (PA_UNLIKELY(++channel >= spec->channels))
182 channel = 0;
183 }
184
185 break;
186 }
187
188 case PA_SAMPLE_S16RE:{
189 unsigned channel = 0;
190
191 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
192
193 while (data < end) {
194 int32_t sum = 0;
195 unsigned i;
196
197 for (i = 0; i < nstreams; i++) {
198 pa_mix_info *m = streams + i;
199 int32_t v, lo, hi, cv = m->linear[channel].i;
200
201 if (PA_LIKELY(cv > 0)) {
202
203 hi = cv >> 16;
204 lo = cv & 0xFFFF;
205
206 v = PA_INT16_SWAP(*((int16_t*) m->ptr));
207 v = ((v * lo) >> 16) + (v * hi);
208 sum += v;
209 }
210 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
211 }
212
213 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
214 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
215
216 data = (uint8_t*) data + sizeof(int16_t);
217
218 if (PA_UNLIKELY(++channel >= spec->channels))
219 channel = 0;
220 }
221
222 break;
223 }
224
225 case PA_SAMPLE_S32NE:{
226 unsigned channel = 0;
227
228 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
229
230 while (data < end) {
231 int64_t sum = 0;
232 unsigned i;
233
234 for (i = 0; i < nstreams; i++) {
235 pa_mix_info *m = streams + i;
236 int32_t cv = m->linear[channel].i;
237 int64_t v;
238
239 if (PA_LIKELY(cv > 0)) {
240
241 v = *((int32_t*) m->ptr);
242 v = (v * cv) >> 16;
243 sum += v;
244 }
245 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
246 }
247
248 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
249 *((int32_t*) data) = (int32_t) sum;
250
251 data = (uint8_t*) data + sizeof(int32_t);
252
253 if (PA_UNLIKELY(++channel >= spec->channels))
254 channel = 0;
255 }
256
257 break;
258 }
259
260 case PA_SAMPLE_S32RE:{
261 unsigned channel = 0;
262
263 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
264
265 while (data < end) {
266 int64_t sum = 0;
267 unsigned i;
268
269 for (i = 0; i < nstreams; i++) {
270 pa_mix_info *m = streams + i;
271 int32_t cv = m->linear[channel].i;
272 int64_t v;
273
274 if (PA_LIKELY(cv > 0)) {
275
276 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
277 v = (v * cv) >> 16;
278 sum += v;
279 }
280 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
281 }
282
283 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
284 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
285
286 data = (uint8_t*) data + sizeof(int32_t);
287
288 if (PA_UNLIKELY(++channel >= spec->channels))
289 channel = 0;
290 }
291
292 break;
293 }
294
295 case PA_SAMPLE_S24NE: {
296 unsigned channel = 0;
297
298 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
299
300 while (data < end) {
301 int64_t sum = 0;
302 unsigned i;
303
304 for (i = 0; i < nstreams; i++) {
305 pa_mix_info *m = streams + i;
306 int32_t cv = m->linear[channel].i;
307 int64_t v;
308
309 if (PA_LIKELY(cv > 0)) {
310
311 v = (int32_t) (PA_READ24NE(m->ptr) << 8);
312 v = (v * cv) >> 16;
313 sum += v;
314 }
315 m->ptr = (uint8_t*) m->ptr + 3;
316 }
317
318 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
319 PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
320
321 data = (uint8_t*) data + 3;
322
323 if (PA_UNLIKELY(++channel >= spec->channels))
324 channel = 0;
325 }
326
327 break;
328 }
329
330 case PA_SAMPLE_S24RE: {
331 unsigned channel = 0;
332
333 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
334
335 while (data < end) {
336 int64_t sum = 0;
337 unsigned i;
338
339 for (i = 0; i < nstreams; i++) {
340 pa_mix_info *m = streams + i;
341 int32_t cv = m->linear[channel].i;
342 int64_t v;
343
344 if (PA_LIKELY(cv > 0)) {
345
346 v = (int32_t) (PA_READ24RE(m->ptr) << 8);
347 v = (v * cv) >> 16;
348 sum += v;
349 }
350 m->ptr = (uint8_t*) m->ptr + 3;
351 }
352
353 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
354 PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
355
356 data = (uint8_t*) data + 3;
357
358 if (PA_UNLIKELY(++channel >= spec->channels))
359 channel = 0;
360 }
361
362 break;
363 }
364
365 case PA_SAMPLE_S24_32NE: {
366 unsigned channel = 0;
367
368 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
369
370 while (data < end) {
371 int64_t sum = 0;
372 unsigned i;
373
374 for (i = 0; i < nstreams; i++) {
375 pa_mix_info *m = streams + i;
376 int32_t cv = m->linear[channel].i;
377 int64_t v;
378
379 if (PA_LIKELY(cv > 0)) {
380
381 v = (int32_t) (*((uint32_t*)m->ptr) << 8);
382 v = (v * cv) >> 16;
383 sum += v;
384 }
385 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
386 }
387
388 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
389 *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
390
391 data = (uint8_t*) data + sizeof(uint32_t);
392
393 if (PA_UNLIKELY(++channel >= spec->channels))
394 channel = 0;
395 }
396
397 break;
398 }
399
400 case PA_SAMPLE_S24_32RE: {
401 unsigned channel = 0;
402
403 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
404
405 while (data < end) {
406 int64_t sum = 0;
407 unsigned i;
408
409 for (i = 0; i < nstreams; i++) {
410 pa_mix_info *m = streams + i;
411 int32_t cv = m->linear[channel].i;
412 int64_t v;
413
414 if (PA_LIKELY(cv > 0)) {
415
416 v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
417 v = (v * cv) >> 16;
418 sum += v;
419 }
420 m->ptr = (uint8_t*) m->ptr + 3;
421 }
422
423 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
424 *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
425
426 data = (uint8_t*) data + sizeof(uint32_t);
427
428 if (PA_UNLIKELY(++channel >= spec->channels))
429 channel = 0;
430 }
431
432 break;
433 }
434
435 case PA_SAMPLE_U8: {
436 unsigned channel = 0;
437
438 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
439
440 while (data < end) {
441 int32_t sum = 0;
442 unsigned i;
443
444 for (i = 0; i < nstreams; i++) {
445 pa_mix_info *m = streams + i;
446 int32_t v, cv = m->linear[channel].i;
447
448 if (PA_LIKELY(cv > 0)) {
449
450 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
451 v = (v * cv) >> 16;
452 sum += v;
453 }
454 m->ptr = (uint8_t*) m->ptr + 1;
455 }
456
457 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
458 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
459
460 data = (uint8_t*) data + 1;
461
462 if (PA_UNLIKELY(++channel >= spec->channels))
463 channel = 0;
464 }
465
466 break;
467 }
468
469 case PA_SAMPLE_ULAW: {
470 unsigned channel = 0;
471
472 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
473
474 while (data < end) {
475 int32_t sum = 0;
476 unsigned i;
477
478 for (i = 0; i < nstreams; i++) {
479 pa_mix_info *m = streams + i;
480 int32_t v, hi, lo, cv = m->linear[channel].i;
481
482 if (PA_LIKELY(cv > 0)) {
483
484 hi = cv >> 16;
485 lo = cv & 0xFFFF;
486
487 v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
488 v = ((v * lo) >> 16) + (v * hi);
489 sum += v;
490 }
491 m->ptr = (uint8_t*) m->ptr + 1;
492 }
493
494 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
495 *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
496
497 data = (uint8_t*) data + 1;
498
499 if (PA_UNLIKELY(++channel >= spec->channels))
500 channel = 0;
501 }
502
503 break;
504 }
505
506 case PA_SAMPLE_ALAW: {
507 unsigned channel = 0;
508
509 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
510
511 while (data < end) {
512 int32_t sum = 0;
513 unsigned i;
514
515 for (i = 0; i < nstreams; i++) {
516 pa_mix_info *m = streams + i;
517 int32_t v, hi, lo, cv = m->linear[channel].i;
518
519 if (PA_LIKELY(cv > 0)) {
520
521 hi = cv >> 16;
522 lo = cv & 0xFFFF;
523
524 v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
525 v = ((v * lo) >> 16) + (v * hi);
526 sum += v;
527 }
528 m->ptr = (uint8_t*) m->ptr + 1;
529 }
530
531 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
532 *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
533
534 data = (uint8_t*) data + 1;
535
536 if (PA_UNLIKELY(++channel >= spec->channels))
537 channel = 0;
538 }
539
540 break;
541 }
542
543 case PA_SAMPLE_FLOAT32NE: {
544 unsigned channel = 0;
545
546 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
547
548 while (data < end) {
549 float sum = 0;
550 unsigned i;
551
552 for (i = 0; i < nstreams; i++) {
553 pa_mix_info *m = streams + i;
554 float v, cv = m->linear[channel].f;
555
556 if (PA_LIKELY(cv > 0)) {
557
558 v = *((float*) m->ptr);
559 v *= cv;
560 sum += v;
561 }
562 m->ptr = (uint8_t*) m->ptr + sizeof(float);
563 }
564
565 *((float*) data) = sum;
566
567 data = (uint8_t*) data + sizeof(float);
568
569 if (PA_UNLIKELY(++channel >= spec->channels))
570 channel = 0;
571 }
572
573 break;
574 }
575
576 case PA_SAMPLE_FLOAT32RE: {
577 unsigned channel = 0;
578
579 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
580
581 while (data < end) {
582 float sum = 0;
583 unsigned i;
584
585 for (i = 0; i < nstreams; i++) {
586 pa_mix_info *m = streams + i;
587 float v, cv = m->linear[channel].f;
588
589 if (PA_LIKELY(cv > 0)) {
590
591 v = PA_FLOAT32_SWAP(*(float*) m->ptr);
592 v *= cv;
593 sum += v;
594 }
595 m->ptr = (uint8_t*) m->ptr + sizeof(float);
596 }
597
598 *((float*) data) = PA_FLOAT32_SWAP(sum);
599
600 data = (uint8_t*) data + sizeof(float);
601
602 if (PA_UNLIKELY(++channel >= spec->channels))
603 channel = 0;
604 }
605
606 break;
607 }
608
609 default:
610 pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
611 pa_assert_not_reached();
612 }
613
614 for (k = 0; k < nstreams; k++)
615 pa_memblock_release(streams[k].chunk.memblock);
616
617 return length;
618 }
619
620 typedef union {
621 float f;
622 uint32_t i;
623 } volume_val;
624
625 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
626
627 static const pa_calc_volume_func_t calc_volume_table[] = {
628 [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume,
629 [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
630 [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
631 [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
632 [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
633 [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
634 [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
635 [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
636 [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
637 [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
638 [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
639 [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
640 [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume
641 };
642
643 void pa_volume_memchunk(
644 pa_memchunk*c,
645 const pa_sample_spec *spec,
646 const pa_cvolume *volume) {
647
648 void *ptr;
649 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
650 pa_do_volume_func_t do_volume;
651
652 pa_assert(c);
653 pa_assert(spec);
654 pa_assert(pa_sample_spec_valid(spec));
655 pa_assert(pa_frame_aligned(c->length, spec));
656 pa_assert(volume);
657
658 if (pa_memblock_is_silence(c->memblock))
659 return;
660
661 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
662 return;
663
664 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
665 pa_silence_memchunk(c, spec);
666 return;
667 }
668
669 do_volume = pa_get_volume_func(spec->format);
670 pa_assert(do_volume);
671
672 calc_volume_table[spec->format] ((void *)linear, volume);
673
674 ptr = pa_memblock_acquire_chunk(c);
675
676 do_volume(ptr, (void *)linear, spec->channels, c->length);
677
678 pa_memblock_release(c->memblock);
679 }