1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2006 Lennart Poettering
5  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 2.1 of the License,
10  or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public License
18  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <string.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <errno.h>
29#include <math.h>
30
31#include <pulse/timeval.h>
32
33#include <pulsecore/log.h>
34#include <pulsecore/core-error.h>
35#include <pulsecore/macro.h>
36#include <pulsecore/g711.h>
37#include <pulsecore/core-util.h>
38#include <pulsecore/endianmacros.h>
39
40#include "sample-util.h"
41
42#define PA_SILENCE_MAX (pa_page_size()*16)
43
44pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
45    void *data;
46
47    pa_assert(b);
48    pa_assert(spec);
49
50    data = pa_memblock_acquire(b);
51    pa_silence_memory(data, pa_memblock_get_length(b), spec);
52    pa_memblock_release(b);
53
54    return b;
55}
56
57pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
58    void *data;
59
60    pa_assert(c);
61    pa_assert(c->memblock);
62    pa_assert(spec);
63
64    data = pa_memblock_acquire(c->memblock);
65    pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
66    pa_memblock_release(c->memblock);
67
68    return c;
69}
70
71static uint8_t silence_byte(pa_sample_format_t format) {
72    switch (format) {
73        case PA_SAMPLE_U8:
74            return 0x80;
75        case PA_SAMPLE_S16LE:
76        case PA_SAMPLE_S16BE:
77        case PA_SAMPLE_S32LE:
78        case PA_SAMPLE_S32BE:
79        case PA_SAMPLE_FLOAT32LE:
80        case PA_SAMPLE_FLOAT32BE:
81        case PA_SAMPLE_S24LE:
82        case PA_SAMPLE_S24BE:
83        case PA_SAMPLE_S24_32LE:
84        case PA_SAMPLE_S24_32BE:
85            return 0;
86        case PA_SAMPLE_ALAW:
87            return 0xd5;
88        case PA_SAMPLE_ULAW:
89            return 0xff;
90        default:
91            pa_assert_not_reached();
92    }
93}
94
95void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
96    pa_assert(p);
97    pa_assert(length > 0);
98    pa_assert(spec);
99
100    memset(p, silence_byte(spec->format), length);
101    return p;
102}
103
104size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
105    size_t fs;
106
107    pa_assert(ss);
108
109    fs = pa_frame_size(ss);
110
111    return (l/fs) * fs;
112}
113
114bool pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
115    size_t fs;
116
117    pa_assert(ss);
118
119    fs = pa_frame_size(ss);
120
121    return l % fs == 0;
122}
123
124void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
125    unsigned c;
126    size_t fs;
127
128    pa_assert(src);
129    pa_assert(channels > 0);
130    pa_assert(dst);
131    pa_assert(ss > 0);
132    pa_assert(n > 0);
133
134    fs = ss * channels;
135
136    for (c = 0; c < channels; c++) {
137        unsigned j;
138        void *d;
139        const void *s;
140
141        s = src[c];
142        d = (uint8_t*) dst + c * ss;
143
144        for (j = 0; j < n; j ++) {
145            memcpy(d, s, (int) ss);
146            s = (uint8_t*) s + ss;
147            d = (uint8_t*) d + fs;
148        }
149    }
150}
151
152void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
153    size_t fs;
154    unsigned c;
155
156    pa_assert(src);
157    pa_assert(dst);
158    pa_assert(channels > 0);
159    pa_assert(ss > 0);
160    pa_assert(n > 0);
161
162    fs = ss * channels;
163
164    for (c = 0; c < channels; c++) {
165        unsigned j;
166        const void *s;
167        void *d;
168
169        s = (uint8_t*) src + c * ss;
170        d = dst[c];
171
172        for (j = 0; j < n; j ++) {
173            memcpy(d, s, (int) ss);
174            s = (uint8_t*) s + fs;
175            d = (uint8_t*) d + ss;
176        }
177    }
178}
179
180static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
181    pa_memblock *b;
182    size_t length;
183    void *data;
184
185    pa_assert(pool);
186
187    length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);
188
189    b = pa_memblock_new(pool, length);
190
191    data = pa_memblock_acquire(b);
192    memset(data, c, length);
193    pa_memblock_release(b);
194
195    pa_memblock_set_is_silence(b, true);
196
197    return b;
198}
199
200void pa_silence_cache_init(pa_silence_cache *cache) {
201    pa_assert(cache);
202
203    memset(cache, 0, sizeof(pa_silence_cache));
204}
205
206void pa_silence_cache_done(pa_silence_cache *cache) {
207    pa_sample_format_t f;
208    pa_assert(cache);
209
210    for (f = 0; f < PA_SAMPLE_MAX; f++)
211        if (cache->blocks[f])
212            pa_memblock_unref(cache->blocks[f]);
213
214    memset(cache, 0, sizeof(pa_silence_cache));
215}
216
217pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length) {
218    pa_memblock *b;
219    size_t l;
220
221    pa_assert(cache);
222    pa_assert(pa_sample_spec_valid(spec));
223
224    if (!(b = cache->blocks[spec->format]))
225
226        switch (spec->format) {
227            case PA_SAMPLE_U8:
228                cache->blocks[PA_SAMPLE_U8] = b = silence_memblock_new(pool, 0x80);
229                break;
230            case PA_SAMPLE_S16LE:
231            case PA_SAMPLE_S16BE:
232            case PA_SAMPLE_S32LE:
233            case PA_SAMPLE_S32BE:
234            case PA_SAMPLE_S24LE:
235            case PA_SAMPLE_S24BE:
236            case PA_SAMPLE_S24_32LE:
237            case PA_SAMPLE_S24_32BE:
238            case PA_SAMPLE_FLOAT32LE:
239            case PA_SAMPLE_FLOAT32BE:
240                cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
241                cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
242                cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
243                cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
244                cache->blocks[PA_SAMPLE_S24LE] = pa_memblock_ref(b);
245                cache->blocks[PA_SAMPLE_S24BE] = pa_memblock_ref(b);
246                cache->blocks[PA_SAMPLE_S24_32LE] = pa_memblock_ref(b);
247                cache->blocks[PA_SAMPLE_S24_32BE] = pa_memblock_ref(b);
248                cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
249                cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
250                break;
251            case PA_SAMPLE_ALAW:
252                cache->blocks[PA_SAMPLE_ALAW] = b = silence_memblock_new(pool, 0xd5);
253                break;
254            case PA_SAMPLE_ULAW:
255                cache->blocks[PA_SAMPLE_ULAW] = b = silence_memblock_new(pool, 0xff);
256                break;
257            default:
258                pa_assert_not_reached();
259    }
260
261    pa_assert(b);
262
263    ret->memblock = pa_memblock_ref(b);
264
265    l = pa_memblock_get_length(b);
266    if (length > l || length == 0)
267        length = l;
268
269    ret->length = pa_frame_align(length, spec);
270    ret->index = 0;
271
272    return ret;
273}
274
275void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n) {
276    const float *s;
277    float *d;
278
279    s = src; d = dst;
280
281    if (format == PA_SAMPLE_FLOAT32NE) {
282        for (; n > 0; n--) {
283            float f;
284
285            f = *s;
286            *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
287
288            s = (const float*) ((const uint8_t*) s + sstr);
289            d = (float*) ((uint8_t*) d + dstr);
290        }
291    } else {
292        pa_assert(format == PA_SAMPLE_FLOAT32RE);
293
294        for (; n > 0; n--) {
295            float f;
296
297            f = PA_READ_FLOAT32RE(s);
298            f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
299            PA_WRITE_FLOAT32RE(d, f);
300
301            s = (const float*) ((const uint8_t*) s + sstr);
302            d = (float*) ((uint8_t*) d + dstr);
303        }
304    }
305}
306
307/* Similar to pa_bytes_to_usec() but rounds up, not down */
308
309pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec) {
310    size_t fs;
311    pa_usec_t usec;
312
313    pa_assert(spec);
314
315    fs = pa_frame_size(spec);
316    length = (length + fs - 1) / fs;
317
318    usec = (pa_usec_t) length * PA_USEC_PER_SEC;
319
320    return (usec + spec->rate - 1) / spec->rate;
321}
322
323/* Similar to pa_usec_to_bytes() but rounds up, not down */
324
325size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec) {
326    uint64_t u;
327    pa_assert(spec);
328
329    u = (uint64_t) t * (uint64_t) spec->rate;
330
331    u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC;
332
333    u *= pa_frame_size(spec);
334
335    return (size_t) u;
336}
337
338void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
339    FILE *f;
340    void *p;
341
342    pa_assert(c);
343    pa_assert(fn);
344
345    /* Only for debugging purposes */
346
347    f = pa_fopen_cloexec(fn, "a");
348
349    if (!f) {
350        pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
351        return;
352    }
353
354    p = pa_memblock_acquire(c->memblock);
355
356    if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length)
357        pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno));
358
359    pa_memblock_release(c->memblock);
360
361    fclose(f);
362}
363
364static void calc_sine(float *f, size_t l, double freq) {
365    size_t i;
366
367    l /= sizeof(float);
368
369    for (i = 0; i < l; i++)
370        *(f++) = (float) 0.5f * sin((double) i*M_PI*2*freq / (double) l);
371}
372
373void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) {
374    size_t l;
375    unsigned gcd, n;
376    void *p;
377
378    pa_memchunk_reset(c);
379
380    gcd = pa_gcd(rate, freq);
381    n = rate / gcd;
382
383    l = pa_mempool_block_size_max(pool) / sizeof(float);
384
385    l /= n;
386    if (l <= 0) l = 1;
387    l *= n;
388
389    c->length = l * sizeof(float);
390    c->memblock = pa_memblock_new(pool, c->length);
391
392    p = pa_memblock_acquire(c->memblock);
393    calc_sine(p, c->length, freq * l / rate);
394    pa_memblock_release(c->memblock);
395}
396
397size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) {
398    pa_usec_t usec;
399
400    pa_assert(from);
401    pa_assert(to);
402
403    usec = pa_bytes_to_usec_round_up(size, from);
404    return pa_usec_to_bytes_round_up(usec, to);
405}
406