Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.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 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
42     assert(pool);
43     assert(spec);
44
45     if (length == 0)
46         length = pa_bytes_per_second(spec)/20; /* 50 ms */
47
48     return pa_silence_memblock(pa_memblock_new(pool, length), spec);
49 }
50
51 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
52     assert(b && b->data && spec);
53     pa_silence_memory(b->data, b->length, spec);
54     return b;
55 }
56
57 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
58     assert(c && c->memblock && c->memblock->data && spec && c->length);
59
60     pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec);
61 }
62
63 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
64     uint8_t c = 0;
65     assert(p && length && spec);
66
67     switch (spec->format) {
68         case PA_SAMPLE_U8:
69             c = 0x80;
70             break;
71         case PA_SAMPLE_S16LE:
72         case PA_SAMPLE_S16BE:
73         case PA_SAMPLE_FLOAT32:
74         case PA_SAMPLE_FLOAT32RE:
75             c = 0;
76             break;
77         case PA_SAMPLE_ALAW:
78         case PA_SAMPLE_ULAW:
79             c = 80;
80             break;
81         default:
82             assert(0);
83     }
84
85     memset(p, c, length);
86 }
87
88 size_t pa_mix(
89     const pa_mix_info streams[],
90     unsigned nstreams,
91     void *data,
92     size_t length,
93     const pa_sample_spec *spec,
94     const pa_cvolume *volume,
95     int mute) {
96
97     assert(streams && data && length && spec);
98
99     switch (spec->format) {
100         case PA_SAMPLE_S16NE:{
101             size_t d;
102             unsigned channel = 0;
103
104             for (d = 0;; d += sizeof(int16_t)) {
105                 int32_t sum = 0;
106
107                 if (d >= length)
108                     return d;
109
110                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
111                     unsigned i;
112
113                     for (i = 0; i < nstreams; i++) {
114                         int32_t v;
115                         pa_volume_t cvolume = streams[i].volume.values[channel];
116
117                         if (d >= streams[i].chunk.length)
118                             return d;
119
120                         if (cvolume == PA_VOLUME_MUTED)
121                             v = 0;
122                         else {
123                             v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
124
125                             if (cvolume != PA_VOLUME_NORM)
126                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
127                         }
128
129                         sum += v;
130                     }
131
132                     if (volume->values[channel] != PA_VOLUME_NORM)
133                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
134
135                     if (sum < -0x8000) sum = -0x8000;
136                     if (sum > 0x7FFF) sum = 0x7FFF;
137
138                 }
139
140                 *((int16_t*) data) = sum;
141                 data = (uint8_t*) data + sizeof(int16_t);
142
143                 if (++channel >= spec->channels)
144                     channel = 0;
145             }
146         }
147
148         case PA_SAMPLE_S16RE:{
149             size_t d;
150             unsigned channel = 0;
151
152             for (d = 0;; d += sizeof(int16_t)) {
153                 int32_t sum = 0;
154
155                 if (d >= length)
156                     return d;
157
158                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
159                     unsigned i;
160
161                     for (i = 0; i < nstreams; i++) {
162                         int32_t v;
163                         pa_volume_t cvolume = streams[i].volume.values[channel];
164
165                         if (d >= streams[i].chunk.length)
166                             return d;
167
168                         if (cvolume == PA_VOLUME_MUTED)
169                             v = 0;
170                         else {
171                             v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)));
172
173                             if (cvolume != PA_VOLUME_NORM)
174                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
175                         }
176
177                         sum += v;
178                     }
179
180                     if (volume->values[channel] != PA_VOLUME_NORM)
181                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
182
183                     if (sum < -0x8000) sum = -0x8000;
184                     if (sum > 0x7FFF) sum = 0x7FFF;
185
186                 }
187
188                 *((int16_t*) data) = INT16_SWAP(sum);
189                 data = (uint8_t*) data + sizeof(int16_t);
190
191                 if (++channel >= spec->channels)
192                     channel = 0;
193             }
194         }
195
196         case PA_SAMPLE_U8: {
197             size_t d;
198             unsigned channel = 0;
199
200             for (d = 0;; d ++) {
201                 int32_t sum = 0;
202
203                 if (d >= length)
204                     return d;
205
206                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
207                     unsigned i;
208
209                     for (i = 0; i < nstreams; i++) {
210                         int32_t v;
211                         pa_volume_t cvolume = streams[i].volume.values[channel];
212
213                         if (d >= streams[i].chunk.length)
214                             return d;
215
216                         if (cvolume == PA_VOLUME_MUTED)
217                             v = 0;
218                         else {
219                             v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80;
220
221                             if (cvolume != PA_VOLUME_NORM)
222                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
223                         }
224
225                         sum += v;
226                     }
227
228                     if (volume->values[channel] != PA_VOLUME_NORM)
229                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
230
231                     if (sum < -0x80) sum = -0x80;
232                     if (sum > 0x7F) sum = 0x7F;
233
234                 }
235
236                 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
237                 data = (uint8_t*) data + 1;
238
239                 if (++channel >= spec->channels)
240                     channel = 0;
241             }
242         }
243
244         case PA_SAMPLE_FLOAT32NE: {
245             size_t d;
246             unsigned channel = 0;
247
248             for (d = 0;; d += sizeof(float)) {
249                 float sum = 0;
250
251                 if (d >= length)
252                     return d;
253
254                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
255                     unsigned i;
256
257                     for (i = 0; i < nstreams; i++) {
258                         float v;
259                         pa_volume_t cvolume = streams[i].volume.values[channel];
260
261                         if (d >= streams[i].chunk.length)
262                             return d;
263
264                         if (cvolume == PA_VOLUME_MUTED)
265                             v = 0;
266                         else {
267                             v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
268
269                             if (cvolume != PA_VOLUME_NORM)
270                                 v *= pa_sw_volume_to_linear(cvolume);
271                         }
272
273                         sum += v;
274                     }
275
276                     if (volume->values[channel] != PA_VOLUME_NORM)
277                         sum *= pa_sw_volume_to_linear(volume->values[channel]);
278                 }
279
280                 *((float*) data) = sum;
281                 data = (uint8_t*) data + sizeof(float);
282
283                 if (++channel >= spec->channels)
284                     channel = 0;
285             }
286         }
287
288         default:
289             pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
290             abort();
291     }
292 }
293
294
295 void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) {
296     assert(c && spec && (c->length % pa_frame_size(spec) == 0));
297     assert(volume);
298
299     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
300         return;
301
302     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
303         pa_silence_memchunk(c, spec);
304         return;
305     }
306
307     switch (spec->format) {
308         case PA_SAMPLE_S16NE: {
309             int16_t *d;
310             size_t n;
311             unsigned channel;
312             double linear[PA_CHANNELS_MAX];
313
314             for (channel = 0; channel < spec->channels; channel++)
315                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
316
317             for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
318                 int32_t t = (int32_t)(*d);
319
320                 t = (int32_t) (t * linear[channel]);
321
322                 if (t < -0x8000) t = -0x8000;
323                 if (t > 0x7FFF) t = 0x7FFF;
324
325                 *d = (int16_t) t;
326
327                 if (++channel >= spec->channels)
328                     channel = 0;
329             }
330             break;
331         }
332
333         case PA_SAMPLE_S16RE: {
334             int16_t *d;
335             size_t n;
336             unsigned channel;
337             double linear[PA_CHANNELS_MAX];
338
339             for (channel = 0; channel < spec->channels; channel++)
340                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
341
342             for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
343                 int32_t t = (int32_t)(INT16_SWAP(*d));
344
345                 t = (int32_t) (t * linear[channel]);
346
347                 if (t < -0x8000) t = -0x8000;
348                 if (t > 0x7FFF) t = 0x7FFF;
349
350                 *d = INT16_SWAP((int16_t) t);
351
352                 if (++channel >= spec->channels)
353                     channel = 0;
354             }
355
356             break;
357         }
358
359         case PA_SAMPLE_U8: {
360             uint8_t *d;
361             size_t n;
362             unsigned channel = 0;
363
364             for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) {
365                 int32_t t = (int32_t) *d - 0x80;
366
367                 t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
368
369                 if (t < -0x80) t = -0x80;
370                 if (t > 0x7F) t = 0x7F;
371
372                 *d = (uint8_t) (t + 0x80);
373
374                 if (++channel >= spec->channels)
375                     channel = 0;
376             }
377             break;
378         }
379
380         case PA_SAMPLE_FLOAT32NE: {
381             float *d;
382             int skip;
383             unsigned n;
384             unsigned channel;
385
386             d = (float*) ((uint8_t*) c->memblock->data + c->index);
387             skip = spec->channels * sizeof(float);
388             n = c->length/sizeof(float)/spec->channels;
389
390             for (channel = 0; channel < spec->channels ; channel ++) {
391                 float v, *t;
392
393                 if (volume->values[channel] == PA_VOLUME_NORM)
394                     continue;
395
396                 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
397
398                 t = d + channel;
399                 oil_scalarmult_f32(t, skip, t, skip, &v, n);
400             }
401             break;
402         }
403
404         default:
405             pa_log_error("ERROR: Unable to change volume of format %s.",
406                 pa_sample_format_to_string(spec->format));
407             abort();
408     }
409 }
410