]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
Add copyright notices to all relevant files. (based on svn log)
[pulseaudio] / 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