~ubuntu-branches/ubuntu/gutsy/vorbis-tools/gutsy

« back to all changes in this revision

Viewing changes to oggenc/resample.c

  • Committer: Bazaar Package Importer
  • Author(s): Jesus Climent
  • Date: 2005-04-10 09:22:24 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050410092224-xtukpa3qghghhjje
Tags: 1.0.1-1.3
* Authorized NMU.
* Modified alsa to mention alsa09 (although the device might be nowadays
  alsa, back, since alsa1.0 has been already released). (Closes: #258286)
* Modified the manpage/help message for vorbiscomment to make it a bit more
  userfiendly: Closes: #252531.
* Added oggdec to the long description field, so that it triggers apt-cache
  searches: Closes: #274894.
* Typos in manpages: Closes: #302150.
* Escaped dashes in manpage: Closes: #264365.
* Quiet option is actually with -Q, not -q (Closes: #211289) Reported
  upstream but patched for Debian.
* Change input.wav with inputfile, since we accept flac-formated files:
  Closes: #262509.
* Translation bits:
  * Updated translation hu.po: Closes: #272037.
  * French translation correction: Encodage -> Codage (Closes: #248431).
  * debian/rules: remove .gmo's to avoid clash with uploaded tarball.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* resample.c: see resample.h for interesting stuff */
 
2
 
 
3
#include <math.h>
 
4
#include <stdlib.h>
 
5
#include <string.h>
 
6
#include <stdarg.h>
 
7
#include <assert.h>
 
8
 
 
9
#include "resample.h"
 
10
 
 
11
/* Some systems don't define this */
 
12
#ifndef M_PI
 
13
#define M_PI       3.14159265358979323846 
 
14
#endif
 
15
 
 
16
static int hcf(int arg1, int arg2)
 
17
{
 
18
        int mult = 1;
 
19
 
 
20
        while (~(arg1 | arg2) & 1)
 
21
                arg1 >>= 1, arg2 >>= 1, mult <<= 1;
 
22
 
 
23
        while (arg1 > 0)
 
24
        {
 
25
                if (~(arg1 & arg2) & 1)
 
26
                {
 
27
                        arg1 >>= (~arg1 & 1);
 
28
                        arg2 >>= (~arg2 & 1);
 
29
                }
 
30
                else if (arg1 < arg2)
 
31
                        arg2 = (arg2 - arg1) >> 1;
 
32
                else
 
33
                        arg1 = (arg1 - arg2) >> 1;
 
34
        }
 
35
 
 
36
        return arg2 * mult;
 
37
}
 
38
 
 
39
 
 
40
static void filt_sinc(float *dest, int N, int step, double fc, double gain, int width)
 
41
{
 
42
        double s = fc / step;
 
43
        int mid, x;
 
44
        float *endpoint = dest + N,
 
45
                *base = dest,
 
46
                *origdest = dest;
 
47
        
 
48
        assert(width <= N);
 
49
 
 
50
        if ((N & 1) == 0)
 
51
        {
 
52
                *dest = 0.0;
 
53
                dest += width;
 
54
                if (dest >= endpoint)
 
55
                        dest = ++base;
 
56
                N--;
 
57
        }
 
58
 
 
59
        mid = N / 2;
 
60
        x = -mid;
 
61
 
 
62
        while (N--)
 
63
        {
 
64
                *dest = (x ? sin(x * M_PI * s) / (x * M_PI) * step : fc) * gain;
 
65
                x++;
 
66
                dest += width;
 
67
                if (dest >= endpoint)
 
68
                        dest = ++base;
 
69
        }
 
70
        assert(dest == origdest + width);
 
71
}
 
72
 
 
73
 
 
74
static double I_zero(double x)
 
75
{
 
76
        int n = 0;
 
77
        double u = 1.0,
 
78
                s = 1.0,
 
79
                t;
 
80
 
 
81
        do
 
82
        {
 
83
                n += 2;
 
84
                t = x / n;
 
85
                u *= t * t;
 
86
                s += u;
 
87
        } while (u > 1e-21 * s);
 
88
 
 
89
        return s;
 
90
}
 
91
 
 
92
 
 
93
static void win_kaiser(float *dest, int N, double alpha, int width)
 
94
{
 
95
        double I_alpha, midsq;
 
96
        int x;
 
97
        float *endpoint = dest + N,
 
98
                *base = dest,
 
99
                *origdest = dest;
 
100
 
 
101
        assert(width <= N);
 
102
 
 
103
        if ((N & 1) == 0)
 
104
        {
 
105
                *dest = 0.0;
 
106
                dest += width;
 
107
                if (dest >= endpoint)
 
108
                        dest = ++base;
 
109
                N--;
 
110
        }
 
111
 
 
112
        x = -(N / 2);
 
113
        midsq = (double)(x - 1) * (double)(x - 1);
 
114
        I_alpha = I_zero(alpha);
 
115
 
 
116
        while (N--)
 
117
        {
 
118
                *dest *= I_zero(alpha * sqrt(1.0 - ((double)x * (double)x) / midsq)) / I_alpha;
 
119
                x++;
 
120
                dest += width;
 
121
                if (dest >= endpoint)
 
122
                        dest = ++base;
 
123
        }
 
124
        assert(dest == origdest + width);
 
125
}
 
126
 
 
127
 
 
128
int res_init(res_state *state, int channels, int outfreq, int infreq, res_parameter op1, ...)
 
129
{
 
130
        double beta = 16.0,
 
131
                cutoff = 0.80,
 
132
                gain = 1.0;
 
133
        int taps = 45;
 
134
 
 
135
        int factor;
 
136
 
 
137
        assert(state);
 
138
        assert(channels > 0);
 
139
        assert(outfreq > 0);
 
140
        assert(infreq > 0);
 
141
        assert(taps > 0);
 
142
 
 
143
        if (state == NULL || channels <= 0 || outfreq <= 0 || infreq <= 0 || taps <= 0)
 
144
                return -1;
 
145
 
 
146
        if (op1 != RES_END)
 
147
        {
 
148
                va_list argp;
 
149
                va_start(argp, op1);
 
150
                do
 
151
                {
 
152
                        switch (op1)
 
153
                        {
 
154
                        case RES_GAIN:
 
155
                                gain = va_arg(argp, double);
 
156
                                break;
 
157
 
 
158
                        case RES_CUTOFF:
 
159
                                cutoff = va_arg(argp, double);
 
160
                                assert(cutoff > 0.01 && cutoff <= 1.0);
 
161
                                break;
 
162
 
 
163
                        case RES_TAPS:
 
164
                                taps = va_arg(argp, int);
 
165
                                assert(taps > 2 && taps < 1000);
 
166
                                break;
 
167
                                
 
168
                        case RES_BETA:
 
169
                                beta = va_arg(argp, double);
 
170
                                assert(beta > 2.0);
 
171
                                break;
 
172
                        default:
 
173
                                assert("arglist" == "valid");
 
174
                                return -1;
 
175
                        }
 
176
                        op1 = va_arg(argp, res_parameter);
 
177
                } while (op1 != RES_END);
 
178
                va_end(argp);
 
179
        }
 
180
 
 
181
        factor = hcf(infreq, outfreq);
 
182
        outfreq /= factor;
 
183
        infreq /= factor;
 
184
 
 
185
        /* adjust to rational values for downsampling */
 
186
        if (outfreq < infreq)
 
187
        {
 
188
                /* push the cutoff frequency down to the output frequency */
 
189
                cutoff = cutoff * outfreq / infreq; 
 
190
 
 
191
        /* compensate for the sharper roll-off requirement
 
192
         * by using a bigger hammer */
 
193
        taps = taps * infreq/outfreq;
 
194
        }
 
195
 
 
196
        assert(taps >= (infreq + outfreq - 1) / outfreq);
 
197
 
 
198
        if ((state->table = calloc(outfreq * taps, sizeof(float))) == NULL)
 
199
                return -1;
 
200
        if ((state->pool = calloc(channels * taps, sizeof(SAMPLE))) == NULL)
 
201
        {
 
202
                free(state->table);
 
203
                state->table = NULL;
 
204
                return -1;
 
205
        }
 
206
 
 
207
        state->poolfill = taps / 2 + 1;
 
208
        state->channels = channels;
 
209
        state->outfreq = outfreq;
 
210
        state->infreq = infreq;
 
211
        state->taps = taps;
 
212
        state->offset = 0;
 
213
 
 
214
        filt_sinc(state->table, outfreq * taps, outfreq, cutoff, gain, taps);
 
215
        win_kaiser(state->table, outfreq * taps, beta, taps);
 
216
 
 
217
        return 0;
 
218
}
 
219
 
 
220
 
 
221
static SAMPLE sum(float const *scale, int count, SAMPLE const *source, SAMPLE const *trigger, SAMPLE const *reset, int srcstep)
 
222
{
 
223
        float total = 0.0;
 
224
 
 
225
        while (count--)
 
226
        {
 
227
                total += *source * *scale;
 
228
 
 
229
                if (source == trigger)
 
230
                        source = reset, srcstep = 1;
 
231
                source -= srcstep;
 
232
                scale++;
 
233
        }
 
234
 
 
235
        return total;
 
236
}
 
237
 
 
238
 
 
239
static int push(res_state const * const state, SAMPLE *pool, int * const poolfill, int * const offset, SAMPLE *dest, int dststep, SAMPLE const *source, int srcstep, size_t srclen)
 
240
{
 
241
        SAMPLE  * const destbase = dest,
 
242
                *poolhead = pool + *poolfill,
 
243
                *poolend = pool + state->taps,
 
244
                *newpool = pool;
 
245
        SAMPLE const *refill, *base, *endpoint;
 
246
        int     lencheck;
 
247
 
 
248
 
 
249
        assert(state);
 
250
        assert(pool);
 
251
        assert(poolfill);
 
252
        assert(dest);
 
253
        assert(source);
 
254
 
 
255
        assert(state->poolfill != -1);
 
256
        
 
257
        lencheck = res_push_check(state, srclen);
 
258
 
 
259
        /* fill the pool before diving in */
 
260
        while (poolhead < poolend && srclen > 0)
 
261
        {
 
262
                *poolhead++ = *source;
 
263
                source += srcstep;
 
264
                srclen--;
 
265
        }
 
266
 
 
267
        if (srclen <= 0)
 
268
                return 0;
 
269
 
 
270
        base = source;
 
271
        endpoint = source + srclen * srcstep;
 
272
 
 
273
        while (source < endpoint)
 
274
        {
 
275
                *dest = sum(state->table + *offset * state->taps, state->taps, source, base, poolend, srcstep);
 
276
                dest += dststep;
 
277
                *offset += state->infreq;
 
278
                while (*offset >= state->outfreq)
 
279
                {
 
280
                        *offset -= state->outfreq;
 
281
                        source += srcstep;
 
282
                }
 
283
        }
 
284
 
 
285
        assert(dest == destbase + lencheck * dststep);
 
286
 
 
287
        /* pretend that source has that underrun data we're not going to get */
 
288
        srclen += (source - endpoint) / srcstep;
 
289
 
 
290
        /* if we didn't get enough to completely replace the pool, then shift things about a bit */
 
291
        if (srclen < state->taps)
 
292
        {
 
293
                refill = pool + srclen;
 
294
                while (refill < poolend)
 
295
                        *newpool++ = *refill++;
 
296
 
 
297
                refill = source - srclen * srcstep;
 
298
        }
 
299
        else
 
300
                refill = source - state->taps * srcstep;
 
301
 
 
302
        /* pull in fresh pool data */
 
303
        while (refill < endpoint)
 
304
        {
 
305
                *newpool++ = *refill;
 
306
                refill += srcstep;
 
307
        }
 
308
 
 
309
        assert(newpool > pool);
 
310
        assert(newpool <= poolend);
 
311
 
 
312
        *poolfill = newpool - pool;
 
313
 
 
314
        return (dest - destbase) / dststep;
 
315
}
 
316
 
 
317
 
 
318
int res_push_max_input(res_state const * const state, size_t maxoutput)
 
319
{
 
320
        return maxoutput * state->infreq / state->outfreq;
 
321
}
 
322
 
 
323
 
 
324
int res_push_check(res_state const * const state, size_t srclen)
 
325
{
 
326
        if (state->poolfill < state->taps)
 
327
                srclen -= state->taps - state->poolfill;
 
328
 
 
329
        return (srclen * state->outfreq - state->offset + state->infreq - 1) / state->infreq;
 
330
}
 
331
 
 
332
 
 
333
int res_push(res_state *state, SAMPLE **dstlist, SAMPLE const **srclist, size_t srclen)
 
334
{
 
335
        int result = -1, poolfill = -1, offset = -1, i;
 
336
 
 
337
        assert(state);
 
338
        assert(dstlist);
 
339
        assert(srclist);
 
340
        assert(state->poolfill >= 0);
 
341
 
 
342
        for (i = 0; i < state->channels; i++)
 
343
        {
 
344
                poolfill = state->poolfill;
 
345
                offset = state->offset;
 
346
                result = push(state, state->pool + i * state->taps, &poolfill, &offset, dstlist[i], 1, srclist[i], 1, srclen);
 
347
        }
 
348
        state->poolfill = poolfill;
 
349
        state->offset = offset;
 
350
 
 
351
        return result;
 
352
}
 
353
 
 
354
 
 
355
int res_push_interleaved(res_state *state, SAMPLE *dest, SAMPLE const *source, size_t srclen)
 
356
{
 
357
        int result = -1, poolfill = -1, offset = -1, i;
 
358
        
 
359
        assert(state);
 
360
        assert(dest);
 
361
        assert(source);
 
362
        assert(state->poolfill >= 0);
 
363
 
 
364
        for (i = 0; i < state->channels; i++)
 
365
        {
 
366
                poolfill = state->poolfill;
 
367
                offset = state->offset;
 
368
                result = push(state, state->pool + i * state->taps, &poolfill, &offset, dest + i, state->channels, source + i, state->channels, srclen);
 
369
        }
 
370
        state->poolfill = poolfill;
 
371
        state->offset = offset;
 
372
 
 
373
        return result;
 
374
}
 
375
 
 
376
 
 
377
int res_drain(res_state *state, SAMPLE **dstlist)
 
378
{
 
379
        SAMPLE *tail;
 
380
        int result = -1, poolfill = -1, offset = -1, i;
 
381
 
 
382
        assert(state);
 
383
        assert(dstlist);
 
384
        assert(state->poolfill >= 0);
 
385
 
 
386
        if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
 
387
                return -1;
 
388
 
 
389
        for (i = 0; i < state->channels; i++)
 
390
        {
 
391
                poolfill = state->poolfill;
 
392
                offset = state->offset;
 
393
                result = push(state, state->pool + i * state->taps, &poolfill, &offset, dstlist[i], 1, tail, 1, state->taps / 2 - 1);
 
394
        }
 
395
                
 
396
        free(tail);
 
397
 
 
398
        state->poolfill = -1;
 
399
 
 
400
        return result;
 
401
}
 
402
 
 
403
 
 
404
int res_drain_interleaved(res_state *state, SAMPLE *dest)
 
405
{
 
406
        SAMPLE *tail;
 
407
        int result = -1, poolfill = -1, offset = -1, i;
 
408
 
 
409
        assert(state);
 
410
        assert(dest);
 
411
        assert(state->poolfill >= 0);
 
412
 
 
413
        if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
 
414
                return -1;
 
415
 
 
416
        for (i = 0; i < state->channels; i++)
 
417
        {
 
418
                poolfill = state->poolfill;
 
419
                offset = state->offset;
 
420
                result = push(state, state->pool + i * state->taps, &poolfill, &offset, dest + i, state->channels, tail, 1, state->taps / 2 - 1);
 
421
        }
 
422
                
 
423
        free(tail);
 
424
 
 
425
        state->poolfill = -1;
 
426
 
 
427
        return result;
 
428
}
 
429
 
 
430
 
 
431
void res_clear(res_state *state)
 
432
{
 
433
        assert(state);
 
434
        assert(state->table);
 
435
        assert(state->pool);
 
436
 
 
437
        free(state->table);
 
438
        free(state->pool);
 
439
        memset(state, 0, sizeof(*state));
 
440
}
 
441