]> code.delx.au - pulseaudio/blob - src/pulsecore/sample-util.c
Support reversed endian floats. (closes #28) (closes #35)
[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 assert(b && b->data && spec);
50 pa_silence_memory(b->data, b->length, spec);
51 return b;
52 }
53
54 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
55 assert(c && c->memblock && c->memblock->data && spec && c->length);
56
57 pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec);
58 }
59
60 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
61 uint8_t c = 0;
62 assert(p && length && spec);
63
64 switch (spec->format) {
65 case PA_SAMPLE_U8:
66 c = 0x80;
67 break;
68 case PA_SAMPLE_S16LE:
69 case PA_SAMPLE_S16BE:
70 case PA_SAMPLE_FLOAT32:
71 case PA_SAMPLE_FLOAT32RE:
72 c = 0;
73 break;
74 case PA_SAMPLE_ALAW:
75 case PA_SAMPLE_ULAW:
76 c = 80;
77 break;
78 default:
79 assert(0);
80 }
81
82 memset(p, c, length);
83 }
84
85 size_t pa_mix(
86 const pa_mix_info streams[],
87 unsigned nstreams,
88 void *data,
89 size_t length,
90 const pa_sample_spec *spec,
91 const pa_cvolume *volume,
92 int mute) {
93
94 assert(streams && data && length && spec);
95
96 switch (spec->format) {
97 case PA_SAMPLE_S16NE:{
98 size_t d;
99 unsigned channel = 0;
100
101 for (d = 0;; d += sizeof(int16_t)) {
102 int32_t sum = 0;
103
104 if (d >= length)
105 return d;
106
107 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
108 unsigned i;
109
110 for (i = 0; i < nstreams; i++) {
111 int32_t v;
112 pa_volume_t cvolume = streams[i].volume.values[channel];
113
114 if (d >= streams[i].chunk.length)
115 return d;
116
117 if (cvolume == PA_VOLUME_MUTED)
118 v = 0;
119 else {
120 v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
121
122 if (cvolume != PA_VOLUME_NORM)
123 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
124 }
125
126 sum += v;
127 }
128
129 if (volume->values[channel] != PA_VOLUME_NORM)
130 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
131
132 if (sum < -0x8000) sum = -0x8000;
133 if (sum > 0x7FFF) sum = 0x7FFF;
134
135 }
136
137 *((int16_t*) data) = sum;
138 data = (uint8_t*) data + sizeof(int16_t);
139
140 if (++channel >= spec->channels)
141 channel = 0;
142 }
143 }
144
145 case PA_SAMPLE_S16RE:{
146 size_t d;
147 unsigned channel = 0;
148
149 for (d = 0;; d += sizeof(int16_t)) {
150 int32_t sum = 0;
151
152 if (d >= length)
153 return d;
154
155 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
156 unsigned i;
157
158 for (i = 0; i < nstreams; i++) {
159 int32_t v;
160 pa_volume_t cvolume = streams[i].volume.values[channel];
161
162 if (d >= streams[i].chunk.length)
163 return d;
164
165 if (cvolume == PA_VOLUME_MUTED)
166 v = 0;
167 else {
168 v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)));
169
170 if (cvolume != PA_VOLUME_NORM)
171 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
172 }
173
174 sum += v;
175 }
176
177 if (volume->values[channel] != PA_VOLUME_NORM)
178 sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
179
180 if (sum < -0x8000) sum = -0x8000;
181 if (sum > 0x7FFF) sum = 0x7FFF;
182
183 }
184
185 *((int16_t*) data) = INT16_SWAP(sum);
186 data = (uint8_t*) data + sizeof(int16_t);
187
188 if (++channel >= spec->channels)
189 channel = 0;
190 }
191 }
192
193 case PA_SAMPLE_U8: {
194 size_t d;
195 unsigned channel = 0;
196
197 for (d = 0;; d ++) {
198 int32_t sum = 0;
199
200 if (d >= length)
201 return d;
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 return d;
212
213 if (cvolume == PA_VOLUME_MUTED)
214 v = 0;
215 else {
216 v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80;
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 if (sum < -0x80) sum = -0x80;
229 if (sum > 0x7F) sum = 0x7F;
230
231 }
232
233 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
234 data = (uint8_t*) data + 1;
235
236 if (++channel >= spec->channels)
237 channel = 0;
238 }
239 }
240
241 case PA_SAMPLE_FLOAT32NE: {
242 size_t d;
243 unsigned channel = 0;
244
245 for (d = 0;; d += sizeof(float)) {
246 float sum = 0;
247
248 if (d >= length)
249 return d;
250
251 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
252 unsigned i;
253
254 for (i = 0; i < nstreams; i++) {
255 float v;
256 pa_volume_t cvolume = streams[i].volume.values[channel];
257
258 if (d >= streams[i].chunk.length)
259 return d;
260
261 if (cvolume == PA_VOLUME_MUTED)
262 v = 0;
263 else {
264 v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
265
266 if (cvolume != PA_VOLUME_NORM)
267 v *= pa_sw_volume_to_linear(cvolume);
268 }
269
270 sum += v;
271 }
272
273 if (volume->values[channel] != PA_VOLUME_NORM)
274 sum *= pa_sw_volume_to_linear(volume->values[channel]);
275 }
276
277 *((float*) data) = sum;
278 data = (uint8_t*) data + sizeof(float);
279
280 if (++channel >= spec->channels)
281 channel = 0;
282 }
283 }
284
285 default:
286 pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
287 abort();
288 }
289 }
290
291
292 void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) {
293 assert(c && spec && (c->length % pa_frame_size(spec) == 0));
294 assert(volume);
295
296 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
297 return;
298
299 if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
300 pa_silence_memchunk(c, spec);
301 return;
302 }
303
304 switch (spec->format) {
305 case PA_SAMPLE_S16NE: {
306 int16_t *d;
307 size_t n;
308 unsigned channel;
309 double linear[PA_CHANNELS_MAX];
310
311 for (channel = 0; channel < spec->channels; channel++)
312 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
313
314 for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
315 int32_t t = (int32_t)(*d);
316
317 t = (int32_t) (t * linear[channel]);
318
319 if (t < -0x8000) t = -0x8000;
320 if (t > 0x7FFF) t = 0x7FFF;
321
322 *d = (int16_t) t;
323
324 if (++channel >= spec->channels)
325 channel = 0;
326 }
327 break;
328 }
329
330 case PA_SAMPLE_S16RE: {
331 int16_t *d;
332 size_t n;
333 unsigned channel;
334 double linear[PA_CHANNELS_MAX];
335
336 for (channel = 0; channel < spec->channels; channel++)
337 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
338
339 for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
340 int32_t t = (int32_t)(INT16_SWAP(*d));
341
342 t = (int32_t) (t * linear[channel]);
343
344 if (t < -0x8000) t = -0x8000;
345 if (t > 0x7FFF) t = 0x7FFF;
346
347 *d = INT16_SWAP((int16_t) t);
348
349 if (++channel >= spec->channels)
350 channel = 0;
351 }
352
353 break;
354 }
355
356 case PA_SAMPLE_U8: {
357 uint8_t *d;
358 size_t n;
359 unsigned channel = 0;
360
361 for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) {
362 int32_t t = (int32_t) *d - 0x80;
363
364 t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
365
366 if (t < -0x80) t = -0x80;
367 if (t > 0x7F) t = 0x7F;
368
369 *d = (uint8_t) (t + 0x80);
370
371 if (++channel >= spec->channels)
372 channel = 0;
373 }
374 break;
375 }
376
377 case PA_SAMPLE_FLOAT32NE: {
378 float *d;
379 int skip;
380 unsigned n;
381 unsigned channel;
382
383 d = (float*) ((uint8_t*) c->memblock->data + c->index);
384 skip = spec->channels * sizeof(float);
385 n = c->length/sizeof(float)/spec->channels;
386
387 for (channel = 0; channel < spec->channels ; channel ++) {
388 float v, *t;
389
390 if (volume->values[channel] == PA_VOLUME_NORM)
391 continue;
392
393 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
394
395 t = d + channel;
396 oil_scalarmult_f32(t, skip, t, skip, &v, n);
397 }
398 break;
399 }
400
401 default:
402 pa_log_error("ERROR: Unable to change volume of format %s.",
403 pa_sample_format_to_string(spec->format));
404 abort();
405 }
406 }
407