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