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