Merge HUGE set of changes temporarily into a branch, to allow me to move them from...
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / sample-util.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2004-2006 Lennart Poettering
7   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9   PulseAudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU Lesser General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13
14   PulseAudio is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with PulseAudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <stdlib.h>
33
34 #include <liboil/liboilfuncs.h>
35
36 #include <pulsecore/log.h>
37
38 #include "sample-util.h"
39 #include "endianmacros.h"
40
41 #define PA_SILENCE_MAX (1024*1024*1)
42
43 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
44     size_t fs;
45     assert(pool);
46     assert(spec);
47
48     if (length == 0)
49         length = pa_bytes_per_second(spec)/20; /* 50 ms */
50
51     if (length > PA_SILENCE_MAX)
52         length = PA_SILENCE_MAX;
53
54     fs = pa_frame_size(spec);
55     length = ((PA_SILENCE_MAX+fs-1) / fs) * fs;
56
57     if (length <= 0)
58         length = fs;
59
60     return pa_silence_memblock(pa_memblock_new(pool, length), spec);
61 }
62
63 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
64     void *data;
65
66     assert(b);
67     assert(spec);
68
69     data = pa_memblock_acquire(b);
70     pa_silence_memory(data, pa_memblock_get_length(b), spec);
71     pa_memblock_release(b);
72     return b;
73 }
74
75 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
76     void *data;
77
78     assert(c);
79     assert(c->memblock);
80     assert(spec);
81
82     data = pa_memblock_acquire(c->memblock);
83     pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
84     pa_memblock_release(c->memblock);
85 }
86
87 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
88     uint8_t c = 0;
89     assert(p && length && spec);
90
91     switch (spec->format) {
92         case PA_SAMPLE_U8:
93             c = 0x80;
94             break;
95         case PA_SAMPLE_S16LE:
96         case PA_SAMPLE_S16BE:
97         case PA_SAMPLE_FLOAT32:
98         case PA_SAMPLE_FLOAT32RE:
99             c = 0;
100             break;
101         case PA_SAMPLE_ALAW:
102         case PA_SAMPLE_ULAW:
103             c = 80;
104             break;
105         default:
106             assert(0);
107     }
108
109     memset(p, c, length);
110 }
111
112 size_t pa_mix(
113         pa_mix_info streams[],
114         unsigned nstreams,
115         void *data,
116         size_t length,
117         const pa_sample_spec *spec,
118         const pa_cvolume *volume,
119         int mute) {
120
121     pa_cvolume full_volume;
122     size_t d = 0;
123     unsigned k;
124
125     assert(streams);
126     assert(data);
127     assert(length);
128     assert(spec);
129
130     if (!volume)
131         volume = pa_cvolume_reset(&full_volume, spec->channels);
132
133     for (k = 0; k < nstreams; k++)
134         streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
135
136     switch (spec->format) {
137         case PA_SAMPLE_S16NE:{
138             unsigned channel = 0;
139
140             for (d = 0;; d += sizeof(int16_t)) {
141                 int32_t sum = 0;
142
143                 if (d >= length)
144                     goto finish;
145
146                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
147                     unsigned i;
148
149                     for (i = 0; i < nstreams; i++) {
150                         int32_t v;
151                         pa_volume_t cvolume = streams[i].volume.values[channel];
152
153                         if (d >= streams[i].chunk.length)
154                             goto finish;
155
156                         if (cvolume == PA_VOLUME_MUTED)
157                             v = 0;
158                         else {
159                             v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
160
161                             if (cvolume != PA_VOLUME_NORM)
162                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
163                         }
164
165                         sum += v;
166                     }
167
168                     if (volume->values[channel] != PA_VOLUME_NORM)
169                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
170
171                     if (sum < -0x8000) sum = -0x8000;
172                     if (sum > 0x7FFF) sum = 0x7FFF;
173
174                 }
175
176                 *((int16_t*) data) = sum;
177                 data = (uint8_t*) data + sizeof(int16_t);
178
179                 if (++channel >= spec->channels)
180                     channel = 0;
181             }
182
183             break;
184         }
185
186         case PA_SAMPLE_S16RE:{
187             unsigned channel = 0;
188
189             for (d = 0;; d += sizeof(int16_t)) {
190                 int32_t sum = 0;
191
192                 if (d >= length)
193                     goto finish;
194
195                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
196                     unsigned i;
197
198                     for (i = 0; i < nstreams; i++) {
199                         int32_t v;
200                         pa_volume_t cvolume = streams[i].volume.values[channel];
201
202                         if (d >= streams[i].chunk.length)
203                             goto finish;
204
205                         if (cvolume == PA_VOLUME_MUTED)
206                             v = 0;
207                         else {
208                             v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
209
210                             if (cvolume != PA_VOLUME_NORM)
211                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
212                         }
213
214                         sum += v;
215                     }
216
217                     if (volume->values[channel] != PA_VOLUME_NORM)
218                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
219
220                     if (sum < -0x8000) sum = -0x8000;
221                     if (sum > 0x7FFF) sum = 0x7FFF;
222
223                 }
224
225                 *((int16_t*) data) = INT16_SWAP(sum);
226                 data = (uint8_t*) data + sizeof(int16_t);
227
228                 if (++channel >= spec->channels)
229                     channel = 0;
230             }
231
232             break;
233         }
234
235         case PA_SAMPLE_U8: {
236             unsigned channel = 0;
237
238             for (d = 0;; d ++) {
239                 int32_t sum = 0;
240
241                 if (d >= length)
242                     goto finish;
243
244                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
245                     unsigned i;
246
247                     for (i = 0; i < nstreams; i++) {
248                         int32_t v;
249                         pa_volume_t cvolume = streams[i].volume.values[channel];
250
251                         if (d >= streams[i].chunk.length)
252                             goto finish;
253
254                         if (cvolume == PA_VOLUME_MUTED)
255                             v = 0;
256                         else {
257                             v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
258
259                             if (cvolume != PA_VOLUME_NORM)
260                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
261                         }
262
263                         sum += v;
264                     }
265
266                     if (volume->values[channel] != PA_VOLUME_NORM)
267                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
268
269                     if (sum < -0x80) sum = -0x80;
270                     if (sum > 0x7F) sum = 0x7F;
271
272                 }
273
274                 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
275                 data = (uint8_t*) data + 1;
276
277                 if (++channel >= spec->channels)
278                     channel = 0;
279             }
280
281             break;
282         }
283
284         case PA_SAMPLE_FLOAT32NE: {
285             unsigned channel = 0;
286
287             for (d = 0;; d += sizeof(float)) {
288                 float sum = 0;
289
290                 if (d >= length)
291                     goto finish;
292
293                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
294                     unsigned i;
295
296                     for (i = 0; i < nstreams; i++) {
297                         float v;
298                         pa_volume_t cvolume = streams[i].volume.values[channel];
299
300                         if (d >= streams[i].chunk.length)
301                             goto finish;
302
303                         if (cvolume == PA_VOLUME_MUTED)
304                             v = 0;
305                         else {
306                             v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
307
308                             if (cvolume != PA_VOLUME_NORM)
309                                 v *= pa_sw_volume_to_linear(cvolume);
310                         }
311
312                         sum += v;
313                     }
314
315                     if (volume->values[channel] != PA_VOLUME_NORM)
316                         sum *= pa_sw_volume_to_linear(volume->values[channel]);
317                 }
318
319                 *((float*) data) = sum;
320                 data = (uint8_t*) data + sizeof(float);
321
322                 if (++channel >= spec->channels)
323                     channel = 0;
324             }
325
326             break;
327         }
328
329         default:
330             pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
331             abort();
332     }
333
334 finish:
335
336     for (k = 0; k < nstreams; k++)
337         pa_memblock_release(streams[k].chunk.memblock);
338
339     return d;
340 }
341
342
343 void pa_volume_memchunk(
344         pa_memchunk*c,
345         const pa_sample_spec *spec,
346         const pa_cvolume *volume) {
347
348     void *ptr;
349
350     assert(c);
351     assert(spec);
352     assert(c->length % pa_frame_size(spec) == 0);
353     assert(volume);
354
355     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
356         return;
357
358     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
359         pa_silence_memchunk(c, spec);
360         return;
361     }
362
363     ptr = pa_memblock_acquire(c->memblock);
364
365     switch (spec->format) {
366         case PA_SAMPLE_S16NE: {
367             int16_t *d;
368             size_t n;
369             unsigned channel;
370             double linear[PA_CHANNELS_MAX];
371
372             for (channel = 0; channel < spec->channels; channel++)
373                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
374
375             for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
376                 int32_t t = (int32_t)(*d);
377
378                 t = (int32_t) (t * linear[channel]);
379
380                 if (t < -0x8000) t = -0x8000;
381                 if (t > 0x7FFF) t = 0x7FFF;
382
383                 *d = (int16_t) t;
384
385                 if (++channel >= spec->channels)
386                     channel = 0;
387             }
388             break;
389         }
390
391         case PA_SAMPLE_S16RE: {
392             int16_t *d;
393             size_t n;
394             unsigned channel;
395             double linear[PA_CHANNELS_MAX];
396
397             for (channel = 0; channel < spec->channels; channel++)
398                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
399
400             for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
401                 int32_t t = (int32_t)(INT16_SWAP(*d));
402
403                 t = (int32_t) (t * linear[channel]);
404
405                 if (t < -0x8000) t = -0x8000;
406                 if (t > 0x7FFF) t = 0x7FFF;
407
408                 *d = INT16_SWAP((int16_t) t);
409
410                 if (++channel >= spec->channels)
411                     channel = 0;
412             }
413
414             break;
415         }
416
417         case PA_SAMPLE_U8: {
418             uint8_t *d;
419             size_t n;
420             unsigned channel = 0;
421
422             for (d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
423                 int32_t t = (int32_t) *d - 0x80;
424
425                 t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
426
427                 if (t < -0x80) t = -0x80;
428                 if (t > 0x7F) t = 0x7F;
429
430                 *d = (uint8_t) (t + 0x80);
431
432                 if (++channel >= spec->channels)
433                     channel = 0;
434             }
435             break;
436         }
437
438         case PA_SAMPLE_FLOAT32NE: {
439             float *d;
440             int skip;
441             unsigned n;
442             unsigned channel;
443
444             d = (float*) ((uint8_t*) ptr + c->index);
445             skip = spec->channels * sizeof(float);
446             n = c->length/sizeof(float)/spec->channels;
447
448             for (channel = 0; channel < spec->channels ; channel ++) {
449                 float v, *t;
450
451                 if (volume->values[channel] == PA_VOLUME_NORM)
452                     continue;
453
454                 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
455
456                 t = d + channel;
457                 oil_scalarmult_f32(t, skip, t, skip, &v, n);
458             }
459             break;
460         }
461
462         default:
463             pa_log_error("ERROR: Unable to change volume of format %s.",
464                 pa_sample_format_to_string(spec->format));
465             abort();
466     }
467
468     pa_memblock_release(c->memblock);
469 }
470