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