]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
sample-util: Fix off-by-one in error check
[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.1 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 #include <stdio.h>
31 #include <errno.h>
32 #include <math.h>
33
34 #include <pulse/timeval.h>
35
36 #include <pulsecore/log.h>
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/g711.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/endianmacros.h>
42
43 #include "sample-util.h"
44
45 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
46
47 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
48 void *data;
49
50 pa_assert(b);
51 pa_assert(spec);
52
53 data = pa_memblock_acquire(b);
54 pa_silence_memory(data, pa_memblock_get_length(b), spec);
55 pa_memblock_release(b);
56
57 return b;
58 }
59
60 pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
61 void *data;
62
63 pa_assert(c);
64 pa_assert(c->memblock);
65 pa_assert(spec);
66
67 data = pa_memblock_acquire(c->memblock);
68 pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
69 pa_memblock_release(c->memblock);
70
71 return c;
72 }
73
74 static uint8_t silence_byte(pa_sample_format_t format) {
75 switch (format) {
76 case PA_SAMPLE_U8:
77 return 0x80;
78 case PA_SAMPLE_S16LE:
79 case PA_SAMPLE_S16BE:
80 case PA_SAMPLE_S32LE:
81 case PA_SAMPLE_S32BE:
82 case PA_SAMPLE_FLOAT32LE:
83 case PA_SAMPLE_FLOAT32BE:
84 case PA_SAMPLE_S24LE:
85 case PA_SAMPLE_S24BE:
86 case PA_SAMPLE_S24_32LE:
87 case PA_SAMPLE_S24_32BE:
88 return 0;
89 case PA_SAMPLE_ALAW:
90 return 0xd5;
91 case PA_SAMPLE_ULAW:
92 return 0xff;
93 default:
94 pa_assert_not_reached();
95 }
96 }
97
98 void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
99 pa_assert(p);
100 pa_assert(length > 0);
101 pa_assert(spec);
102
103 memset(p, silence_byte(spec->format), length);
104 return p;
105 }
106
107 #define VOLUME_PADDING 32
108
109 static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
110 unsigned channel, nchannels, padding;
111
112 pa_assert(linear);
113 pa_assert(volume);
114
115 nchannels = volume->channels;
116
117 for (channel = 0; channel < nchannels; channel++)
118 linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
119
120 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
121 linear[channel] = linear[padding];
122 }
123
124 static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
125 unsigned channel, nchannels, padding;
126
127 pa_assert(linear);
128 pa_assert(volume);
129
130 nchannels = volume->channels;
131
132 for (channel = 0; channel < nchannels; channel++)
133 linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]);
134
135 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
136 linear[channel] = linear[padding];
137 }
138
139 static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
140 unsigned k, channel;
141 float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
142
143 pa_assert(streams);
144 pa_assert(spec);
145 pa_assert(volume);
146
147 calc_linear_float_volume(linear, volume);
148
149 for (k = 0; k < nstreams; k++) {
150
151 for (channel = 0; channel < spec->channels; channel++) {
152 pa_mix_info *m = streams + k;
153 m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000);
154 }
155 }
156 }
157
158 static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
159 unsigned k, channel;
160 float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
161
162 pa_assert(streams);
163 pa_assert(spec);
164 pa_assert(volume);
165
166 calc_linear_float_volume(linear, volume);
167
168 for (k = 0; k < nstreams; k++) {
169
170 for (channel = 0; channel < spec->channels; channel++) {
171 pa_mix_info *m = streams + k;
172 m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]);
173 }
174 }
175 }
176
177 size_t pa_mix(
178 pa_mix_info streams[],
179 unsigned nstreams,
180 void *data,
181 size_t length,
182 const pa_sample_spec *spec,
183 const pa_cvolume *volume,
184 pa_bool_t mute) {
185
186 pa_cvolume full_volume;
187 unsigned k;
188 unsigned z;
189 void *end;
190
191 pa_assert(streams);
192 pa_assert(data);
193 pa_assert(length);
194 pa_assert(spec);
195
196 if (!volume)
197 volume = pa_cvolume_reset(&full_volume, spec->channels);
198
199 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
200 pa_silence_memory(data, length, spec);
201 return length;
202 }
203
204 for (k = 0; k < nstreams; k++)
205 streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
206
207 for (z = 0; z < nstreams; z++)
208 if (length > streams[z].chunk.length)
209 length = streams[z].chunk.length;
210
211 end = (uint8_t*) data + length;
212
213 switch (spec->format) {
214
215 case PA_SAMPLE_S16NE:{
216 unsigned channel = 0;
217
218 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
219
220 while (data < end) {
221 int32_t sum = 0;
222 unsigned i;
223
224 for (i = 0; i < nstreams; i++) {
225 pa_mix_info *m = streams + i;
226 int32_t v, lo, hi, cv = m->linear[channel].i;
227
228 if (PA_UNLIKELY(cv <= 0))
229 continue;
230
231 /* Multiplying the 32bit volume factor with the
232 * 16bit sample might result in an 48bit value. We
233 * want to do without 64 bit integers and hence do
234 * the multiplication independantly for the HI and
235 * LO part of the volume. */
236
237 hi = cv >> 16;
238 lo = cv & 0xFFFF;
239
240 v = *((int16_t*) m->ptr);
241 v = ((v * lo) >> 16) + (v * hi);
242 sum += v;
243
244 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
245 }
246
247 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
248 *((int16_t*) data) = (int16_t) sum;
249
250 data = (uint8_t*) data + sizeof(int16_t);
251
252 if (PA_UNLIKELY(++channel >= spec->channels))
253 channel = 0;
254 }
255
256 break;
257 }
258
259 case PA_SAMPLE_S16RE:{
260 unsigned channel = 0;
261
262 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
263
264 while (data < end) {
265 int32_t sum = 0;
266 unsigned i;
267
268 for (i = 0; i < nstreams; i++) {
269 pa_mix_info *m = streams + i;
270 int32_t v, lo, hi, cv = m->linear[channel].i;
271
272 if (PA_UNLIKELY(cv <= 0))
273 continue;
274
275 hi = cv >> 16;
276 lo = cv & 0xFFFF;
277
278 v = PA_INT16_SWAP(*((int16_t*) m->ptr));
279 v = ((v * lo) >> 16) + (v * hi);
280 sum += v;
281
282 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
283 }
284
285 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
286 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
287
288 data = (uint8_t*) data + sizeof(int16_t);
289
290 if (PA_UNLIKELY(++channel >= spec->channels))
291 channel = 0;
292 }
293
294 break;
295 }
296
297 case PA_SAMPLE_S32NE:{
298 unsigned channel = 0;
299
300 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
301
302 while (data < end) {
303 int64_t sum = 0;
304 unsigned i;
305
306 for (i = 0; i < nstreams; i++) {
307 pa_mix_info *m = streams + i;
308 int32_t cv = m->linear[channel].i;
309 int64_t v;
310
311 if (PA_UNLIKELY(cv <= 0))
312 continue;
313
314 v = *((int32_t*) m->ptr);
315 v = (v * cv) >> 16;
316 sum += v;
317
318 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
319 }
320
321 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
322 *((int32_t*) data) = (int32_t) sum;
323
324 data = (uint8_t*) data + sizeof(int32_t);
325
326 if (PA_UNLIKELY(++channel >= spec->channels))
327 channel = 0;
328 }
329
330 break;
331 }
332
333 case PA_SAMPLE_S32RE:{
334 unsigned channel = 0;
335
336 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
337
338 while (data < end) {
339 int64_t sum = 0;
340 unsigned i;
341
342 for (i = 0; i < nstreams; i++) {
343 pa_mix_info *m = streams + i;
344 int32_t cv = m->linear[channel].i;
345 int64_t v;
346
347 if (PA_UNLIKELY(cv <= 0))
348 continue;
349
350 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
351 v = (v * cv) >> 16;
352 sum += v;
353
354 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
355 }
356
357 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
358 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
359
360 data = (uint8_t*) data + sizeof(int32_t);
361
362 if (PA_UNLIKELY(++channel >= spec->channels))
363 channel = 0;
364 }
365
366 break;
367 }
368
369 case PA_SAMPLE_S24NE: {
370 unsigned channel = 0;
371
372 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
373
374 while (data < end) {
375 int64_t sum = 0;
376 unsigned i;
377
378 for (i = 0; i < nstreams; i++) {
379 pa_mix_info *m = streams + i;
380 int32_t cv = m->linear[channel].i;
381 int64_t v;
382
383 if (PA_UNLIKELY(cv <= 0))
384 continue;
385
386 v = (int32_t) (PA_READ24NE(m->ptr) << 8);
387 v = (v * cv) >> 16;
388 sum += v;
389
390 m->ptr = (uint8_t*) m->ptr + 3;
391 }
392
393 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
394 PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
395
396 data = (uint8_t*) data + 3;
397
398 if (PA_UNLIKELY(++channel >= spec->channels))
399 channel = 0;
400 }
401
402 break;
403 }
404
405 case PA_SAMPLE_S24RE: {
406 unsigned channel = 0;
407
408 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
409
410 while (data < end) {
411 int64_t sum = 0;
412 unsigned i;
413
414 for (i = 0; i < nstreams; i++) {
415 pa_mix_info *m = streams + i;
416 int32_t cv = m->linear[channel].i;
417 int64_t v;
418
419 if (PA_UNLIKELY(cv <= 0))
420 continue;
421
422 v = (int32_t) (PA_READ24RE(m->ptr) << 8);
423 v = (v * cv) >> 16;
424 sum += v;
425
426 m->ptr = (uint8_t*) m->ptr + 3;
427 }
428
429 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
430 PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
431
432 data = (uint8_t*) data + 3;
433
434 if (PA_UNLIKELY(++channel >= spec->channels))
435 channel = 0;
436 }
437
438 break;
439 }
440
441 case PA_SAMPLE_S24_32NE: {
442 unsigned channel = 0;
443
444 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
445
446 while (data < end) {
447 int64_t sum = 0;
448 unsigned i;
449
450 for (i = 0; i < nstreams; i++) {
451 pa_mix_info *m = streams + i;
452 int32_t cv = m->linear[channel].i;
453 int64_t v;
454
455 if (PA_UNLIKELY(cv <= 0))
456 continue;
457
458 v = (int32_t) (*((uint32_t*)m->ptr) << 8);
459 v = (v * cv) >> 16;
460 sum += v;
461
462 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
463 }
464
465 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
466 *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
467
468 data = (uint8_t*) data + sizeof(uint32_t);
469
470 if (PA_UNLIKELY(++channel >= spec->channels))
471 channel = 0;
472 }
473
474 break;
475 }
476
477 case PA_SAMPLE_S24_32RE: {
478 unsigned channel = 0;
479
480 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
481
482 while (data < end) {
483 int64_t sum = 0;
484 unsigned i;
485
486 for (i = 0; i < nstreams; i++) {
487 pa_mix_info *m = streams + i;
488 int32_t cv = m->linear[channel].i;
489 int64_t v;
490
491 if (PA_UNLIKELY(cv <= 0))
492 continue;
493
494 v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
495 v = (v * cv) >> 16;
496 sum += v;
497
498 m->ptr = (uint8_t*) m->ptr + 3;
499 }
500
501 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
502 *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
503
504 data = (uint8_t*) data + sizeof(uint32_t);
505
506 if (PA_UNLIKELY(++channel >= spec->channels))
507 channel = 0;
508 }
509
510 break;
511 }
512
513 case PA_SAMPLE_U8: {
514 unsigned channel = 0;
515
516 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
517
518 while (data < end) {
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 v, cv = m->linear[channel].i;
525
526 if (PA_UNLIKELY(cv <= 0))
527 continue;
528
529 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
530 v = (v * cv) >> 16;
531 sum += v;
532
533 m->ptr = (uint8_t*) m->ptr + 1;
534 }
535
536 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
537 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
538
539 data = (uint8_t*) data + 1;
540
541 if (PA_UNLIKELY(++channel >= spec->channels))
542 channel = 0;
543 }
544
545 break;
546 }
547
548 case PA_SAMPLE_ULAW: {
549 unsigned channel = 0;
550
551 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
552
553 while (data < end) {
554 int32_t sum = 0;
555 unsigned i;
556
557 for (i = 0; i < nstreams; i++) {
558 pa_mix_info *m = streams + i;
559 int32_t v, hi, lo, cv = m->linear[channel].i;
560
561 if (PA_UNLIKELY(cv <= 0))
562 continue;
563
564 hi = cv >> 16;
565 lo = cv & 0xFFFF;
566
567 v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
568 v = ((v * lo) >> 16) + (v * hi);
569 sum += v;
570
571 m->ptr = (uint8_t*) m->ptr + 1;
572 }
573
574 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
575 *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
576
577 data = (uint8_t*) data + 1;
578
579 if (PA_UNLIKELY(++channel >= spec->channels))
580 channel = 0;
581 }
582
583 break;
584 }
585
586 case PA_SAMPLE_ALAW: {
587 unsigned channel = 0;
588
589 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
590
591 while (data < end) {
592 int32_t sum = 0;
593 unsigned i;
594
595 for (i = 0; i < nstreams; i++) {
596 pa_mix_info *m = streams + i;
597 int32_t v, hi, lo, cv = m->linear[channel].i;
598
599 if (PA_UNLIKELY(cv <= 0))
600 continue;
601
602 hi = cv >> 16;
603 lo = cv & 0xFFFF;
604
605 v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
606 v = ((v * lo) >> 16) + (v * hi);
607 sum += v;
608
609 m->ptr = (uint8_t*) m->ptr + 1;
610 }
611
612 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
613 *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
614
615 data = (uint8_t*) data + 1;
616
617 if (PA_UNLIKELY(++channel >= spec->channels))
618 channel = 0;
619 }
620
621 break;
622 }
623
624 case PA_SAMPLE_FLOAT32NE: {
625 unsigned channel = 0;
626
627 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
628
629 while (data < end) {
630 float sum = 0;
631 unsigned i;
632
633 for (i = 0; i < nstreams; i++) {
634 pa_mix_info *m = streams + i;
635 float v, cv = m->linear[channel].f;
636
637 if (PA_UNLIKELY(cv <= 0))
638 continue;
639
640 v = *((float*) m->ptr);
641 v *= cv;
642 sum += v;
643
644 m->ptr = (uint8_t*) m->ptr + sizeof(float);
645 }
646
647 *((float*) data) = sum;
648
649 data = (uint8_t*) data + sizeof(float);
650
651 if (PA_UNLIKELY(++channel >= spec->channels))
652 channel = 0;
653 }
654
655 break;
656 }
657
658 case PA_SAMPLE_FLOAT32RE: {
659 unsigned channel = 0;
660
661 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
662
663 while (data < end) {
664 float sum = 0;
665 unsigned i;
666
667 for (i = 0; i < nstreams; i++) {
668 pa_mix_info *m = streams + i;
669 float v, cv = m->linear[channel].f;
670
671 if (PA_UNLIKELY(cv <= 0))
672 continue;
673
674 v = PA_FLOAT32_SWAP(*(float*) m->ptr);
675 v *= cv;
676 sum += v;
677
678 m->ptr = (uint8_t*) m->ptr + sizeof(float);
679 }
680
681 *((float*) data) = PA_FLOAT32_SWAP(sum);
682
683 data = (uint8_t*) data + sizeof(float);
684
685 if (PA_UNLIKELY(++channel >= spec->channels))
686 channel = 0;
687 }
688
689 break;
690 }
691
692 default:
693 pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
694 pa_assert_not_reached();
695 }
696
697 for (k = 0; k < nstreams; k++)
698 pa_memblock_release(streams[k].chunk.memblock);
699
700 return length;
701 }
702
703 typedef union {
704 float f;
705 uint32_t i;
706 } volume_val;
707
708 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
709
710 static const pa_calc_volume_func_t calc_volume_table[] = {
711 [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume,
712 [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
713 [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume,
714 [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
715 [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
716 [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
717 [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
718 [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
719 [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
720 [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
721 [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
722 [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume,
723 [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume
724 };
725
726 void pa_volume_memchunk(
727 pa_memchunk*c,
728 const pa_sample_spec *spec,
729 const pa_cvolume *volume) {
730
731 void *ptr;
732 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
733 pa_do_volume_func_t do_volume;
734
735 pa_assert(c);
736 pa_assert(spec);
737 pa_assert(pa_frame_aligned(c->length, spec));
738 pa_assert(volume);
739
740 if (pa_memblock_is_silence(c->memblock))
741 return;
742
743 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
744 return;
745
746 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
747 pa_silence_memchunk(c, spec);
748 return;
749 }
750
751 if (spec->format < 0 || spec->format >= PA_SAMPLE_MAX) {
752 pa_log_warn("Unable to change volume of format");
753 return;
754 }
755
756 do_volume = pa_get_volume_func(spec->format);
757 pa_assert(do_volume);
758
759 calc_volume_table[spec->format] ((void *)linear, volume);
760
761 ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
762
763 do_volume (ptr, (void *)linear, spec->channels, c->length);
764
765 pa_memblock_release(c->memblock);
766 }
767
768 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
769 size_t fs;
770
771 pa_assert(ss);
772
773 fs = pa_frame_size(ss);
774
775 return (l/fs) * fs;
776 }
777
778 pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
779 size_t fs;
780
781 pa_assert(ss);
782
783 fs = pa_frame_size(ss);
784
785 return l % fs == 0;
786 }
787
788 void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
789 unsigned c;
790 size_t fs;
791
792 pa_assert(src);
793 pa_assert(channels > 0);
794 pa_assert(dst);
795 pa_assert(ss > 0);
796 pa_assert(n > 0);
797
798 fs = ss * channels;
799
800 for (c = 0; c < channels; c++) {
801 unsigned j;
802 void *d;
803 const void *s;
804
805 s = src[c];
806 d = (uint8_t*) dst + c * ss;
807
808 for (j = 0; j < n; j ++) {
809 memcpy(d, s, (int) ss);
810 s = (uint8_t*) s + ss;
811 d = (uint8_t*) d + fs;
812 }
813 }
814 }
815
816 void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
817 size_t fs;
818 unsigned c;
819
820 pa_assert(src);
821 pa_assert(dst);
822 pa_assert(channels > 0);
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 const void *s;
831 void *d;
832
833 s = (uint8_t*) src + c * ss;
834 d = dst[c];
835
836 for (j = 0; j < n; j ++) {
837 memcpy(d, s, (int) ss);
838 s = (uint8_t*) s + fs;
839 d = (uint8_t*) d + ss;
840 }
841 }
842 }
843
844 static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
845 pa_memblock *b;
846 size_t length;
847 void *data;
848
849 pa_assert(pool);
850
851 length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);
852
853 b = pa_memblock_new(pool, length);
854
855 data = pa_memblock_acquire(b);
856 memset(data, c, length);
857 pa_memblock_release(b);
858
859 pa_memblock_set_is_silence(b, TRUE);
860
861 return b;
862 }
863
864 void pa_silence_cache_init(pa_silence_cache *cache) {
865 pa_assert(cache);
866
867 memset(cache, 0, sizeof(pa_silence_cache));
868 }
869
870 void pa_silence_cache_done(pa_silence_cache *cache) {
871 pa_sample_format_t f;
872 pa_assert(cache);
873
874 for (f = 0; f < PA_SAMPLE_MAX; f++)
875 if (cache->blocks[f])
876 pa_memblock_unref(cache->blocks[f]);
877
878 memset(cache, 0, sizeof(pa_silence_cache));
879 }
880
881 pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length) {
882 pa_memblock *b;
883 size_t l;
884
885 pa_assert(cache);
886 pa_assert(pa_sample_spec_valid(spec));
887
888 if (!(b = cache->blocks[spec->format]))
889
890 switch (spec->format) {
891 case PA_SAMPLE_U8:
892 cache->blocks[PA_SAMPLE_U8] = b = silence_memblock_new(pool, 0x80);
893 break;
894 case PA_SAMPLE_S16LE:
895 case PA_SAMPLE_S16BE:
896 case PA_SAMPLE_S32LE:
897 case PA_SAMPLE_S32BE:
898 case PA_SAMPLE_S24LE:
899 case PA_SAMPLE_S24BE:
900 case PA_SAMPLE_S24_32LE:
901 case PA_SAMPLE_S24_32BE:
902 case PA_SAMPLE_FLOAT32LE:
903 case PA_SAMPLE_FLOAT32BE:
904 cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
905 cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
906 cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
907 cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
908 cache->blocks[PA_SAMPLE_S24LE] = pa_memblock_ref(b);
909 cache->blocks[PA_SAMPLE_S24BE] = pa_memblock_ref(b);
910 cache->blocks[PA_SAMPLE_S24_32LE] = pa_memblock_ref(b);
911 cache->blocks[PA_SAMPLE_S24_32BE] = pa_memblock_ref(b);
912 cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
913 cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
914 break;
915 case PA_SAMPLE_ALAW:
916 cache->blocks[PA_SAMPLE_ALAW] = b = silence_memblock_new(pool, 0xd5);
917 break;
918 case PA_SAMPLE_ULAW:
919 cache->blocks[PA_SAMPLE_ULAW] = b = silence_memblock_new(pool, 0xff);
920 break;
921 default:
922 pa_assert_not_reached();
923 }
924
925 pa_assert(b);
926
927 ret->memblock = pa_memblock_ref(b);
928
929 l = pa_memblock_get_length(b);
930 if (length > l || length == 0)
931 length = l;
932
933 ret->length = pa_frame_align(length, spec);
934 ret->index = 0;
935
936 return ret;
937 }
938
939 void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n) {
940 const float *s;
941 float *d;
942
943 s = src; d = dst;
944
945 if (format == PA_SAMPLE_FLOAT32NE) {
946 for (; n > 0; n--) {
947 float f;
948
949 f = *s;
950 *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
951
952 s = (const float*) ((const uint8_t*) s + sstr);
953 d = (float*) ((uint8_t*) d + dstr);
954 }
955 } else {
956 pa_assert(format == PA_SAMPLE_FLOAT32RE);
957
958 for (; n > 0; n--) {
959 float f;
960
961 f = PA_FLOAT32_SWAP(*s);
962 f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
963 *d = PA_FLOAT32_SWAP(f);
964
965 s = (const float*) ((const uint8_t*) s + sstr);
966 d = (float*) ((uint8_t*) d + dstr);
967 }
968 }
969 }
970
971 /* Similar to pa_bytes_to_usec() but rounds up, not down */
972
973 pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec) {
974 size_t fs;
975 pa_usec_t usec;
976
977 pa_assert(spec);
978
979 fs = pa_frame_size(spec);
980 length = (length + fs - 1) / fs;
981
982 usec = (pa_usec_t) length * PA_USEC_PER_SEC;
983
984 return (usec + spec->rate - 1) / spec->rate;
985 }
986
987 /* Similar to pa_usec_to_bytes() but rounds up, not down */
988
989 size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec) {
990 uint64_t u;
991 pa_assert(spec);
992
993 u = (uint64_t) t * (uint64_t) spec->rate;
994
995 u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC;
996
997 u *= pa_frame_size(spec);
998
999 return (size_t) u;
1000 }
1001
1002 void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
1003 FILE *f;
1004 void *p;
1005
1006 pa_assert(c);
1007 pa_assert(fn);
1008
1009 /* Only for debugging purposes */
1010
1011 f = pa_fopen_cloexec(fn, "a");
1012
1013 if (!f) {
1014 pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
1015 return;
1016 }
1017
1018 p = pa_memblock_acquire(c->memblock);
1019
1020 if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length)
1021 pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno));
1022
1023 pa_memblock_release(c->memblock);
1024
1025 fclose(f);
1026 }
1027
1028 static void calc_sine(float *f, size_t l, double freq) {
1029 size_t i;
1030
1031 l /= sizeof(float);
1032
1033 for (i = 0; i < l; i++)
1034 *(f++) = (float) 0.5f * sin((double) i*M_PI*2*freq / (double) l);
1035 }
1036
1037 void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) {
1038 size_t l;
1039 unsigned gcd, n;
1040 void *p;
1041
1042 pa_memchunk_reset(c);
1043
1044 gcd = pa_gcd(rate, freq);
1045 n = rate / gcd;
1046
1047 l = pa_mempool_block_size_max(pool) / sizeof(float);
1048
1049 l /= n;
1050 if (l <= 0) l = 1;
1051 l *= n;
1052
1053 c->length = l * sizeof(float);
1054 c->memblock = pa_memblock_new(pool, c->length);
1055
1056 p = pa_memblock_acquire(c->memblock);
1057 calc_sine(p, c->length, freq * l / rate);
1058 pa_memblock_release(c->memblock);
1059 }
1060
1061 size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) {
1062 pa_usec_t usec;
1063
1064 pa_assert(from);
1065 pa_assert(to);
1066
1067 usec = pa_bytes_to_usec_round_up(size, from);
1068 return pa_usec_to_bytes_round_up(usec, to);
1069 }