2 This file is part of PulseAudio.
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>
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.
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.
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
30 #include <pulsecore/sample-util.h>
31 #include <pulsecore/macro.h>
32 #include <pulsecore/g711.h>
33 #include <pulsecore/endianmacros.h>
37 #define VOLUME_PADDING 32
39 static void calc_linear_integer_volume(int32_t linear
[], const pa_cvolume
*volume
) {
40 unsigned channel
, nchannels
, padding
;
45 nchannels
= volume
->channels
;
47 for (channel
= 0; channel
< nchannels
; channel
++)
48 linear
[channel
] = (int32_t) lrint(pa_sw_volume_to_linear(volume
->values
[channel
]) * 0x10000);
50 for (padding
= 0; padding
< VOLUME_PADDING
; padding
++, channel
++)
51 linear
[channel
] = linear
[padding
];
54 static void calc_linear_float_volume(float linear
[], const pa_cvolume
*volume
) {
55 unsigned channel
, nchannels
, padding
;
60 nchannels
= volume
->channels
;
62 for (channel
= 0; channel
< nchannels
; channel
++)
63 linear
[channel
] = (float) pa_sw_volume_to_linear(volume
->values
[channel
]);
65 for (padding
= 0; padding
< VOLUME_PADDING
; padding
++, channel
++)
66 linear
[channel
] = linear
[padding
];
69 static void calc_linear_integer_stream_volumes(pa_mix_info streams
[], unsigned nstreams
, const pa_cvolume
*volume
, const pa_sample_spec
*spec
) {
71 float linear
[PA_CHANNELS_MAX
+ VOLUME_PADDING
];
77 calc_linear_float_volume(linear
, volume
);
79 for (k
= 0; k
< nstreams
; k
++) {
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);
88 static void calc_linear_float_stream_volumes(pa_mix_info streams
[], unsigned nstreams
, const pa_cvolume
*volume
, const pa_sample_spec
*spec
) {
90 float linear
[PA_CHANNELS_MAX
+ VOLUME_PADDING
];
96 calc_linear_float_volume(linear
, volume
);
98 for (k
= 0; k
< nstreams
; k
++) {
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
]);
107 typedef void (*pa_calc_stream_volumes_func_t
) (pa_mix_info streams
[], unsigned nstreams
, const pa_cvolume
*volume
, const pa_sample_spec
*spec
);
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
125 static void pa_mix_s16ne_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
126 unsigned channel
= 0;
132 for (i
= 0; i
< nstreams
; i
++) {
133 pa_mix_info
*m
= streams
+ i
;
134 int32_t v
, lo
, hi
, cv
= m
->linear
[channel
].i
;
136 if (PA_LIKELY(cv
> 0)) {
138 /* Multiplying the 32bit volume factor with the
139 * 16bit sample might result in an 48bit value. We
140 * want to do without 64 bit integers and hence do
141 * the multiplication independently for the HI and
142 * LO part of the volume. */
147 v
= *((int16_t*) m
->ptr
);
148 v
= ((v
* lo
) >> 16) + (v
* hi
);
151 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int16_t);
154 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
155 *((int16_t*) data
) = (int16_t) sum
;
157 data
= (uint8_t*) data
+ sizeof(int16_t);
159 if (PA_UNLIKELY(++channel
>= channels
))
164 static void pa_mix_s16re_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
165 unsigned channel
= 0;
171 for (i
= 0; i
< nstreams
; i
++) {
172 pa_mix_info
*m
= streams
+ i
;
173 int32_t v
, lo
, hi
, cv
= m
->linear
[channel
].i
;
175 if (PA_LIKELY(cv
> 0)) {
180 v
= PA_INT16_SWAP(*((int16_t*) m
->ptr
));
181 v
= ((v
* lo
) >> 16) + (v
* hi
);
184 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int16_t);
187 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
188 *((int16_t*) data
) = PA_INT16_SWAP((int16_t) sum
);
190 data
= (uint8_t*) data
+ sizeof(int16_t);
192 if (PA_UNLIKELY(++channel
>= channels
))
197 static void pa_mix_s32ne_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
198 unsigned channel
= 0;
204 for (i
= 0; i
< nstreams
; i
++) {
205 pa_mix_info
*m
= streams
+ i
;
206 int32_t cv
= m
->linear
[channel
].i
;
209 if (PA_LIKELY(cv
> 0)) {
211 v
= *((int32_t*) m
->ptr
);
215 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int32_t);
218 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
219 *((int32_t*) data
) = (int32_t) sum
;
221 data
= (uint8_t*) data
+ sizeof(int32_t);
223 if (PA_UNLIKELY(++channel
>= channels
))
228 static void pa_mix_s32re_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
229 unsigned channel
= 0;
235 for (i
= 0; i
< nstreams
; i
++) {
236 pa_mix_info
*m
= streams
+ i
;
237 int32_t cv
= m
->linear
[channel
].i
;
240 if (PA_LIKELY(cv
> 0)) {
242 v
= PA_INT32_SWAP(*((int32_t*) m
->ptr
));
246 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int32_t);
249 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
250 *((int32_t*) data
) = PA_INT32_SWAP((int32_t) sum
);
252 data
= (uint8_t*) data
+ sizeof(int32_t);
254 if (PA_UNLIKELY(++channel
>= channels
))
259 static void pa_mix_s24ne_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
260 unsigned channel
= 0;
266 for (i
= 0; i
< nstreams
; i
++) {
267 pa_mix_info
*m
= streams
+ i
;
268 int32_t cv
= m
->linear
[channel
].i
;
271 if (PA_LIKELY(cv
> 0)) {
273 v
= (int32_t) (PA_READ24NE(m
->ptr
) << 8);
277 m
->ptr
= (uint8_t*) m
->ptr
+ 3;
280 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
281 PA_WRITE24NE(data
, ((uint32_t) sum
) >> 8);
283 data
= (uint8_t*) data
+ 3;
285 if (PA_UNLIKELY(++channel
>= channels
))
290 static void pa_mix_s24re_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
291 unsigned channel
= 0;
297 for (i
= 0; i
< nstreams
; i
++) {
298 pa_mix_info
*m
= streams
+ i
;
299 int32_t cv
= m
->linear
[channel
].i
;
302 if (PA_LIKELY(cv
> 0)) {
304 v
= (int32_t) (PA_READ24RE(m
->ptr
) << 8);
308 m
->ptr
= (uint8_t*) m
->ptr
+ 3;
311 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
312 PA_WRITE24RE(data
, ((uint32_t) sum
) >> 8);
314 data
= (uint8_t*) data
+ 3;
316 if (PA_UNLIKELY(++channel
>= channels
))
321 static void pa_mix_s24_32ne_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
322 unsigned channel
= 0;
328 for (i
= 0; i
< nstreams
; i
++) {
329 pa_mix_info
*m
= streams
+ i
;
330 int32_t cv
= m
->linear
[channel
].i
;
333 if (PA_LIKELY(cv
> 0)) {
335 v
= (int32_t) (*((uint32_t*)m
->ptr
) << 8);
339 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(int32_t);
342 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
343 *((uint32_t*) data
) = ((uint32_t) (int32_t) sum
) >> 8;
345 data
= (uint8_t*) data
+ sizeof(uint32_t);
347 if (PA_UNLIKELY(++channel
>= channels
))
352 static void pa_mix_s24_32re_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
353 unsigned channel
= 0;
359 for (i
= 0; i
< nstreams
; i
++) {
360 pa_mix_info
*m
= streams
+ i
;
361 int32_t cv
= m
->linear
[channel
].i
;
364 if (PA_LIKELY(cv
> 0)) {
366 v
= (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m
->ptr
)) << 8);
370 m
->ptr
= (uint8_t*) m
->ptr
+ 3;
373 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80000000LL
, 0x7FFFFFFFLL
);
374 *((uint32_t*) data
) = PA_INT32_SWAP(((uint32_t) (int32_t) sum
) >> 8);
376 data
= (uint8_t*) data
+ sizeof(uint32_t);
378 if (PA_UNLIKELY(++channel
>= channels
))
383 static void pa_mix_u8_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
384 unsigned channel
= 0;
390 for (i
= 0; i
< nstreams
; i
++) {
391 pa_mix_info
*m
= streams
+ i
;
392 int32_t v
, cv
= m
->linear
[channel
].i
;
394 if (PA_LIKELY(cv
> 0)) {
396 v
= (int32_t) *((uint8_t*) m
->ptr
) - 0x80;
400 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
403 sum
= PA_CLAMP_UNLIKELY(sum
, -0x80, 0x7F);
404 *((uint8_t*) data
) = (uint8_t) (sum
+ 0x80);
406 data
= (uint8_t*) data
+ 1;
408 if (PA_UNLIKELY(++channel
>= channels
))
413 static void pa_mix_ulaw_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
414 unsigned channel
= 0;
420 for (i
= 0; i
< nstreams
; i
++) {
421 pa_mix_info
*m
= streams
+ i
;
422 int32_t v
, hi
, lo
, cv
= m
->linear
[channel
].i
;
424 if (PA_LIKELY(cv
> 0)) {
429 v
= (int32_t) st_ulaw2linear16(*((uint8_t*) m
->ptr
));
430 v
= ((v
* lo
) >> 16) + (v
* hi
);
433 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
436 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
437 *((uint8_t*) data
) = (uint8_t) st_14linear2ulaw((int16_t) sum
>> 2);
439 data
= (uint8_t*) data
+ 1;
441 if (PA_UNLIKELY(++channel
>= channels
))
446 static void pa_mix_alaw_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
447 unsigned channel
= 0;
453 for (i
= 0; i
< nstreams
; i
++) {
454 pa_mix_info
*m
= streams
+ i
;
455 int32_t v
, hi
, lo
, cv
= m
->linear
[channel
].i
;
457 if (PA_LIKELY(cv
> 0)) {
462 v
= (int32_t) st_alaw2linear16(*((uint8_t*) m
->ptr
));
463 v
= ((v
* lo
) >> 16) + (v
* hi
);
466 m
->ptr
= (uint8_t*) m
->ptr
+ 1;
469 sum
= PA_CLAMP_UNLIKELY(sum
, -0x8000, 0x7FFF);
470 *((uint8_t*) data
) = (uint8_t) st_13linear2alaw((int16_t) sum
>> 3);
472 data
= (uint8_t*) data
+ 1;
474 if (PA_UNLIKELY(++channel
>= channels
))
479 static void pa_mix_float32ne_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
480 unsigned channel
= 0;
486 for (i
= 0; i
< nstreams
; i
++) {
487 pa_mix_info
*m
= streams
+ i
;
488 float v
, cv
= m
->linear
[channel
].f
;
490 if (PA_LIKELY(cv
> 0)) {
492 v
= *((float*) m
->ptr
);
496 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(float);
499 *((float*) data
) = sum
;
501 data
= (uint8_t*) data
+ sizeof(float);
503 if (PA_UNLIKELY(++channel
>= channels
))
508 static void pa_mix_float32re_c(pa_mix_info streams
[], unsigned nstreams
, unsigned channels
, void *data
, void *end
) {
509 unsigned channel
= 0;
515 for (i
= 0; i
< nstreams
; i
++) {
516 pa_mix_info
*m
= streams
+ i
;
517 float v
, cv
= m
->linear
[channel
].f
;
519 if (PA_LIKELY(cv
> 0)) {
521 v
= PA_FLOAT32_SWAP(*(float*) m
->ptr
);
525 m
->ptr
= (uint8_t*) m
->ptr
+ sizeof(float);
528 *((float*) data
) = PA_FLOAT32_SWAP(sum
);
530 data
= (uint8_t*) data
+ sizeof(float);
532 if (PA_UNLIKELY(++channel
>= channels
))
537 static pa_do_mix_func_t do_mix_table
[] = {
538 [PA_SAMPLE_U8
] = (pa_do_mix_func_t
) pa_mix_u8_c
,
539 [PA_SAMPLE_ALAW
] = (pa_do_mix_func_t
) pa_mix_alaw_c
,
540 [PA_SAMPLE_ULAW
] = (pa_do_mix_func_t
) pa_mix_ulaw_c
,
541 [PA_SAMPLE_S16NE
] = (pa_do_mix_func_t
) pa_mix_s16ne_c
,
542 [PA_SAMPLE_S16RE
] = (pa_do_mix_func_t
) pa_mix_s16re_c
,
543 [PA_SAMPLE_FLOAT32NE
] = (pa_do_mix_func_t
) pa_mix_float32ne_c
,
544 [PA_SAMPLE_FLOAT32RE
] = (pa_do_mix_func_t
) pa_mix_float32re_c
,
545 [PA_SAMPLE_S32NE
] = (pa_do_mix_func_t
) pa_mix_s32ne_c
,
546 [PA_SAMPLE_S32RE
] = (pa_do_mix_func_t
) pa_mix_s32re_c
,
547 [PA_SAMPLE_S24NE
] = (pa_do_mix_func_t
) pa_mix_s24ne_c
,
548 [PA_SAMPLE_S24RE
] = (pa_do_mix_func_t
) pa_mix_s24re_c
,
549 [PA_SAMPLE_S24_32NE
] = (pa_do_mix_func_t
) pa_mix_s24_32ne_c
,
550 [PA_SAMPLE_S24_32RE
] = (pa_do_mix_func_t
) pa_mix_s24_32re_c
554 pa_mix_info streams
[],
558 const pa_sample_spec
*spec
,
559 const pa_cvolume
*volume
,
562 pa_cvolume full_volume
;
573 volume
= pa_cvolume_reset(&full_volume
, spec
->channels
);
575 if (mute
|| pa_cvolume_is_muted(volume
) || nstreams
<= 0) {
576 pa_silence_memory(data
, length
, spec
);
580 for (k
= 0; k
< nstreams
; k
++)
581 streams
[k
].ptr
= pa_memblock_acquire_chunk(&streams
[k
].chunk
);
583 for (z
= 0; z
< nstreams
; z
++)
584 if (length
> streams
[z
].chunk
.length
)
585 length
= streams
[z
].chunk
.length
;
587 end
= (uint8_t*) data
+ length
;
589 calc_stream_volumes_table
[spec
->format
](streams
, nstreams
, volume
, spec
);
590 do_mix_table
[spec
->format
](streams
, nstreams
, spec
->channels
, data
, end
);
592 for (k
= 0; k
< nstreams
; k
++)
593 pa_memblock_release(streams
[k
].chunk
.memblock
);
598 pa_do_mix_func_t
pa_get_mix_func(pa_sample_format_t f
) {
600 pa_assert(f
< PA_SAMPLE_MAX
);
602 return do_mix_table
[f
];
605 void pa_set_mix_func(pa_sample_format_t f
, pa_do_mix_func_t func
) {
607 pa_assert(f
< PA_SAMPLE_MAX
);
609 do_mix_table
[f
] = func
;
617 typedef void (*pa_calc_volume_func_t
) (void *volumes
, const pa_cvolume
*volume
);
619 static const pa_calc_volume_func_t calc_volume_table
[] = {
620 [PA_SAMPLE_U8
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
621 [PA_SAMPLE_ALAW
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
622 [PA_SAMPLE_ULAW
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
623 [PA_SAMPLE_S16LE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
624 [PA_SAMPLE_S16BE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
625 [PA_SAMPLE_FLOAT32LE
] = (pa_calc_volume_func_t
) calc_linear_float_volume
,
626 [PA_SAMPLE_FLOAT32BE
] = (pa_calc_volume_func_t
) calc_linear_float_volume
,
627 [PA_SAMPLE_S32LE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
628 [PA_SAMPLE_S32BE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
629 [PA_SAMPLE_S24LE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
630 [PA_SAMPLE_S24BE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
631 [PA_SAMPLE_S24_32LE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
,
632 [PA_SAMPLE_S24_32BE
] = (pa_calc_volume_func_t
) calc_linear_integer_volume
635 void pa_volume_memchunk(
637 const pa_sample_spec
*spec
,
638 const pa_cvolume
*volume
) {
641 volume_val linear
[PA_CHANNELS_MAX
+ VOLUME_PADDING
];
642 pa_do_volume_func_t do_volume
;
646 pa_assert(pa_sample_spec_valid(spec
));
647 pa_assert(pa_frame_aligned(c
->length
, spec
));
650 if (pa_memblock_is_silence(c
->memblock
))
653 if (pa_cvolume_channels_equal_to(volume
, PA_VOLUME_NORM
))
656 if (pa_cvolume_channels_equal_to(volume
, PA_VOLUME_MUTED
)) {
657 pa_silence_memchunk(c
, spec
);
661 do_volume
= pa_get_volume_func(spec
->format
);
662 pa_assert(do_volume
);
664 calc_volume_table
[spec
->format
] ((void *)linear
, volume
);
666 ptr
= pa_memblock_acquire_chunk(c
);
668 do_volume(ptr
, (void *)linear
, spec
->channels
, c
->length
);
670 pa_memblock_release(c
->memblock
);