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