]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
prefix by order macros with PA_
[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 <stdlib.h>
32
33 #include <liboil/liboilfuncs.h>
34
35 #include <pulsecore/log.h>
36 #include <pulsecore/macro.h>
37
38 #include "sample-util.h"
39 #include "endianmacros.h"
40
41 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
42
43 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
44 size_t fs;
45 pa_assert(pool);
46 pa_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
56 length = (length+fs-1)/fs;
57
58 if (length <= 0)
59 length = 1;
60
61 length *= fs;
62
63 return pa_silence_memblock(pa_memblock_new(pool, length), spec);
64 }
65
66 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
67 void *data;
68
69 pa_assert(b);
70 pa_assert(spec);
71
72 data = pa_memblock_acquire(b);
73 pa_silence_memory(data, pa_memblock_get_length(b), spec);
74 pa_memblock_release(b);
75 return b;
76 }
77
78 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
79 void *data;
80
81 pa_assert(c);
82 pa_assert(c->memblock);
83 pa_assert(spec);
84
85 data = pa_memblock_acquire(c->memblock);
86 pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
87 pa_memblock_release(c->memblock);
88 }
89
90 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
91 uint8_t c = 0;
92 pa_assert(p);
93 pa_assert(length > 0);
94 pa_assert(spec);
95
96 switch (spec->format) {
97 case PA_SAMPLE_U8:
98 c = 0x80;
99 break;
100 case PA_SAMPLE_S16LE:
101 case PA_SAMPLE_S16BE:
102 case PA_SAMPLE_FLOAT32:
103 case PA_SAMPLE_FLOAT32RE:
104 c = 0;
105 break;
106 case PA_SAMPLE_ALAW:
107 case PA_SAMPLE_ULAW:
108 c = 80;
109 break;
110 default:
111 pa_assert_not_reached();
112 }
113
114 memset(p, c, length);
115 }
116
117 size_t pa_mix(
118 pa_mix_info streams[],
119 unsigned nstreams,
120 void *data,
121 size_t length,
122 const pa_sample_spec *spec,
123 const pa_cvolume *volume,
124 int mute) {
125
126 pa_cvolume full_volume;
127 size_t d = 0;
128 unsigned k;
129
130 pa_assert(streams);
131 pa_assert(data);
132 pa_assert(length);
133 pa_assert(spec);
134
135 if (!volume)
136 volume = pa_cvolume_reset(&full_volume, spec->channels);
137
138 for (k = 0; k < nstreams; k++)
139 streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
140
141 switch (spec->format) {
142 case PA_SAMPLE_S16NE:{
143 unsigned channel = 0;
144
145 for (d = 0;; d += sizeof(int16_t)) {
146 int32_t sum = 0;
147
148 if (d >= length)
149 goto finish;
150
151 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
152 unsigned i;
153
154 for (i = 0; i < nstreams; i++) {
155 int32_t v;
156 pa_volume_t cvolume = streams[i].volume.values[channel];
157
158 if (d >= streams[i].chunk.length)
159 goto finish;
160
161 if (cvolume == PA_VOLUME_MUTED)
162 v = 0;
163 else {
164 v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
165
166 if (cvolume != PA_VOLUME_NORM)
167 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
168 }
169
170 sum += v;
171 }
172
173 if (volume->values[channel] != PA_VOLUME_NORM)
174 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
175
176 sum = CLAMP(sum, -0x8000, 0x7FFF);
177 }
178
179 *((int16_t*) data) = (int16_t) sum;
180 data = (uint8_t*) data + sizeof(int16_t);
181
182 if (++channel >= spec->channels)
183 channel = 0;
184 }
185
186 break;
187 }
188
189 case PA_SAMPLE_S16RE:{
190 unsigned channel = 0;
191
192 for (d = 0;; d += sizeof(int16_t)) {
193 int32_t sum = 0;
194
195 if (d >= length)
196 goto finish;
197
198 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
199 unsigned i;
200
201 for (i = 0; i < nstreams; i++) {
202 int32_t v;
203 pa_volume_t cvolume = streams[i].volume.values[channel];
204
205 if (d >= streams[i].chunk.length)
206 goto finish;
207
208 if (cvolume == PA_VOLUME_MUTED)
209 v = 0;
210 else {
211 v = PA_INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
212
213 if (cvolume != PA_VOLUME_NORM)
214 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
215 }
216
217 sum += v;
218 }
219
220 if (volume->values[channel] != PA_VOLUME_NORM)
221 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
222
223 sum = CLAMP(sum, -0x8000, 0x7FFF);
224 }
225
226 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
227 data = (uint8_t*) data + sizeof(int16_t);
228
229 if (++channel >= spec->channels)
230 channel = 0;
231 }
232
233 break;
234 }
235
236 case PA_SAMPLE_U8: {
237 unsigned channel = 0;
238
239 for (d = 0;; d ++) {
240 int32_t sum = 0;
241
242 if (d >= length)
243 goto finish;
244
245 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
246 unsigned i;
247
248 for (i = 0; i < nstreams; i++) {
249 int32_t v;
250 pa_volume_t cvolume = streams[i].volume.values[channel];
251
252 if (d >= streams[i].chunk.length)
253 goto finish;
254
255 if (cvolume == PA_VOLUME_MUTED)
256 v = 0;
257 else {
258 v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
259
260 if (cvolume != PA_VOLUME_NORM)
261 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
262 }
263
264 sum += v;
265 }
266
267 if (volume->values[channel] != PA_VOLUME_NORM)
268 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
269
270 sum = CLAMP(sum, -0x80, 0x7F);
271 }
272
273 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
274 data = (uint8_t*) data + 1;
275
276 if (++channel >= spec->channels)
277 channel = 0;
278 }
279
280 break;
281 }
282
283 case PA_SAMPLE_FLOAT32NE: {
284 unsigned channel = 0;
285
286 for (d = 0;; d += sizeof(float)) {
287 float sum = 0;
288
289 if (d >= length)
290 goto finish;
291
292 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
293 unsigned i;
294
295 for (i = 0; i < nstreams; i++) {
296 float v;
297 pa_volume_t cvolume = streams[i].volume.values[channel];
298
299 if (d >= streams[i].chunk.length)
300 goto finish;
301
302 if (cvolume == PA_VOLUME_MUTED)
303 v = 0;
304 else {
305 v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
306
307 if (cvolume != PA_VOLUME_NORM)
308 v *= pa_sw_volume_to_linear(cvolume);
309 }
310
311 sum += v;
312 }
313
314 if (volume->values[channel] != PA_VOLUME_NORM)
315 sum *= pa_sw_volume_to_linear(volume->values[channel]);
316 }
317
318 *((float*) data) = sum;
319 data = (uint8_t*) data + sizeof(float);
320
321 if (++channel >= spec->channels)
322 channel = 0;
323 }
324
325 break;
326 }
327
328 default:
329 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
330 abort();
331 }
332
333 finish:
334
335 for (k = 0; k < nstreams; k++)
336 pa_memblock_release(streams[k].chunk.memblock);
337
338 return d;
339 }
340
341
342 void pa_volume_memchunk(
343 pa_memchunk*c,
344 const pa_sample_spec *spec,
345 const pa_cvolume *volume) {
346
347 void *ptr;
348
349 pa_assert(c);
350 pa_assert(spec);
351 pa_assert(c->length % pa_frame_size(spec) == 0);
352 pa_assert(volume);
353
354 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
355 return;
356
357 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
358 pa_silence_memchunk(c, spec);
359 return;
360 }
361
362 ptr = pa_memblock_acquire(c->memblock);
363
364 switch (spec->format) {
365
366 case PA_SAMPLE_S16NE: {
367 int16_t *d;
368 size_t n;
369 unsigned channel;
370 int32_t linear[PA_CHANNELS_MAX];
371
372 for (channel = 0; channel < spec->channels; channel++)
373 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
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;
377
378 t = (int32_t)(*d);
379 t = (t * linear[channel]) / 0x10000;
380 t = CLAMP(t, -0x8000, 0x7FFF);
381 *d = (int16_t) t;
382
383 if (++channel >= spec->channels)
384 channel = 0;
385 }
386 break;
387 }
388
389 case PA_SAMPLE_S16RE: {
390 int16_t *d;
391 size_t n;
392 unsigned channel;
393 int32_t linear[PA_CHANNELS_MAX];
394
395 for (channel = 0; channel < spec->channels; channel++)
396 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
397
398 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
399 int32_t t;
400
401 t = (int32_t)(PA_INT16_SWAP(*d));
402 t = (t * linear[channel]) / 0x10000;
403 t = CLAMP(t, -0x8000, 0x7FFF);
404 *d = PA_INT16_SWAP((int16_t) t);
405
406 if (++channel >= spec->channels)
407 channel = 0;
408 }
409
410 break;
411 }
412
413 case PA_SAMPLE_U8: {
414 uint8_t *d;
415 size_t n;
416 unsigned channel;
417 int32_t linear[PA_CHANNELS_MAX];
418
419 for (channel = 0; channel < spec->channels; channel++)
420 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
421
422 for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
423 int32_t t;
424
425 t = (int32_t) *d - 0x80;
426 t = (t * linear[channel]) / 0x10000;
427 t = CLAMP(t, -0x80, 0x7F);
428 *d = (uint8_t) (t + 0x80);
429
430 if (++channel >= spec->channels)
431 channel = 0;
432 }
433 break;
434 }
435
436 case PA_SAMPLE_FLOAT32NE: {
437 float *d;
438 int skip;
439 unsigned n;
440 unsigned channel;
441
442 d = (float*) ((uint8_t*) ptr + c->index);
443 skip = spec->channels * sizeof(float);
444 n = c->length/sizeof(float)/spec->channels;
445
446 for (channel = 0; channel < spec->channels ; channel ++) {
447 float v, *t;
448
449 if (volume->values[channel] == PA_VOLUME_NORM)
450 continue;
451
452 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
453 t = d + channel;
454 oil_scalarmult_f32(t, skip, t, skip, &v, n);
455 }
456 break;
457 }
458
459 default:
460 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
461 /* If we cannot change the volume, we just don't do it */
462 }
463
464 pa_memblock_release(c->memblock);
465 }
466
467 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
468 size_t fs;
469
470 pa_assert(ss);
471
472 fs = pa_frame_size(ss);
473
474 return (l/fs) * fs;
475 }
476
477 int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
478 size_t fs;
479
480 pa_assert(ss);
481
482 fs = pa_frame_size(ss);
483
484 return l % fs == 0;
485 }