]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
rework memory block management to be thread-safe and mostly lock-free.
[pulseaudio] / src / pulsecore / sample-util.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdlib.h>
30
31 #include <liboil/liboilfuncs.h>
32
33 #include <pulsecore/log.h>
34
35 #include "sample-util.h"
36 #include "endianmacros.h"
37
38 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
39 assert(pool);
40 assert(spec);
41
42 if (length == 0)
43 length = pa_bytes_per_second(spec)/20; /* 50 ms */
44
45 return pa_silence_memblock(pa_memblock_new(pool, length), spec);
46 }
47
48 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
49 void *data;
50
51 assert(b);
52 assert(spec);
53
54 data = pa_memblock_acquire(b);
55 pa_silence_memory(data, pa_memblock_get_length(b), spec);
56 pa_memblock_release(b);
57 return b;
58 }
59
60 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
61 void *data;
62
63 assert(c);
64 assert(c->memblock);
65 assert(spec);
66
67 data = pa_memblock_acquire(c->memblock);
68 pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
69 pa_memblock_release(c->memblock);
70 }
71
72 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
73 uint8_t c = 0;
74 assert(p && length && spec);
75
76 switch (spec->format) {
77 case PA_SAMPLE_U8:
78 c = 0x80;
79 break;
80 case PA_SAMPLE_S16LE:
81 case PA_SAMPLE_S16BE:
82 case PA_SAMPLE_FLOAT32:
83 c = 0;
84 break;
85 case PA_SAMPLE_ALAW:
86 case PA_SAMPLE_ULAW:
87 c = 80;
88 break;
89 default:
90 assert(0);
91 }
92
93 memset(p, c, length);
94 }
95
96 size_t pa_mix(
97 pa_mix_info streams[],
98 unsigned nstreams,
99 void *data,
100 size_t length,
101 const pa_sample_spec *spec,
102 const pa_cvolume *volume,
103 int mute) {
104
105 pa_cvolume full_volume;
106 size_t d = 0;
107 unsigned k;
108
109 assert(streams);
110 assert(data);
111 assert(length);
112 assert(spec);
113
114 if (!volume)
115 volume = pa_cvolume_reset(&full_volume, spec->channels);
116
117 for (k = 0; k < nstreams; k++)
118 streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
119
120 switch (spec->format) {
121 case PA_SAMPLE_S16NE:{
122 unsigned channel = 0;
123
124 for (d = 0;; d += sizeof(int16_t)) {
125 int32_t sum = 0;
126
127 if (d >= length)
128 goto finish;
129
130 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
131 unsigned i;
132
133 for (i = 0; i < nstreams; i++) {
134 int32_t v;
135 pa_volume_t cvolume = streams[i].volume.values[channel];
136
137 if (d >= streams[i].chunk.length)
138 goto finish;
139
140 if (cvolume == PA_VOLUME_MUTED)
141 v = 0;
142 else {
143 v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
144
145 if (cvolume != PA_VOLUME_NORM)
146 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
147 }
148
149 sum += v;
150 }
151
152 if (volume->values[channel] != PA_VOLUME_NORM)
153 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
154
155 if (sum < -0x8000) sum = -0x8000;
156 if (sum > 0x7FFF) sum = 0x7FFF;
157
158 }
159
160 *((int16_t*) data) = sum;
161 data = (uint8_t*) data + sizeof(int16_t);
162
163 if (++channel >= spec->channels)
164 channel = 0;
165 }
166
167 break;
168 }
169
170 case PA_SAMPLE_S16RE:{
171 unsigned channel = 0;
172
173 for (d = 0;; d += sizeof(int16_t)) {
174 int32_t sum = 0;
175
176 if (d >= length)
177 goto finish;
178
179 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
180 unsigned i;
181
182 for (i = 0; i < nstreams; i++) {
183 int32_t v;
184 pa_volume_t cvolume = streams[i].volume.values[channel];
185
186 if (d >= streams[i].chunk.length)
187 goto finish;
188
189 if (cvolume == PA_VOLUME_MUTED)
190 v = 0;
191 else {
192 v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
193
194 if (cvolume != PA_VOLUME_NORM)
195 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
196 }
197
198 sum += v;
199 }
200
201 if (volume->values[channel] != PA_VOLUME_NORM)
202 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
203
204 if (sum < -0x8000) sum = -0x8000;
205 if (sum > 0x7FFF) sum = 0x7FFF;
206
207 }
208
209 *((int16_t*) data) = INT16_SWAP(sum);
210 data = (uint8_t*) data + sizeof(int16_t);
211
212 if (++channel >= spec->channels)
213 channel = 0;
214 }
215
216 break;
217 }
218
219 case PA_SAMPLE_U8: {
220 unsigned channel = 0;
221
222 for (d = 0;; d ++) {
223 int32_t sum = 0;
224
225 if (d >= length)
226 goto finish;
227
228 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
229 unsigned i;
230
231 for (i = 0; i < nstreams; i++) {
232 int32_t v;
233 pa_volume_t cvolume = streams[i].volume.values[channel];
234
235 if (d >= streams[i].chunk.length)
236 goto finish;
237
238 if (cvolume == PA_VOLUME_MUTED)
239 v = 0;
240 else {
241 v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
242
243 if (cvolume != PA_VOLUME_NORM)
244 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
245 }
246
247 sum += v;
248 }
249
250 if (volume->values[channel] != PA_VOLUME_NORM)
251 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
252
253 if (sum < -0x80) sum = -0x80;
254 if (sum > 0x7F) sum = 0x7F;
255
256 }
257
258 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
259 data = (uint8_t*) data + 1;
260
261 if (++channel >= spec->channels)
262 channel = 0;
263 }
264
265 break;
266 }
267
268 case PA_SAMPLE_FLOAT32NE: {
269 unsigned channel = 0;
270
271 for (d = 0;; d += sizeof(float)) {
272 float sum = 0;
273
274 if (d >= length)
275 goto finish;
276
277 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
278 unsigned i;
279
280 for (i = 0; i < nstreams; i++) {
281 float v;
282 pa_volume_t cvolume = streams[i].volume.values[channel];
283
284 if (d >= streams[i].chunk.length)
285 goto finish;
286
287 if (cvolume == PA_VOLUME_MUTED)
288 v = 0;
289 else {
290 v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
291
292 if (cvolume != PA_VOLUME_NORM)
293 v *= pa_sw_volume_to_linear(cvolume);
294 }
295
296 sum += v;
297 }
298
299 if (volume->values[channel] != PA_VOLUME_NORM)
300 sum *= pa_sw_volume_to_linear(volume->values[channel]);
301 }
302
303 *((float*) data) = sum;
304 data = (uint8_t*) data + sizeof(float);
305
306 if (++channel >= spec->channels)
307 channel = 0;
308 }
309
310 break;
311 }
312
313 default:
314 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
315 abort();
316 }
317
318 finish:
319
320 for (k = 0; k < nstreams; k++)
321 pa_memblock_release(streams[k].chunk.memblock);
322
323 return d;
324 }
325
326
327 void pa_volume_memchunk(
328 pa_memchunk*c,
329 const pa_sample_spec *spec,
330 const pa_cvolume *volume) {
331
332 void *ptr;
333
334 assert(c);
335 assert(spec);
336 assert(c->length % pa_frame_size(spec) == 0);
337 assert(volume);
338
339 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
340 return;
341
342 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
343 pa_silence_memchunk(c, spec);
344 return;
345 }
346
347 ptr = pa_memblock_acquire(c->memblock);
348
349 switch (spec->format) {
350 case PA_SAMPLE_S16NE: {
351 int16_t *d;
352 size_t n;
353 unsigned channel;
354 double linear[PA_CHANNELS_MAX];
355
356 for (channel = 0; channel < spec->channels; channel++)
357 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
358
359 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
360 int32_t t = (int32_t)(*d);
361
362 t = (int32_t) (t * linear[channel]);
363
364 if (t < -0x8000) t = -0x8000;
365 if (t > 0x7FFF) t = 0x7FFF;
366
367 *d = (int16_t) t;
368
369 if (++channel >= spec->channels)
370 channel = 0;
371 }
372 break;
373 }
374
375 case PA_SAMPLE_S16RE: {
376 int16_t *d;
377 size_t n;
378 unsigned channel;
379 double linear[PA_CHANNELS_MAX];
380
381 for (channel = 0; channel < spec->channels; channel++)
382 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
383
384 for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
385 int32_t t = (int32_t)(INT16_SWAP(*d));
386
387 t = (int32_t) (t * linear[channel]);
388
389 if (t < -0x8000) t = -0x8000;
390 if (t > 0x7FFF) t = 0x7FFF;
391
392 *d = INT16_SWAP((int16_t) t);
393
394 if (++channel >= spec->channels)
395 channel = 0;
396 }
397
398 break;
399 }
400
401 case PA_SAMPLE_U8: {
402 uint8_t *d;
403 size_t n;
404 unsigned channel = 0;
405
406 for (d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
407 int32_t t = (int32_t) *d - 0x80;
408
409 t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
410
411 if (t < -0x80) t = -0x80;
412 if (t > 0x7F) t = 0x7F;
413
414 *d = (uint8_t) (t + 0x80);
415
416 if (++channel >= spec->channels)
417 channel = 0;
418 }
419 break;
420 }
421
422 case PA_SAMPLE_FLOAT32NE: {
423 float *d;
424 int skip;
425 unsigned n;
426 unsigned channel;
427
428 d = (float*) ((uint8_t*) ptr + c->index);
429 skip = spec->channels * sizeof(float);
430 n = c->length/sizeof(float)/spec->channels;
431
432 for (channel = 0; channel < spec->channels ; channel ++) {
433 float v, *t;
434
435 if (volume->values[channel] == PA_VOLUME_NORM)
436 continue;
437
438 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
439
440 t = d + channel;
441 oil_scalarmult_f32(t, skip, t, skip, &v, n);
442 }
443 break;
444 }
445
446 default:
447 pa_log_error("ERROR: Unable to change volume of format %s.",
448 pa_sample_format_to_string(spec->format));
449 abort();
450 }
451
452 pa_memblock_release(c->memblock);
453 }
454