]> code.delx.au - pulseaudio/blob - src/pulsecore/mix.c
mix: Export function to get/set mixing implementation for a sample format
[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 static void pa_mix_s16ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
126 unsigned channel = 0;
127
128 while (data < end) {
129 int32_t sum = 0;
130 unsigned i;
131
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;
135
136 if (PA_LIKELY(cv > 0)) {
137
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. */
143
144 hi = cv >> 16;
145 lo = cv & 0xFFFF;
146
147 v = *((int16_t*) m->ptr);
148 v = ((v * lo) >> 16) + (v * hi);
149 sum += v;
150 }
151 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
152 }
153
154 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
155 *((int16_t*) data) = (int16_t) sum;
156
157 data = (uint8_t*) data + sizeof(int16_t);
158
159 if (PA_UNLIKELY(++channel >= channels))
160 channel = 0;
161 }
162 }
163
164 static void pa_mix_s16re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
165 unsigned channel = 0;
166
167 while (data < end) {
168 int32_t sum = 0;
169 unsigned i;
170
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;
174
175 if (PA_LIKELY(cv > 0)) {
176
177 hi = cv >> 16;
178 lo = cv & 0xFFFF;
179
180 v = PA_INT16_SWAP(*((int16_t*) m->ptr));
181 v = ((v * lo) >> 16) + (v * hi);
182 sum += v;
183 }
184 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
185 }
186
187 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
188 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
189
190 data = (uint8_t*) data + sizeof(int16_t);
191
192 if (PA_UNLIKELY(++channel >= channels))
193 channel = 0;
194 }
195 }
196
197 static void pa_mix_s32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
198 unsigned channel = 0;
199
200 while (data < end) {
201 int64_t sum = 0;
202 unsigned i;
203
204 for (i = 0; i < nstreams; i++) {
205 pa_mix_info *m = streams + i;
206 int32_t cv = m->linear[channel].i;
207 int64_t v;
208
209 if (PA_LIKELY(cv > 0)) {
210
211 v = *((int32_t*) m->ptr);
212 v = (v * cv) >> 16;
213 sum += v;
214 }
215 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
216 }
217
218 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
219 *((int32_t*) data) = (int32_t) sum;
220
221 data = (uint8_t*) data + sizeof(int32_t);
222
223 if (PA_UNLIKELY(++channel >= channels))
224 channel = 0;
225 }
226 }
227
228 static void pa_mix_s32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
229 unsigned channel = 0;
230
231 while (data < end) {
232 int64_t sum = 0;
233 unsigned i;
234
235 for (i = 0; i < nstreams; i++) {
236 pa_mix_info *m = streams + i;
237 int32_t cv = m->linear[channel].i;
238 int64_t v;
239
240 if (PA_LIKELY(cv > 0)) {
241
242 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
243 v = (v * cv) >> 16;
244 sum += v;
245 }
246 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
247 }
248
249 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
250 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
251
252 data = (uint8_t*) data + sizeof(int32_t);
253
254 if (PA_UNLIKELY(++channel >= channels))
255 channel = 0;
256 }
257 }
258
259 static void pa_mix_s24ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
260 unsigned channel = 0;
261
262 while (data < end) {
263 int64_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 int64_t v;
270
271 if (PA_LIKELY(cv > 0)) {
272
273 v = (int32_t) (PA_READ24NE(m->ptr) << 8);
274 v = (v * cv) >> 16;
275 sum += v;
276 }
277 m->ptr = (uint8_t*) m->ptr + 3;
278 }
279
280 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
281 PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
282
283 data = (uint8_t*) data + 3;
284
285 if (PA_UNLIKELY(++channel >= channels))
286 channel = 0;
287 }
288 }
289
290 static void pa_mix_s24re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
291 unsigned channel = 0;
292
293 while (data < end) {
294 int64_t sum = 0;
295 unsigned i;
296
297 for (i = 0; i < nstreams; i++) {
298 pa_mix_info *m = streams + i;
299 int32_t cv = m->linear[channel].i;
300 int64_t v;
301
302 if (PA_LIKELY(cv > 0)) {
303
304 v = (int32_t) (PA_READ24RE(m->ptr) << 8);
305 v = (v * cv) >> 16;
306 sum += v;
307 }
308 m->ptr = (uint8_t*) m->ptr + 3;
309 }
310
311 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
312 PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
313
314 data = (uint8_t*) data + 3;
315
316 if (PA_UNLIKELY(++channel >= channels))
317 channel = 0;
318 }
319 }
320
321 static void pa_mix_s24_32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
322 unsigned channel = 0;
323
324 while (data < end) {
325 int64_t sum = 0;
326 unsigned i;
327
328 for (i = 0; i < nstreams; i++) {
329 pa_mix_info *m = streams + i;
330 int32_t cv = m->linear[channel].i;
331 int64_t v;
332
333 if (PA_LIKELY(cv > 0)) {
334
335 v = (int32_t) (*((uint32_t*)m->ptr) << 8);
336 v = (v * cv) >> 16;
337 sum += v;
338 }
339 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
340 }
341
342 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
343 *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
344
345 data = (uint8_t*) data + sizeof(uint32_t);
346
347 if (PA_UNLIKELY(++channel >= channels))
348 channel = 0;
349 }
350 }
351
352 static void pa_mix_s24_32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
353 unsigned channel = 0;
354
355 while (data < end) {
356 int64_t sum = 0;
357 unsigned i;
358
359 for (i = 0; i < nstreams; i++) {
360 pa_mix_info *m = streams + i;
361 int32_t cv = m->linear[channel].i;
362 int64_t v;
363
364 if (PA_LIKELY(cv > 0)) {
365
366 v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
367 v = (v * cv) >> 16;
368 sum += v;
369 }
370 m->ptr = (uint8_t*) m->ptr + 3;
371 }
372
373 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
374 *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
375
376 data = (uint8_t*) data + sizeof(uint32_t);
377
378 if (PA_UNLIKELY(++channel >= channels))
379 channel = 0;
380 }
381 }
382
383 static void pa_mix_u8_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
384 unsigned channel = 0;
385
386 while (data < end) {
387 int32_t sum = 0;
388 unsigned i;
389
390 for (i = 0; i < nstreams; i++) {
391 pa_mix_info *m = streams + i;
392 int32_t v, cv = m->linear[channel].i;
393
394 if (PA_LIKELY(cv > 0)) {
395
396 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
397 v = (v * cv) >> 16;
398 sum += v;
399 }
400 m->ptr = (uint8_t*) m->ptr + 1;
401 }
402
403 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
404 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
405
406 data = (uint8_t*) data + 1;
407
408 if (PA_UNLIKELY(++channel >= channels))
409 channel = 0;
410 }
411 }
412
413 static void pa_mix_ulaw_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
414 unsigned channel = 0;
415
416 while (data < end) {
417 int32_t sum = 0;
418 unsigned i;
419
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;
423
424 if (PA_LIKELY(cv > 0)) {
425
426 hi = cv >> 16;
427 lo = cv & 0xFFFF;
428
429 v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
430 v = ((v * lo) >> 16) + (v * hi);
431 sum += v;
432 }
433 m->ptr = (uint8_t*) m->ptr + 1;
434 }
435
436 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
437 *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
438
439 data = (uint8_t*) data + 1;
440
441 if (PA_UNLIKELY(++channel >= channels))
442 channel = 0;
443 }
444 }
445
446 static void pa_mix_alaw_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
447 unsigned channel = 0;
448
449 while (data < end) {
450 int32_t sum = 0;
451 unsigned i;
452
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;
456
457 if (PA_LIKELY(cv > 0)) {
458
459 hi = cv >> 16;
460 lo = cv & 0xFFFF;
461
462 v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
463 v = ((v * lo) >> 16) + (v * hi);
464 sum += v;
465 }
466 m->ptr = (uint8_t*) m->ptr + 1;
467 }
468
469 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
470 *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
471
472 data = (uint8_t*) data + 1;
473
474 if (PA_UNLIKELY(++channel >= channels))
475 channel = 0;
476 }
477 }
478
479 static void pa_mix_float32ne_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
480 unsigned channel = 0;
481
482 while (data < end) {
483 float sum = 0;
484 unsigned i;
485
486 for (i = 0; i < nstreams; i++) {
487 pa_mix_info *m = streams + i;
488 float v, cv = m->linear[channel].f;
489
490 if (PA_LIKELY(cv > 0)) {
491
492 v = *((float*) m->ptr);
493 v *= cv;
494 sum += v;
495 }
496 m->ptr = (uint8_t*) m->ptr + sizeof(float);
497 }
498
499 *((float*) data) = sum;
500
501 data = (uint8_t*) data + sizeof(float);
502
503 if (PA_UNLIKELY(++channel >= channels))
504 channel = 0;
505 }
506 }
507
508 static void pa_mix_float32re_c(pa_mix_info streams[], unsigned nstreams, unsigned channels, void *data, void *end) {
509 unsigned channel = 0;
510
511 while (data < end) {
512 float sum = 0;
513 unsigned i;
514
515 for (i = 0; i < nstreams; i++) {
516 pa_mix_info *m = streams + i;
517 float v, cv = m->linear[channel].f;
518
519 if (PA_LIKELY(cv > 0)) {
520
521 v = PA_FLOAT32_SWAP(*(float*) m->ptr);
522 v *= cv;
523 sum += v;
524 }
525 m->ptr = (uint8_t*) m->ptr + sizeof(float);
526 }
527
528 *((float*) data) = PA_FLOAT32_SWAP(sum);
529
530 data = (uint8_t*) data + sizeof(float);
531
532 if (PA_UNLIKELY(++channel >= channels))
533 channel = 0;
534 }
535 }
536
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
551 };
552
553 size_t pa_mix(
554 pa_mix_info streams[],
555 unsigned nstreams,
556 void *data,
557 size_t length,
558 const pa_sample_spec *spec,
559 const pa_cvolume *volume,
560 pa_bool_t mute) {
561
562 pa_cvolume full_volume;
563 unsigned k;
564 unsigned z;
565 void *end;
566
567 pa_assert(streams);
568 pa_assert(data);
569 pa_assert(length);
570 pa_assert(spec);
571
572 if (!volume)
573 volume = pa_cvolume_reset(&full_volume, spec->channels);
574
575 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
576 pa_silence_memory(data, length, spec);
577 return length;
578 }
579
580 for (k = 0; k < nstreams; k++)
581 streams[k].ptr = pa_memblock_acquire_chunk(&streams[k].chunk);
582
583 for (z = 0; z < nstreams; z++)
584 if (length > streams[z].chunk.length)
585 length = streams[z].chunk.length;
586
587 end = (uint8_t*) data + length;
588
589 calc_stream_volumes_table[spec->format](streams, nstreams, volume, spec);
590 do_mix_table[spec->format](streams, nstreams, spec->channels, data, end);
591
592 for (k = 0; k < nstreams; k++)
593 pa_memblock_release(streams[k].chunk.memblock);
594
595 return length;
596 }
597
598 pa_do_mix_func_t pa_get_mix_func(pa_sample_format_t f) {
599 pa_assert(f >= 0);
600 pa_assert(f < PA_SAMPLE_MAX);
601
602 return do_mix_table[f];
603 }
604
605 void pa_set_mix_func(pa_sample_format_t f, pa_do_mix_func_t func) {
606 pa_assert(f >= 0);
607 pa_assert(f < PA_SAMPLE_MAX);
608
609 do_mix_table[f] = func;
610 }
611
612 typedef union {
613 float f;
614 uint32_t i;
615 } volume_val;
616
617 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
618
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
633 };
634
635 void pa_volume_memchunk(
636 pa_memchunk*c,
637 const pa_sample_spec *spec,
638 const pa_cvolume *volume) {
639
640 void *ptr;
641 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
642 pa_do_volume_func_t do_volume;
643
644 pa_assert(c);
645 pa_assert(spec);
646 pa_assert(pa_sample_spec_valid(spec));
647 pa_assert(pa_frame_aligned(c->length, spec));
648 pa_assert(volume);
649
650 if (pa_memblock_is_silence(c->memblock))
651 return;
652
653 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
654 return;
655
656 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
657 pa_silence_memchunk(c, spec);
658 return;
659 }
660
661 do_volume = pa_get_volume_func(spec->format);
662 pa_assert(do_volume);
663
664 calc_volume_table[spec->format] ((void *)linear, volume);
665
666 ptr = pa_memblock_acquire_chunk(c);
667
668 do_volume(ptr, (void *)linear, spec->channels, c->length);
669
670 pa_memblock_release(c->memblock);
671 }