]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
replace a few CLAMPs by PA_CLAMP_UNLIKELY
[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 #include <liboil/liboil.h>
35
36 #include <pulsecore/log.h>
37 #include <pulsecore/macro.h>
38
39 #include "sample-util.h"
40 #include "endianmacros.h"
41
42 #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
43
44 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
45 size_t fs;
46 pa_assert(pool);
47 pa_assert(spec);
48
49 if (length <= 0)
50 length = pa_bytes_per_second(spec)/20; /* 50 ms */
51
52 if (length > PA_SILENCE_MAX)
53 length = PA_SILENCE_MAX;
54
55 fs = pa_frame_size(spec);
56
57 length = (length+fs-1)/fs;
58
59 if (length <= 0)
60 length = 1;
61
62 length *= fs;
63
64 return pa_silence_memblock(pa_memblock_new(pool, length), spec);
65 }
66
67 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
68 void *data;
69
70 pa_assert(b);
71 pa_assert(spec);
72
73 data = pa_memblock_acquire(b);
74 pa_silence_memory(data, pa_memblock_get_length(b), spec);
75 pa_memblock_release(b);
76 return b;
77 }
78
79 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
80 void *data;
81
82 pa_assert(c);
83 pa_assert(c->memblock);
84 pa_assert(spec);
85
86 data = pa_memblock_acquire(c->memblock);
87 pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
88 pa_memblock_release(c->memblock);
89 }
90
91 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
92 uint8_t c = 0;
93 pa_assert(p);
94 pa_assert(length > 0);
95 pa_assert(spec);
96
97 switch (spec->format) {
98 case PA_SAMPLE_U8:
99 c = 0x80;
100 break;
101 case PA_SAMPLE_S16LE:
102 case PA_SAMPLE_S16BE:
103 case PA_SAMPLE_S32LE:
104 case PA_SAMPLE_S32BE:
105 case PA_SAMPLE_FLOAT32:
106 case PA_SAMPLE_FLOAT32RE:
107 c = 0;
108 break;
109 case PA_SAMPLE_ALAW:
110 c = 0xd5;
111 break;
112 case PA_SAMPLE_ULAW:
113 c = 0xff;
114 break;
115 default:
116 pa_assert_not_reached();
117 }
118
119 memset(p, c, length);
120 }
121
122 size_t pa_mix(
123 pa_mix_info streams[],
124 unsigned nstreams,
125 void *data,
126 size_t length,
127 const pa_sample_spec *spec,
128 const pa_cvolume *volume,
129 int mute) {
130
131 pa_cvolume full_volume;
132 size_t d = 0;
133 unsigned k;
134
135 pa_assert(streams);
136 pa_assert(data);
137 pa_assert(length);
138 pa_assert(spec);
139
140 if (!volume)
141 volume = pa_cvolume_reset(&full_volume, spec->channels);
142
143 for (k = 0; k < nstreams; k++)
144 streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
145
146 switch (spec->format) {
147 case PA_SAMPLE_S16NE:{
148 unsigned channel = 0;
149
150 for (d = 0;; d += sizeof(int16_t)) {
151 int32_t sum = 0;
152
153 if (d >= length)
154 goto finish;
155
156 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
157 unsigned i;
158
159 for (i = 0; i < nstreams; i++) {
160 int32_t v;
161 pa_volume_t cvolume = streams[i].volume.values[channel];
162
163 if (d >= streams[i].chunk.length)
164 goto finish;
165
166 if (cvolume == PA_VOLUME_MUTED)
167 v = 0;
168 else {
169 v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
170
171 if (cvolume != PA_VOLUME_NORM)
172 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
173 }
174
175 sum += v;
176 }
177
178 if (volume->values[channel] != PA_VOLUME_NORM)
179 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
180
181 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
182 }
183
184 *((int16_t*) data) = (int16_t) sum;
185 data = (uint8_t*) data + sizeof(int16_t);
186
187 if (++channel >= spec->channels)
188 channel = 0;
189 }
190
191 break;
192 }
193
194 case PA_SAMPLE_S16RE:{
195 unsigned channel = 0;
196
197 for (d = 0;; d += sizeof(int16_t)) {
198 int32_t sum = 0;
199
200 if (d >= length)
201 goto finish;
202
203 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
204 unsigned i;
205
206 for (i = 0; i < nstreams; i++) {
207 int32_t v;
208 pa_volume_t cvolume = streams[i].volume.values[channel];
209
210 if (d >= streams[i].chunk.length)
211 goto finish;
212
213 if (cvolume == PA_VOLUME_MUTED)
214 v = 0;
215 else {
216 v = PA_INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
217
218 if (cvolume != PA_VOLUME_NORM)
219 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
220 }
221
222 sum += v;
223 }
224
225 if (volume->values[channel] != PA_VOLUME_NORM)
226 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
227
228 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
229 }
230
231 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
232 data = (uint8_t*) data + sizeof(int16_t);
233
234 if (++channel >= spec->channels)
235 channel = 0;
236 }
237
238 break;
239 }
240
241 case PA_SAMPLE_U8: {
242 unsigned channel = 0;
243
244 for (d = 0;; d ++) {
245 int32_t sum = 0;
246
247 if (d >= length)
248 goto finish;
249
250 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
251 unsigned i;
252
253 for (i = 0; i < nstreams; i++) {
254 int32_t v;
255 pa_volume_t cvolume = streams[i].volume.values[channel];
256
257 if (d >= streams[i].chunk.length)
258 goto finish;
259
260 if (cvolume == PA_VOLUME_MUTED)
261 v = 0;
262 else {
263 v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
264
265 if (cvolume != PA_VOLUME_NORM)
266 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
267 }
268
269 sum += v;
270 }
271
272 if (volume->values[channel] != PA_VOLUME_NORM)
273 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
274
275 sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
276 }
277
278 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
279 data = (uint8_t*) data + 1;
280
281 if (++channel >= spec->channels)
282 channel = 0;
283 }
284
285 break;
286 }
287
288 case PA_SAMPLE_FLOAT32NE: {
289 unsigned channel = 0;
290
291 for (d = 0;; d += sizeof(float)) {
292 float sum = 0;
293
294 if (d >= length)
295 goto finish;
296
297 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
298 unsigned i;
299
300 for (i = 0; i < nstreams; i++) {
301 float v;
302 pa_volume_t cvolume = streams[i].volume.values[channel];
303
304 if (d >= streams[i].chunk.length)
305 goto finish;
306
307 if (cvolume == PA_VOLUME_MUTED)
308 v = 0;
309 else {
310 v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
311
312 if (cvolume != PA_VOLUME_NORM)
313 v *= pa_sw_volume_to_linear(cvolume);
314 }
315
316 sum += v;
317 }
318
319 if (volume->values[channel] != PA_VOLUME_NORM)
320 sum *= pa_sw_volume_to_linear(volume->values[channel]);
321 }
322
323 *((float*) data) = sum;
324 data = (uint8_t*) data + sizeof(float);
325
326 if (++channel >= spec->channels)
327 channel = 0;
328 }
329
330 break;
331 }
332
333 default:
334 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
335 abort();
336 }
337
338 finish:
339
340 for (k = 0; k < nstreams; k++)
341 pa_memblock_release(streams[k].chunk.memblock);
342
343 return d;
344 }
345
346
347 void pa_volume_memchunk(
348 pa_memchunk*c,
349 const pa_sample_spec *spec,
350 const pa_cvolume *volume) {
351
352 void *ptr;
353
354 pa_assert(c);
355 pa_assert(spec);
356 pa_assert(c->length % pa_frame_size(spec) == 0);
357 pa_assert(volume);
358
359 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
360 return;
361
362 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
363 pa_silence_memchunk(c, spec);
364 return;
365 }
366
367 ptr = pa_memblock_acquire(c->memblock);
368
369 switch (spec->format) {
370
371 case PA_SAMPLE_S16NE: {
372 int16_t *d;
373 size_t n;
374 unsigned channel;
375 int32_t linear[PA_CHANNELS_MAX];
376
377 for (channel = 0; channel < spec->channels; channel++)
378 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
379
380 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
381 int32_t t;
382
383 t = (int32_t)(*d);
384 t = (t * linear[channel]) / 0x10000;
385 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
386 *d = (int16_t) t;
387
388 if (PA_UNLIKELY(++channel >= spec->channels))
389 channel = 0;
390 }
391 break;
392 }
393
394 case PA_SAMPLE_S16RE: {
395 int16_t *d;
396 size_t n;
397 unsigned channel;
398 int32_t linear[PA_CHANNELS_MAX];
399
400 for (channel = 0; channel < spec->channels; channel++)
401 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
402
403 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
404 int32_t t;
405
406 t = (int32_t)(PA_INT16_SWAP(*d));
407 t = (t * linear[channel]) / 0x10000;
408 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
409 *d = PA_INT16_SWAP((int16_t) t);
410
411 if (PA_UNLIKELY(++channel >= spec->channels))
412 channel = 0;
413 }
414
415 break;
416 }
417
418 case PA_SAMPLE_S32NE: {
419 int32_t *d;
420 size_t n;
421 unsigned channel;
422 int32_t linear[PA_CHANNELS_MAX];
423
424 for (channel = 0; channel < spec->channels; channel++)
425 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
426
427 for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) {
428 int64_t t;
429
430 t = (int64_t)(*d);
431 t = (t * linear[channel]) / 0x10000;
432 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
433 *d = (int32_t) t;
434
435 if (PA_UNLIKELY(++channel >= spec->channels))
436 channel = 0;
437 }
438 break;
439 }
440
441 case PA_SAMPLE_S32RE: {
442 int32_t *d;
443 size_t n;
444 unsigned channel;
445 int32_t linear[PA_CHANNELS_MAX];
446
447 for (channel = 0; channel < spec->channels; channel++)
448 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
449
450 for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) {
451 int64_t t;
452
453 t = (int64_t)(PA_INT32_SWAP(*d));
454 t = (t * linear[channel]) / 0x10000;
455 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
456 *d = PA_INT32_SWAP((int32_t) t);
457
458 if (PA_UNLIKELY(++channel >= spec->channels))
459 channel = 0;
460 }
461
462 break;
463 }
464
465 case PA_SAMPLE_U8: {
466 uint8_t *d;
467 size_t n;
468 unsigned channel;
469 int32_t linear[PA_CHANNELS_MAX];
470
471 for (channel = 0; channel < spec->channels; channel++)
472 linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
473
474 for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
475 int32_t t;
476
477 t = (int32_t) *d - 0x80;
478 t = (t * linear[channel]) / 0x10000;
479 t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
480 *d = (uint8_t) (t + 0x80);
481
482 if (PA_UNLIKELY(++channel >= spec->channels))
483 channel = 0;
484 }
485 break;
486 }
487
488 case PA_SAMPLE_FLOAT32NE: {
489 float *d;
490 int skip;
491 unsigned n;
492 unsigned channel;
493
494 d = (float*) ((uint8_t*) ptr + c->index);
495 skip = spec->channels * sizeof(float);
496 n = c->length/sizeof(float)/spec->channels;
497
498 for (channel = 0; channel < spec->channels ; channel ++) {
499 float v, *t;
500
501 if (volume->values[channel] == PA_VOLUME_NORM)
502 continue;
503
504 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
505 t = d + channel;
506 oil_scalarmult_f32(t, skip, t, skip, &v, n);
507 }
508 break;
509 }
510
511 default:
512 pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
513 /* If we cannot change the volume, we just don't do it */
514 }
515
516 pa_memblock_release(c->memblock);
517 }
518
519 size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
520 size_t fs;
521
522 pa_assert(ss);
523
524 fs = pa_frame_size(ss);
525
526 return (l/fs) * fs;
527 }
528
529 int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
530 size_t fs;
531
532 pa_assert(ss);
533
534 fs = pa_frame_size(ss);
535
536 return l % fs == 0;
537 }
538
539 void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
540 unsigned c;
541 size_t fs;
542
543 pa_assert(src);
544 pa_assert(channels > 0);
545 pa_assert(dst);
546 pa_assert(ss > 0);
547 pa_assert(n > 0);
548
549 fs = ss * channels;
550
551 for (c = 0; c < channels; c++) {
552 unsigned j;
553 void *d;
554 const void *s;
555
556 s = src[c];
557 d = (uint8_t*) dst + c * ss;
558
559 for (j = 0; j < n; j ++) {
560 oil_memcpy(d, s, ss);
561 s = (uint8_t*) s + ss;
562 d = (uint8_t*) d + fs;
563 }
564 }
565 }
566
567 void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
568 size_t fs;
569 unsigned c;
570
571 pa_assert(src);
572 pa_assert(dst);
573 pa_assert(channels > 0);
574 pa_assert(ss > 0);
575 pa_assert(n > 0);
576
577 fs = ss * channels;
578
579 for (c = 0; c < channels; c++) {
580 unsigned j;
581 const void *s;
582 void *d;
583
584 s = (uint8_t*) src + c * ss;
585 d = dst[c];
586
587 for (j = 0; j < n; j ++) {
588 oil_memcpy(d, s, ss);
589 s = (uint8_t*) s + fs;
590 d = (uint8_t*) d + ss;
591 }
592 }
593 }