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