build-sys: Use ax_check_flag macros from autoconf archive
[pulseaudio-mirror.git] / src / pulsecore / sample-util.c
blob8a13495cbb883c9abaea09923e5be581f2726504
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <math.h>
34 #include <pulse/timeval.h>
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>
43 #include "sample-util.h"
45 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
47 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
48 void *data;
50 pa_assert(b);
51 pa_assert(spec);
53 data = pa_memblock_acquire(b);
54 pa_silence_memory(data, pa_memblock_get_length(b), spec);
55 pa_memblock_release(b);
57 return b;
60 pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
61 void *data;
63 pa_assert(c);
64 pa_assert(c->memblock);
65 pa_assert(spec);
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);
71 return c;
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();
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);
103 memset(p, silence_byte(spec->format), length);
104 return p;
107 #define VOLUME_PADDING 32
109 static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
110 unsigned channel, nchannels, padding;
112 pa_assert(linear);
113 pa_assert(volume);
115 nchannels = volume->channels;
117 for (channel = 0; channel < nchannels; channel++)
118 linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
120 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
121 linear[channel] = linear[padding];
124 static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
125 unsigned channel, nchannels, padding;
127 pa_assert(linear);
128 pa_assert(volume);
130 nchannels = volume->channels;
132 for (channel = 0; channel < nchannels; channel++)
133 linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]);
135 for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
136 linear[channel] = linear[padding];
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];
143 pa_assert(streams);
144 pa_assert(spec);
145 pa_assert(volume);
147 calc_linear_float_volume(linear, volume);
149 for (k = 0; k < nstreams; k++) {
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);
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];
162 pa_assert(streams);
163 pa_assert(spec);
164 pa_assert(volume);
166 calc_linear_float_volume(linear, volume);
168 for (k = 0; k < nstreams; k++) {
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]);
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) {
186 pa_cvolume full_volume;
187 unsigned k;
188 unsigned z;
189 void *end;
191 pa_assert(streams);
192 pa_assert(data);
193 pa_assert(length);
194 pa_assert(spec);
196 if (!volume)
197 volume = pa_cvolume_reset(&full_volume, spec->channels);
199 if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
200 pa_silence_memory(data, length, spec);
201 return length;
204 for (k = 0; k < nstreams; k++)
205 streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
207 for (z = 0; z < nstreams; z++)
208 if (length > streams[z].chunk.length)
209 length = streams[z].chunk.length;
211 end = (uint8_t*) data + length;
213 switch (spec->format) {
215 case PA_SAMPLE_S16NE:{
216 unsigned channel = 0;
218 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
220 while (data < end) {
221 int32_t sum = 0;
222 unsigned i;
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;
228 if (PA_UNLIKELY(cv <= 0))
229 continue;
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. */
237 hi = cv >> 16;
238 lo = cv & 0xFFFF;
240 v = *((int16_t*) m->ptr);
241 v = ((v * lo) >> 16) + (v * hi);
242 sum += v;
244 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
247 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
248 *((int16_t*) data) = (int16_t) sum;
250 data = (uint8_t*) data + sizeof(int16_t);
252 if (PA_UNLIKELY(++channel >= spec->channels))
253 channel = 0;
256 break;
259 case PA_SAMPLE_S16RE:{
260 unsigned channel = 0;
262 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
264 while (data < end) {
265 int32_t sum = 0;
266 unsigned i;
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;
272 if (PA_UNLIKELY(cv <= 0))
273 continue;
275 hi = cv >> 16;
276 lo = cv & 0xFFFF;
278 v = PA_INT16_SWAP(*((int16_t*) m->ptr));
279 v = ((v * lo) >> 16) + (v * hi);
280 sum += v;
282 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
285 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
286 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
288 data = (uint8_t*) data + sizeof(int16_t);
290 if (PA_UNLIKELY(++channel >= spec->channels))
291 channel = 0;
294 break;
297 case PA_SAMPLE_S32NE:{
298 unsigned channel = 0;
300 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
302 while (data < end) {
303 int64_t sum = 0;
304 unsigned i;
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;
311 if (PA_UNLIKELY(cv <= 0))
312 continue;
314 v = *((int32_t*) m->ptr);
315 v = (v * cv) >> 16;
316 sum += v;
318 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
321 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
322 *((int32_t*) data) = (int32_t) sum;
324 data = (uint8_t*) data + sizeof(int32_t);
326 if (PA_UNLIKELY(++channel >= spec->channels))
327 channel = 0;
330 break;
333 case PA_SAMPLE_S32RE:{
334 unsigned channel = 0;
336 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
338 while (data < end) {
339 int64_t sum = 0;
340 unsigned i;
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;
347 if (PA_UNLIKELY(cv <= 0))
348 continue;
350 v = PA_INT32_SWAP(*((int32_t*) m->ptr));
351 v = (v * cv) >> 16;
352 sum += v;
354 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
357 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
358 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
360 data = (uint8_t*) data + sizeof(int32_t);
362 if (PA_UNLIKELY(++channel >= spec->channels))
363 channel = 0;
366 break;
369 case PA_SAMPLE_S24NE: {
370 unsigned channel = 0;
372 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
374 while (data < end) {
375 int64_t sum = 0;
376 unsigned i;
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;
383 if (PA_UNLIKELY(cv <= 0))
384 continue;
386 v = (int32_t) (PA_READ24NE(m->ptr) << 8);
387 v = (v * cv) >> 16;
388 sum += v;
390 m->ptr = (uint8_t*) m->ptr + 3;
393 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
394 PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
396 data = (uint8_t*) data + 3;
398 if (PA_UNLIKELY(++channel >= spec->channels))
399 channel = 0;
402 break;
405 case PA_SAMPLE_S24RE: {
406 unsigned channel = 0;
408 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
410 while (data < end) {
411 int64_t sum = 0;
412 unsigned i;
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;
419 if (PA_UNLIKELY(cv <= 0))
420 continue;
422 v = (int32_t) (PA_READ24RE(m->ptr) << 8);
423 v = (v * cv) >> 16;
424 sum += v;
426 m->ptr = (uint8_t*) m->ptr + 3;
429 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
430 PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
432 data = (uint8_t*) data + 3;
434 if (PA_UNLIKELY(++channel >= spec->channels))
435 channel = 0;
438 break;
441 case PA_SAMPLE_S24_32NE: {
442 unsigned channel = 0;
444 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
446 while (data < end) {
447 int64_t sum = 0;
448 unsigned i;
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;
455 if (PA_UNLIKELY(cv <= 0))
456 continue;
458 v = (int32_t) (*((uint32_t*)m->ptr) << 8);
459 v = (v * cv) >> 16;
460 sum += v;
462 m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
465 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
466 *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
468 data = (uint8_t*) data + sizeof(uint32_t);
470 if (PA_UNLIKELY(++channel >= spec->channels))
471 channel = 0;
474 break;
477 case PA_SAMPLE_S24_32RE: {
478 unsigned channel = 0;
480 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
482 while (data < end) {
483 int64_t sum = 0;
484 unsigned i;
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;
491 if (PA_UNLIKELY(cv <= 0))
492 continue;
494 v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
495 v = (v * cv) >> 16;
496 sum += v;
498 m->ptr = (uint8_t*) m->ptr + 3;
501 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
502 *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
504 data = (uint8_t*) data + sizeof(uint32_t);
506 if (PA_UNLIKELY(++channel >= spec->channels))
507 channel = 0;
510 break;
513 case PA_SAMPLE_U8: {
514 unsigned channel = 0;
516 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
518 while (data < end) {
519 int32_t sum = 0;
520 unsigned i;
522 for (i = 0; i < nstreams; i++) {
523 pa_mix_info *m = streams + i;
524 int32_t v, cv = m->linear[channel].i;
526 if (PA_UNLIKELY(cv <= 0))
527 continue;
529 v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
530 v = (v * cv) >> 16;
531 sum += v;
533 m->ptr = (uint8_t*) m->ptr + 1;
536 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
537 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
539 data = (uint8_t*) data + 1;
541 if (PA_UNLIKELY(++channel >= spec->channels))
542 channel = 0;
545 break;
548 case PA_SAMPLE_ULAW: {
549 unsigned channel = 0;
551 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
553 while (data < end) {
554 int32_t sum = 0;
555 unsigned i;
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;
561 if (PA_UNLIKELY(cv <= 0))
562 continue;
564 hi = cv >> 16;
565 lo = cv & 0xFFFF;
567 v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
568 v = ((v * lo) >> 16) + (v * hi);
569 sum += v;
571 m->ptr = (uint8_t*) m->ptr + 1;
574 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
575 *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
577 data = (uint8_t*) data + 1;
579 if (PA_UNLIKELY(++channel >= spec->channels))
580 channel = 0;
583 break;
586 case PA_SAMPLE_ALAW: {
587 unsigned channel = 0;
589 calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
591 while (data < end) {
592 int32_t sum = 0;
593 unsigned i;
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;
599 if (PA_UNLIKELY(cv <= 0))
600 continue;
602 hi = cv >> 16;
603 lo = cv & 0xFFFF;
605 v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
606 v = ((v * lo) >> 16) + (v * hi);
607 sum += v;
609 m->ptr = (uint8_t*) m->ptr + 1;
612 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
613 *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
615 data = (uint8_t*) data + 1;
617 if (PA_UNLIKELY(++channel >= spec->channels))
618 channel = 0;
621 break;
624 case PA_SAMPLE_FLOAT32NE: {
625 unsigned channel = 0;
627 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
629 while (data < end) {
630 float sum = 0;
631 unsigned i;
633 for (i = 0; i < nstreams; i++) {
634 pa_mix_info *m = streams + i;
635 float v, cv = m->linear[channel].f;
637 if (PA_UNLIKELY(cv <= 0))
638 continue;
640 v = *((float*) m->ptr);
641 v *= cv;
642 sum += v;
644 m->ptr = (uint8_t*) m->ptr + sizeof(float);
647 *((float*) data) = sum;
649 data = (uint8_t*) data + sizeof(float);
651 if (PA_UNLIKELY(++channel >= spec->channels))
652 channel = 0;
655 break;
658 case PA_SAMPLE_FLOAT32RE: {
659 unsigned channel = 0;
661 calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
663 while (data < end) {
664 float sum = 0;
665 unsigned i;
667 for (i = 0; i < nstreams; i++) {
668 pa_mix_info *m = streams + i;
669 float v, cv = m->linear[channel].f;
671 if (PA_UNLIKELY(cv <= 0))
672 continue;
674 v = PA_FLOAT32_SWAP(*(float*) m->ptr);
675 v *= cv;
676 sum += v;
678 m->ptr = (uint8_t*) m->ptr + sizeof(float);
681 *((float*) data) = PA_FLOAT32_SWAP(sum);
683 data = (uint8_t*) data + sizeof(float);
685 if (PA_UNLIKELY(++channel >= spec->channels))
686 channel = 0;
689 break;
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();
697 for (k = 0; k < nstreams; k++)
698 pa_memblock_release(streams[k].chunk.memblock);
700 return length;
703 typedef union {
704 float f;
705 uint32_t i;
706 } volume_val;
708 typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
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
726 void pa_volume_memchunk(
727 pa_memchunk*c,
728 const pa_sample_spec *spec,
729 const pa_cvolume *volume) {
731 void *ptr;
732 volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
733 pa_do_volume_func_t do_volume;
735 pa_assert(c);
736 pa_assert(spec);
737 pa_assert(c->length % pa_frame_size(spec) == 0);
738 pa_assert(volume);
740 if (pa_memblock_is_silence(c->memblock))
741 return;
743 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
744 return;
746 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
747 pa_silence_memchunk(c, spec);
748 return;
751 if (spec->format < 0 || spec->format > PA_SAMPLE_MAX) {
752 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
753 return;
756 do_volume = pa_get_volume_func(spec->format);
757 pa_assert(do_volume);
759 calc_volume_table[spec->format] ((void *)linear, volume);
761 ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
763 do_volume (ptr, (void *)linear, spec->channels, c->length);
765 pa_memblock_release(c->memblock);
768 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
769 size_t fs;
771 pa_assert(ss);
773 fs = pa_frame_size(ss);
775 return (l/fs) * fs;
778 pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
779 size_t fs;
781 pa_assert(ss);
783 fs = pa_frame_size(ss);
785 return l % fs == 0;
788 void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
789 unsigned c;
790 size_t fs;
792 pa_assert(src);
793 pa_assert(channels > 0);
794 pa_assert(dst);
795 pa_assert(ss > 0);
796 pa_assert(n > 0);
798 fs = ss * channels;
800 for (c = 0; c < channels; c++) {
801 unsigned j;
802 void *d;
803 const void *s;
805 s = src[c];
806 d = (uint8_t*) dst + c * ss;
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;
816 void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
817 size_t fs;
818 unsigned c;
820 pa_assert(src);
821 pa_assert(dst);
822 pa_assert(channels > 0);
823 pa_assert(ss > 0);
824 pa_assert(n > 0);
826 fs = ss * channels;
828 for (c = 0; c < channels; c++) {
829 unsigned j;
830 const void *s;
831 void *d;
833 s = (uint8_t*) src + c * ss;
834 d = dst[c];
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;
844 static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
845 pa_memblock *b;
846 size_t length;
847 void *data;
849 pa_assert(pool);
851 length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);
853 b = pa_memblock_new(pool, length);
855 data = pa_memblock_acquire(b);
856 memset(data, c, length);
857 pa_memblock_release(b);
859 pa_memblock_set_is_silence(b, TRUE);
861 return b;
864 void pa_silence_cache_init(pa_silence_cache *cache) {
865 pa_assert(cache);
867 memset(cache, 0, sizeof(pa_silence_cache));
870 void pa_silence_cache_done(pa_silence_cache *cache) {
871 pa_sample_format_t f;
872 pa_assert(cache);
874 for (f = 0; f < PA_SAMPLE_MAX; f++)
875 if (cache->blocks[f])
876 pa_memblock_unref(cache->blocks[f]);
878 memset(cache, 0, sizeof(pa_silence_cache));
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;
885 pa_assert(cache);
886 pa_assert(pa_sample_spec_valid(spec));
888 if (!(b = cache->blocks[spec->format]))
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();
925 pa_assert(b);
927 ret->memblock = pa_memblock_ref(b);
929 l = pa_memblock_get_length(b);
930 if (length > l || length == 0)
931 length = l;
933 ret->length = pa_frame_align(length, spec);
934 ret->index = 0;
936 return ret;
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;
943 s = src; d = dst;
945 if (format == PA_SAMPLE_FLOAT32NE) {
946 for (; n > 0; n--) {
947 float f;
949 f = *s;
950 *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
952 s = (const float*) ((const uint8_t*) s + sstr);
953 d = (float*) ((uint8_t*) d + dstr);
955 } else {
956 pa_assert(format == PA_SAMPLE_FLOAT32RE);
958 for (; n > 0; n--) {
959 float f;
961 f = PA_FLOAT32_SWAP(*s);
962 f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
963 *d = PA_FLOAT32_SWAP(f);
965 s = (const float*) ((const uint8_t*) s + sstr);
966 d = (float*) ((uint8_t*) d + dstr);
971 /* Similar to pa_bytes_to_usec() but rounds up, not down */
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;
977 pa_assert(spec);
979 fs = pa_frame_size(spec);
980 length = (length + fs - 1) / fs;
982 usec = (pa_usec_t) length * PA_USEC_PER_SEC;
984 return (usec + spec->rate - 1) / spec->rate;
987 /* Similar to pa_usec_to_bytes() but rounds up, not down */
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);
993 u = (uint64_t) t * (uint64_t) spec->rate;
995 u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC;
997 u *= pa_frame_size(spec);
999 return (size_t) u;
1002 void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
1003 FILE *f;
1004 void *p;
1006 pa_assert(c);
1007 pa_assert(fn);
1009 /* Only for debugging purposes */
1011 f = pa_fopen_cloexec(fn, "a");
1013 if (!f) {
1014 pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
1015 return;
1018 p = pa_memblock_acquire(c->memblock);
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));
1023 pa_memblock_release(c->memblock);
1025 fclose(f);
1028 static void calc_sine(float *f, size_t l, double freq) {
1029 size_t i;
1031 l /= sizeof(float);
1033 for (i = 0; i < l; i++)
1034 *(f++) = (float) 0.5f * sin((double) i*M_PI*2*freq / (double) l);
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;
1042 pa_memchunk_reset(c);
1044 gcd = pa_gcd(rate, freq);
1045 n = rate / gcd;
1047 l = pa_mempool_block_size_max(pool) / sizeof(float);
1049 l /= n;
1050 if (l <= 0) l = 1;
1051 l *= n;
1053 c->length = l * sizeof(float);
1054 c->memblock = pa_memblock_new(pool, c->length);
1056 p = pa_memblock_acquire(c->memblock);
1057 calc_sine(p, c->length, freq * l / rate);
1058 pa_memblock_release(c->memblock);
1061 size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) {
1062 pa_usec_t usec;
1064 pa_assert(from);
1065 pa_assert(to);
1067 usec = pa_bytes_to_usec_round_up(size, from);
1068 return pa_usec_to_bytes_round_up(usec, to);