]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
otpimize mixing code a bit by moving a few checks out of the inner loops
[pulseaudio] / src / pulsecore / sample-util.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
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include <liboil/liboilfuncs.h>
32 #include <liboil/liboil.h>
33
34 #include <pulsecore/log.h>
35 #include <pulsecore/macro.h>
36 #include <pulsecore/g711.h>
37
38 #include "sample-util.h"
39 #include "endianmacros.h"
40
41 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
42
43 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
44 void *data;
45
46 pa_assert(b);
47 pa_assert(spec);
48
49 data = pa_memblock_acquire(b);
50 pa_silence_memory(data, pa_memblock_get_length(b), spec);
51 pa_memblock_release(b);
52
53 return b;
54 }
55
56 pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
57 void *data;
58
59 pa_assert(c);
60 pa_assert(c->memblock);
61 pa_assert(spec);
62
63 data = pa_memblock_acquire(c->memblock);
64 pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
65 pa_memblock_release(c->memblock);
66
67 return c;
68 }
69
70 static uint8_t silence_byte(pa_sample_format_t format) {
71 switch (format) {
72 case PA_SAMPLE_U8:
73 return 0x80;
74 case PA_SAMPLE_S16LE:
75 case PA_SAMPLE_S16BE:
76 case PA_SAMPLE_S32LE:
77 case PA_SAMPLE_S32BE:
78 case PA_SAMPLE_FLOAT32LE:
79 case PA_SAMPLE_FLOAT32BE:
80 return 0;
81 case PA_SAMPLE_ALAW:
82 return 0xd5;
83 case PA_SAMPLE_ULAW:
84 return 0xff;
85 default:
86 pa_assert_not_reached();
87 }
88 return 0;
89 }
90
91 void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
92 pa_assert(p);
93 pa_assert(length > 0);
94 pa_assert(spec);
95
96 memset(p, silence_byte(spec->format), length);
97 return p;
98 }
99
100 static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) {
101 unsigned k;
102
103 pa_assert(streams);
104 pa_assert(spec);
105
106 for (k = 0; k < nstreams; k++) {
107 unsigned channel;
108
109 for (channel = 0; channel < spec->channels; channel++) {
110 pa_mix_info *m = streams + k;
111 m->linear[channel].i = (int32_t) (pa_sw_volume_to_linear(m->volume.values[channel]) * 0x10000);
112 }
113 }
114 }
115
116 static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
117 unsigned channel;
118
119 pa_assert(linear);
120 pa_assert(volume);
121
122 for (channel = 0; channel < volume->channels; channel++)
123 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
124 }
125
126 static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) {
127 unsigned k;
128
129 pa_assert(streams);
130 pa_assert(spec);
131
132 for (k = 0; k < nstreams; k++) {
133 unsigned channel;
134
135 for (channel = 0; channel < spec->channels; channel++) {
136 pa_mix_info *m = streams + k;
137 m->linear[channel].f = pa_sw_volume_to_linear(m->volume.values[channel]);
138 }
139 }
140 }
141
142 static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
143 unsigned channel;
144
145 pa_assert(linear);
146 pa_assert(volume);
147
148 for (channel = 0; channel < volume->channels; channel++)
149 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
150 }
151
152 size_t pa_mix(
153 pa_mix_info streams[],
154 unsigned nstreams,
155 void *data,
156 size_t length,
157 const pa_sample_spec *spec,
158 const pa_cvolume *volume,
159 pa_bool_t mute) {
160
161 pa_cvolume full_volume;
162 unsigned k;
163 unsigned z;
164 void *end;
165
166 pa_assert(streams);
167 pa_assert(data);
168 pa_assert(length);
169 pa_assert(spec);
170
171 if (!volume)
172 volume = pa_cvolume_reset(&full_volume, spec->channels);
173
174 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
175 pa_silence_memory(data, length, spec);
176 return length;
177 }
178
179 for (k = 0; k < nstreams; k++)
180 streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
181
182 for (z = 0; z < nstreams; z++)
183 if (length > streams[z].chunk.length)
184 length = streams[z].chunk.length;
185
186 end = (uint8_t*) data + length;
187
188 switch (spec->format) {
189
190 case PA_SAMPLE_S16NE:{
191 unsigned channel = 0;
192 int32_t linear[PA_CHANNELS_MAX];
193
194 calc_linear_integer_stream_volumes(streams, nstreams, spec);
195 calc_linear_integer_volume(linear, volume);
196
197 while (data < end) {
198 int32_t sum = 0;
199 unsigned i;
200
201 for (i = 0; i < nstreams; i++) {
202 pa_mix_info *m = streams + i;
203 int32_t v, cv = m->linear[channel].i;
204
205 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
206 v = 0;
207 else {
208 v = *((int16_t*) m->ptr);
209 v = (v * cv) / 0x10000;
210 }
211
212 sum += v;
213 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
214 }
215
216 sum = (sum * linear[channel]) / 0x10000;
217 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
218 *((int16_t*) data) = (int16_t) sum;
219
220 data = (uint8_t*) data + sizeof(int16_t);
221
222 if (PA_UNLIKELY(++channel >= spec->channels))
223 channel = 0;
224 }
225
226 break;
227 }
228
229 case PA_SAMPLE_S16RE:{
230 unsigned channel = 0;
231 int32_t linear[PA_CHANNELS_MAX];
232
233 calc_linear_integer_stream_volumes(streams, nstreams, spec);
234 calc_linear_integer_volume(linear, volume);
235
236 while (data < end) {
237 int32_t sum = 0;
238 unsigned i;
239
240 for (i = 0; i < nstreams; i++) {
241 pa_mix_info *m = streams + i;
242 int32_t v, cv = m->linear[channel].i;
243
244 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
245 v = 0;
246 else {
247 v = PA_INT16_SWAP(*((int16_t*) m->ptr));
248 v = (v * cv) / 0x10000;
249 }
250
251 sum += v;
252 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
253 }
254
255 sum = (sum * linear[channel]) / 0x10000;
256 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
257 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
258
259 data = (uint8_t*) data + sizeof(int16_t);
260
261 if (PA_UNLIKELY(++channel >= spec->channels))
262 channel = 0;
263 }
264
265 break;
266 }
267
268 case PA_SAMPLE_S32NE:{
269 unsigned channel = 0;
270 int32_t linear[PA_CHANNELS_MAX];
271
272 calc_linear_integer_stream_volumes(streams, nstreams, spec);
273 calc_linear_integer_volume(linear, volume);
274
275 while (data < end) {
276 int64_t sum = 0;
277 unsigned i;
278
279 for (i = 0; i < nstreams; i++) {
280 pa_mix_info *m = streams + i;
281 int64_t v;
282 int32_t cv = m->linear[channel].i;
283
284 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
285 v = 0;
286 else {
287 v = *((int32_t*) m->ptr);
288 v = (v * cv) / 0x10000;
289 }
290
291 sum += v;
292 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
293 }
294
295 sum = (sum * linear[channel]) / 0x10000;
296 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
297 *((int32_t*) data) = (int32_t) sum;
298
299 data = (uint8_t*) data + sizeof(int32_t);
300
301 if (PA_UNLIKELY(++channel >= spec->channels))
302 channel = 0;
303 }
304
305 break;
306 }
307
308 case PA_SAMPLE_S32RE:{
309 unsigned channel = 0;
310 int32_t linear[PA_CHANNELS_MAX];
311
312 calc_linear_integer_stream_volumes(streams, nstreams, spec);
313 calc_linear_integer_volume(linear, volume);
314
315 while (data < end) {
316 int64_t sum = 0;
317 unsigned i;
318
319 for (i = 0; i < nstreams; i++) {
320 pa_mix_info *m = streams + i;
321 int64_t v;
322 int32_t cv = m->linear[channel].i;
323
324 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
325 v = 0;
326 else {
327 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
328 v = (v * cv) / 0x10000;
329 }
330
331 sum += v;
332 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
333 }
334
335 sum = (sum * linear[channel]) / 0x10000;
336 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
337 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
338
339 data = (uint8_t*) data + sizeof(int32_t);
340
341 if (PA_UNLIKELY(++channel >= spec->channels))
342 channel = 0;
343 }
344
345 break;
346 }
347
348 case PA_SAMPLE_U8: {
349 unsigned channel = 0;
350 int32_t linear[PA_CHANNELS_MAX];
351
352 calc_linear_integer_stream_volumes(streams, nstreams, spec);
353 calc_linear_integer_volume(linear, volume);
354
355 while (data < end) {
356 int32_t sum = 0;
357 unsigned i;
358
359 for (i = 0; i < nstreams; i++) {
360 pa_mix_info *m = streams + i;
361 int32_t v, cv = m->linear[channel].i;
362
363 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
364 v = 0;
365 else {
366 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
367 v = (v * cv) / 0x10000;
368 }
369
370 sum += v;
371 m->ptr = (uint8_t*) m->ptr + 1;
372 }
373
374 sum = (sum * linear[channel]) / 0x10000;
375 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
376 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
377
378 data = (uint8_t*) data + 1;
379
380 if (PA_UNLIKELY(++channel >= spec->channels))
381 channel = 0;
382 }
383
384 break;
385 }
386
387 case PA_SAMPLE_ULAW: {
388 unsigned channel = 0;
389 int32_t linear[PA_CHANNELS_MAX];
390
391 calc_linear_integer_stream_volumes(streams, nstreams, spec);
392 calc_linear_integer_volume(linear, volume);
393
394 while (data < end) {
395 int32_t sum = 0;
396 unsigned i;
397
398 for (i = 0; i < nstreams; i++) {
399 pa_mix_info *m = streams + i;
400 int32_t v, cv = m->linear[channel].i;
401
402 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
403 v = 0;
404 else {
405 v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
406 v = (v * cv) / 0x10000;
407 }
408
409 sum += v;
410 m->ptr = (uint8_t*) m->ptr + 1;
411 }
412
413 sum = (sum * linear[channel]) / 0x10000;
414 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
415 *((uint8_t*) data) = (uint8_t) st_14linear2ulaw(sum >> 2);
416
417 data = (uint8_t*) data + 1;
418
419 if (PA_UNLIKELY(++channel >= spec->channels))
420 channel = 0;
421 }
422
423 break;
424 }
425
426 case PA_SAMPLE_ALAW: {
427 unsigned channel = 0;
428 int32_t linear[PA_CHANNELS_MAX];
429
430 calc_linear_integer_stream_volumes(streams, nstreams, spec);
431 calc_linear_integer_volume(linear, volume);
432
433 while (data < end) {
434 int32_t sum = 0;
435 unsigned i;
436
437 for (i = 0; i < nstreams; i++) {
438 pa_mix_info *m = streams + i;
439 int32_t v, cv = m->linear[channel].i;
440
441 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
442 v = 0;
443 else {
444 v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
445 v = (v * cv) / 0x10000;
446 }
447
448 sum += v;
449 m->ptr = (uint8_t*) m->ptr + 1;
450 }
451
452 sum = (sum * linear[channel]) / 0x10000;
453 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
454 *((uint8_t*) data) = (uint8_t) st_13linear2alaw(sum >> 3);
455
456 data = (uint8_t*) data + 1;
457
458 if (PA_UNLIKELY(++channel >= spec->channels))
459 channel = 0;
460 }
461
462 break;
463 }
464
465 case PA_SAMPLE_FLOAT32NE: {
466 unsigned channel = 0;
467 float linear[PA_CHANNELS_MAX];
468
469 calc_linear_float_stream_volumes(streams, nstreams, spec);
470 calc_linear_float_volume(linear, volume);
471
472 while (data < end) {
473 float sum = 0;
474 unsigned i;
475
476 for (i = 0; i < nstreams; i++) {
477 pa_mix_info *m = streams + i;
478 float v, cv = m->linear[channel].f;
479
480 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
481 v = 0;
482 else {
483 v = *((float*) m->ptr);
484 v *= cv;
485 }
486
487 sum += v;
488 m->ptr = (uint8_t*) m->ptr + sizeof(float);
489 }
490
491 sum *= linear[channel];
492 *((float*) data) = sum;
493
494 data = (uint8_t*) data + sizeof(float);
495
496 if (PA_UNLIKELY(++channel >= spec->channels))
497 channel = 0;
498 }
499
500 break;
501 }
502
503 case PA_SAMPLE_FLOAT32RE: {
504 unsigned channel = 0;
505 float linear[PA_CHANNELS_MAX];
506
507 calc_linear_float_stream_volumes(streams, nstreams, spec);
508 calc_linear_float_volume(linear, volume);
509
510 while (data < end) {
511 float sum = 0;
512 unsigned i;
513
514 for (i = 0; i < nstreams; i++) {
515 pa_mix_info *m = streams + i;
516 float v, cv = m->linear[channel].f;
517
518 if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(linear[channel] <= 0))
519 v = 0;
520 else
521 v = PA_FLOAT32_SWAP(*(float*) m->ptr) *cv;
522
523 sum += v;
524 m->ptr = (uint8_t*) m->ptr + sizeof(float);
525 }
526
527 sum *= linear[channel];
528 *((float*) data) = PA_FLOAT32_SWAP(sum);
529
530 data = (uint8_t*) data + sizeof(float);
531
532 if (PA_UNLIKELY(++channel >= spec->channels))
533 channel = 0;
534 }
535
536 break;
537 }
538
539 default:
540 pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
541 pa_assert_not_reached();
542 }
543
544 for (k = 0; k < nstreams; k++)
545 pa_memblock_release(streams[k].chunk.memblock);
546
547 return length;
548 }
549
550
551 void pa_volume_memchunk(
552 pa_memchunk*c,
553 const pa_sample_spec *spec,
554 const pa_cvolume *volume) {
555
556 void *ptr;
557
558 pa_assert(c);
559 pa_assert(spec);
560 pa_assert(c->length % pa_frame_size(spec) == 0);
561 pa_assert(volume);
562
563 if (pa_memblock_is_silence(c->memblock))
564 return;
565
566 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
567 return;
568
569 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
570 pa_silence_memchunk(c, spec);
571 return;
572 }
573
574 ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
575
576 switch (spec->format) {
577
578 case PA_SAMPLE_S16NE: {
579 int16_t *d, *e;
580 unsigned channel;
581 int32_t linear[PA_CHANNELS_MAX];
582
583 calc_linear_integer_volume(linear, volume);
584
585 e = (int16_t*) ptr + c->length/sizeof(int16_t);
586
587 for (channel = 0, d = ptr; d < e; d++) {
588 int32_t t;
589
590 t = (int32_t)(*d);
591 t = (t * linear[channel]) / 0x10000;
592 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
593 *d = (int16_t) t;
594
595 if (PA_UNLIKELY(++channel >= spec->channels))
596 channel = 0;
597 }
598 break;
599 }
600
601 case PA_SAMPLE_S16RE: {
602 int16_t *d, *e;
603 unsigned channel;
604 int32_t linear[PA_CHANNELS_MAX];
605
606 calc_linear_integer_volume(linear, volume);
607
608 e = (int16_t*) ptr + c->length/sizeof(int16_t);
609
610 for (channel = 0, d = ptr; d < e; d++) {
611 int32_t t;
612
613 t = (int32_t) PA_INT16_SWAP(*d);
614 t = (t * linear[channel]) / 0x10000;
615 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
616 *d = PA_INT16_SWAP((int16_t) t);
617
618 if (PA_UNLIKELY(++channel >= spec->channels))
619 channel = 0;
620 }
621
622 break;
623 }
624
625 case PA_SAMPLE_S32NE: {
626 int32_t *d, *e;
627 unsigned channel;
628 int32_t linear[PA_CHANNELS_MAX];
629
630 calc_linear_integer_volume(linear, volume);
631
632 e = (int32_t*) ptr + c->length/sizeof(int32_t);
633
634 for (channel = 0, d = ptr; d < e; d++) {
635 int64_t t;
636
637 t = (int64_t)(*d);
638 t = (t * linear[channel]) / 0x10000;
639 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
640 *d = (int32_t) t;
641
642 if (PA_UNLIKELY(++channel >= spec->channels))
643 channel = 0;
644 }
645 break;
646 }
647
648 case PA_SAMPLE_S32RE: {
649 int32_t *d, *e;
650 unsigned channel;
651 int32_t linear[PA_CHANNELS_MAX];
652
653 calc_linear_integer_volume(linear, volume);
654
655 e = (int32_t*) ptr + c->length/sizeof(int32_t);
656
657 for (channel = 0, d = ptr; d < e; d++) {
658 int64_t t;
659
660 t = (int64_t) PA_INT32_SWAP(*d);
661 t = (t * linear[channel]) / 0x10000;
662 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
663 *d = PA_INT32_SWAP((int32_t) t);
664
665 if (PA_UNLIKELY(++channel >= spec->channels))
666 channel = 0;
667 }
668
669 break;
670 }
671
672 case PA_SAMPLE_U8: {
673 uint8_t *d, *e;
674 unsigned channel;
675 int32_t linear[PA_CHANNELS_MAX];
676
677 calc_linear_integer_volume(linear, volume);
678
679 e = (uint8_t*) ptr + c->length;
680
681 for (channel = 0, d = ptr; d < e; d++) {
682 int32_t t;
683
684 t = (int32_t) *d - 0x80;
685 t = (t * linear[channel]) / 0x10000;
686 t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
687 *d = (uint8_t) (t + 0x80);
688
689 if (PA_UNLIKELY(++channel >= spec->channels))
690 channel = 0;
691 }
692 break;
693 }
694
695 case PA_SAMPLE_ULAW: {
696 uint8_t *d, *e;
697 unsigned channel;
698 int32_t linear[PA_CHANNELS_MAX];
699
700 calc_linear_integer_volume(linear, volume);
701
702 e = (uint8_t*) ptr + c->length;
703
704 for (channel = 0, d = ptr; d < e; d++) {
705 int32_t t;
706
707 t = (int32_t) st_ulaw2linear16(*d);
708 t = (t * linear[channel]) / 0x10000;
709 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
710 *d = (uint8_t) st_14linear2ulaw(t >> 2);
711
712 if (PA_UNLIKELY(++channel >= spec->channels))
713 channel = 0;
714 }
715 break;
716 }
717
718 case PA_SAMPLE_ALAW: {
719 uint8_t *d, *e;
720 unsigned channel;
721 int32_t linear[PA_CHANNELS_MAX];
722
723 calc_linear_integer_volume(linear, volume);
724
725 e = (uint8_t*) ptr + c->length;
726
727 for (channel = 0, d = ptr; d < e; d++) {
728 int32_t t;
729
730 t = (int32_t) st_alaw2linear16(*d);
731 t = (t * linear[channel]) / 0x10000;
732 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
733 *d = (uint8_t) st_13linear2alaw(t >> 3);
734
735 if (PA_UNLIKELY(++channel >= spec->channels))
736 channel = 0;
737 }
738 break;
739 }
740
741 case PA_SAMPLE_FLOAT32NE: {
742 float *d;
743 int skip;
744 unsigned n;
745 unsigned channel;
746
747 d = ptr;
748 skip = spec->channels * sizeof(float);
749 n = c->length/sizeof(float)/spec->channels;
750
751 for (channel = 0; channel < spec->channels; channel ++) {
752 float v, *t;
753
754 if (PA_UNLIKELY(volume->values[channel] == PA_VOLUME_NORM))
755 continue;
756
757 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
758 t = d + channel;
759 oil_scalarmult_f32(t, skip, t, skip, &v, n);
760 }
761 break;
762 }
763
764 case PA_SAMPLE_FLOAT32RE: {
765 float *d, *e;
766 unsigned channel;
767 float linear[PA_CHANNELS_MAX];
768
769 calc_linear_float_volume(linear, volume);
770
771 e = (float*) ptr + c->length/sizeof(float);
772
773 for (channel = 0, d = ptr; d < e; d++) {
774 float t;
775
776 t = PA_FLOAT32_SWAP(*d);
777 t *= linear[channel];
778 *d = PA_FLOAT32_SWAP(t);
779
780 if (PA_UNLIKELY(++channel >= spec->channels))
781 channel = 0;
782 }
783
784 break;
785 }
786
787
788 default:
789 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
790 /* If we cannot change the volume, we just don't do it */
791 }
792
793 pa_memblock_release(c->memblock);
794 }
795
796 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
797 size_t fs;
798
799 pa_assert(ss);
800
801 fs = pa_frame_size(ss);
802
803 return (l/fs) * fs;
804 }
805
806 int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
807 size_t fs;
808
809 pa_assert(ss);
810
811 fs = pa_frame_size(ss);
812
813 return l % fs == 0;
814 }
815
816 void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
817 unsigned c;
818 size_t fs;
819
820 pa_assert(src);
821 pa_assert(channels > 0);
822 pa_assert(dst);
823 pa_assert(ss > 0);
824 pa_assert(n > 0);
825
826 fs = ss * channels;
827
828 for (c = 0; c < channels; c++) {
829 unsigned j;
830 void *d;
831 const void *s;
832
833 s = src[c];
834 d = (uint8_t*) dst + c * ss;
835
836 for (j = 0; j < n; j ++) {
837 oil_memcpy(d, s, ss);
838 s = (uint8_t*) s + ss;
839 d = (uint8_t*) d + fs;
840 }
841 }
842 }
843
844 void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
845 size_t fs;
846 unsigned c;
847
848 pa_assert(src);
849 pa_assert(dst);
850 pa_assert(channels > 0);
851 pa_assert(ss > 0);
852 pa_assert(n > 0);
853
854 fs = ss * channels;
855
856 for (c = 0; c < channels; c++) {
857 unsigned j;
858 const void *s;
859 void *d;
860
861 s = (uint8_t*) src + c * ss;
862 d = dst[c];
863
864 for (j = 0; j < n; j ++) {
865 oil_memcpy(d, s, ss);
866 s = (uint8_t*) s + fs;
867 d = (uint8_t*) d + ss;
868 }
869 }
870 }
871
872 static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
873 pa_memblock *b;
874 size_t length;
875 void *data;
876
877 pa_assert(pool);
878
879 length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);
880
881 b = pa_memblock_new(pool, length);
882
883 data = pa_memblock_acquire(b);
884 memset(data, c, length);
885 pa_memblock_release(b);
886
887 pa_memblock_set_is_silence(b, TRUE);
888
889 return b;
890 }
891
892 void pa_silence_cache_init(pa_silence_cache *cache) {
893 pa_assert(cache);
894
895 memset(cache, 0, sizeof(pa_silence_cache));
896 }
897
898 void pa_silence_cache_done(pa_silence_cache *cache) {
899 pa_sample_format_t f;
900 pa_assert(cache);
901
902 for (f = 0; f < PA_SAMPLE_MAX; f++)
903 if (cache->blocks[f])
904 pa_memblock_unref(cache->blocks[f]);
905
906 memset(cache, 0, sizeof(pa_silence_cache));
907 }
908
909 pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length) {
910 pa_memblock *b;
911 size_t l;
912
913 pa_assert(cache);
914 pa_assert(pa_sample_spec_valid(spec));
915
916 if (!(b = cache->blocks[spec->format]))
917
918 switch (spec->format) {
919 case PA_SAMPLE_U8:
920 cache->blocks[PA_SAMPLE_U8] = b = silence_memblock_new(pool, 0x80);
921 break;
922 case PA_SAMPLE_S16LE:
923 case PA_SAMPLE_S16BE:
924 case PA_SAMPLE_S32LE:
925 case PA_SAMPLE_S32BE:
926 case PA_SAMPLE_FLOAT32LE:
927 case PA_SAMPLE_FLOAT32BE:
928 cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
929 cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
930 cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
931 cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
932 cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
933 cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
934 break;
935 case PA_SAMPLE_ALAW:
936 cache->blocks[PA_SAMPLE_ALAW] = b = silence_memblock_new(pool, 0xd5);
937 break;
938 case PA_SAMPLE_ULAW:
939 cache->blocks[PA_SAMPLE_ULAW] = b = silence_memblock_new(pool, 0xff);
940 break;
941 default:
942 pa_assert_not_reached();
943 }
944
945 pa_assert(b);
946
947 ret->memblock = pa_memblock_ref(b);
948
949 l = pa_memblock_get_length(b);
950 if (length > l || length == 0)
951 length = l;
952
953 ret->length = pa_frame_align(length, spec);
954 ret->index = 0;
955
956 return ret;
957 }
958
959 void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n) {
960 const float *s;
961 float *d;
962
963 s = src; d = dst;
964
965 if (format == PA_SAMPLE_FLOAT32NE) {
966
967 float minus_one = -1.0, plus_one = 1.0;
968 oil_clip_f32(d, dstr, s, sstr, n, &minus_one, &plus_one);
969
970 } else {
971 pa_assert(format == PA_SAMPLE_FLOAT32RE);
972
973 for (; n > 0; n--) {
974 float f;
975
976 f = PA_FLOAT32_SWAP(*s);
977 f = PA_CLAMP_UNLIKELY(f, -1.0, 1.0);
978 *d = PA_FLOAT32_SWAP(f);
979
980 s = (const float*) ((const uint8_t*) s + sstr);
981 d = (float*) ((uint8_t*) d + dstr);
982 }
983 }
984 }