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