]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
fix silence initializer for alaw and ulaw
[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 c = 0xd5;
108 break;
109 case PA_SAMPLE_ULAW:
110 c = 0xff;
111 breaK;
112 default:
113 pa_assert_not_reached();
114 }
115
116 memset(p, c, length);
117 }
118
119 size_t pa_mix(
120 pa_mix_info streams[],
121 unsigned nstreams,
122 void *data,
123 size_t length,
124 const pa_sample_spec *spec,
125 const pa_cvolume *volume,
126 int mute) {
127
128 pa_cvolume full_volume;
129 size_t d = 0;
130 unsigned k;
131
132 pa_assert(streams);
133 pa_assert(data);
134 pa_assert(length);
135 pa_assert(spec);
136
137 if (!volume)
138 volume = pa_cvolume_reset(&full_volume, spec->channels);
139
140 for (k = 0; k < nstreams; k++)
141 streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
142
143 switch (spec->format) {
144 case PA_SAMPLE_S16NE:{
145 unsigned channel = 0;
146
147 for (d = 0;; d += sizeof(int16_t)) {
148 int32_t sum = 0;
149
150 if (d >= length)
151 goto finish;
152
153 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
154 unsigned i;
155
156 for (i = 0; i < nstreams; i++) {
157 int32_t v;
158 pa_volume_t cvolume = streams[i].volume.values[channel];
159
160 if (d >= streams[i].chunk.length)
161 goto finish;
162
163 if (cvolume == PA_VOLUME_MUTED)
164 v = 0;
165 else {
166 v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
167
168 if (cvolume != PA_VOLUME_NORM)
169 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
170 }
171
172 sum += v;
173 }
174
175 if (volume->values[channel] != PA_VOLUME_NORM)
176 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
177
178 sum = CLAMP(sum, -0x8000, 0x7FFF);
179 }
180
181 *((int16_t*) data) = (int16_t) sum;
182 data = (uint8_t*) data + sizeof(int16_t);
183
184 if (++channel >= spec->channels)
185 channel = 0;
186 }
187
188 break;
189 }
190
191 case PA_SAMPLE_S16RE:{
192 unsigned channel = 0;
193
194 for (d = 0;; d += sizeof(int16_t)) {
195 int32_t sum = 0;
196
197 if (d >= length)
198 goto finish;
199
200 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
201 unsigned i;
202
203 for (i = 0; i < nstreams; i++) {
204 int32_t v;
205 pa_volume_t cvolume = streams[i].volume.values[channel];
206
207 if (d >= streams[i].chunk.length)
208 goto finish;
209
210 if (cvolume == PA_VOLUME_MUTED)
211 v = 0;
212 else {
213 v = PA_INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
214
215 if (cvolume != PA_VOLUME_NORM)
216 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
217 }
218
219 sum += v;
220 }
221
222 if (volume->values[channel] != PA_VOLUME_NORM)
223 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
224
225 sum = CLAMP(sum, -0x8000, 0x7FFF);
226 }
227
228 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
229 data = (uint8_t*) data + sizeof(int16_t);
230
231 if (++channel >= spec->channels)
232 channel = 0;
233 }
234
235 break;
236 }
237
238 case PA_SAMPLE_U8: {
239 unsigned channel = 0;
240
241 for (d = 0;; d ++) {
242 int32_t sum = 0;
243
244 if (d >= length)
245 goto finish;
246
247 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
248 unsigned i;
249
250 for (i = 0; i < nstreams; i++) {
251 int32_t v;
252 pa_volume_t cvolume = streams[i].volume.values[channel];
253
254 if (d >= streams[i].chunk.length)
255 goto finish;
256
257 if (cvolume == PA_VOLUME_MUTED)
258 v = 0;
259 else {
260 v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
261
262 if (cvolume != PA_VOLUME_NORM)
263 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
264 }
265
266 sum += v;
267 }
268
269 if (volume->values[channel] != PA_VOLUME_NORM)
270 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
271
272 sum = CLAMP(sum, -0x80, 0x7F);
273 }
274
275 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
276 data = (uint8_t*) data + 1;
277
278 if (++channel >= spec->channels)
279 channel = 0;
280 }
281
282 break;
283 }
284
285 case PA_SAMPLE_FLOAT32NE: {
286 unsigned channel = 0;
287
288 for (d = 0;; d += sizeof(float)) {
289 float sum = 0;
290
291 if (d >= length)
292 goto finish;
293
294 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
295 unsigned i;
296
297 for (i = 0; i < nstreams; i++) {
298 float v;
299 pa_volume_t cvolume = streams[i].volume.values[channel];
300
301 if (d >= streams[i].chunk.length)
302 goto finish;
303
304 if (cvolume == PA_VOLUME_MUTED)
305 v = 0;
306 else {
307 v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
308
309 if (cvolume != PA_VOLUME_NORM)
310 v *= pa_sw_volume_to_linear(cvolume);
311 }
312
313 sum += v;
314 }
315
316 if (volume->values[channel] != PA_VOLUME_NORM)
317 sum *= pa_sw_volume_to_linear(volume->values[channel]);
318 }
319
320 *((float*) data) = sum;
321 data = (uint8_t*) data + sizeof(float);
322
323 if (++channel >= spec->channels)
324 channel = 0;
325 }
326
327 break;
328 }
329
330 default:
331 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
332 abort();
333 }
334
335 finish:
336
337 for (k = 0; k < nstreams; k++)
338 pa_memblock_release(streams[k].chunk.memblock);
339
340 return d;
341 }
342
343
344 void pa_volume_memchunk(
345 pa_memchunk*c,
346 const pa_sample_spec *spec,
347 const pa_cvolume *volume) {
348
349 void *ptr;
350
351 pa_assert(c);
352 pa_assert(spec);
353 pa_assert(c->length % pa_frame_size(spec) == 0);
354 pa_assert(volume);
355
356 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
357 return;
358
359 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
360 pa_silence_memchunk(c, spec);
361 return;
362 }
363
364 ptr = pa_memblock_acquire(c->memblock);
365
366 switch (spec->format) {
367
368 case PA_SAMPLE_S16NE: {
369 int16_t *d;
370 size_t n;
371 unsigned channel;
372 int32_t linear[PA_CHANNELS_MAX];
373
374 for (channel = 0; channel < spec->channels; channel++)
375 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
376
377 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
378 int32_t t;
379
380 t = (int32_t)(*d);
381 t = (t * linear[channel]) / 0x10000;
382 t = CLAMP(t, -0x8000, 0x7FFF);
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 int32_t linear[PA_CHANNELS_MAX];
396
397 for (channel = 0; channel < spec->channels; channel++)
398 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
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;
402
403 t = (int32_t)(PA_INT16_SWAP(*d));
404 t = (t * linear[channel]) / 0x10000;
405 t = CLAMP(t, -0x8000, 0x7FFF);
406 *d = PA_INT16_SWAP((int16_t) t);
407
408 if (++channel >= spec->channels)
409 channel = 0;
410 }
411
412 break;
413 }
414
415 case PA_SAMPLE_U8: {
416 uint8_t *d;
417 size_t n;
418 unsigned channel;
419 int32_t linear[PA_CHANNELS_MAX];
420
421 for (channel = 0; channel < spec->channels; channel++)
422 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
423
424 for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
425 int32_t t;
426
427 t = (int32_t) *d - 0x80;
428 t = (t * linear[channel]) / 0x10000;
429 t = CLAMP(t, -0x80, 0x7F);
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 t = d + channel;
456 oil_scalarmult_f32(t, skip, t, skip, &v, n);
457 }
458 break;
459 }
460
461 default:
462 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
463 /* If we cannot change the volume, we just don't do it */
464 }
465
466 pa_memblock_release(c->memblock);
467 }
468
469 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
470 size_t fs;
471
472 pa_assert(ss);
473
474 fs = pa_frame_size(ss);
475
476 return (l/fs) * fs;
477 }
478
479 int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
480 size_t fs;
481
482 pa_assert(ss);
483
484 fs = pa_frame_size(ss);
485
486 return l % fs == 0;
487 }