1
/* resample.c: see resample.h for interesting stuff */
11
/* Some systems don't define this */
13
#define M_PI 3.14159265358979323846
16
static int hcf(int arg1, int arg2)
20
while (~(arg1 | arg2) & 1)
21
arg1 >>= 1, arg2 >>= 1, mult <<= 1;
25
if (~(arg1 & arg2) & 1)
31
arg2 = (arg2 - arg1) >> 1;
33
arg1 = (arg1 - arg2) >> 1;
40
static void filt_sinc(float *dest, int N, int step, double fc, double gain, int width)
44
float *endpoint = dest + N,
64
*dest = (x ? sin(x * M_PI * s) / (x * M_PI) * step : fc) * gain;
70
assert(dest == origdest + width);
74
static double I_zero(double x)
87
} while (u > 1e-21 * s);
93
static void win_kaiser(float *dest, int N, double alpha, int width)
95
double I_alpha, midsq;
97
float *endpoint = dest + N,
107
if (dest >= endpoint)
113
midsq = (double)(x - 1) * (double)(x - 1);
114
I_alpha = I_zero(alpha);
118
*dest *= I_zero(alpha * sqrt(1.0 - ((double)x * (double)x) / midsq)) / I_alpha;
121
if (dest >= endpoint)
124
assert(dest == origdest + width);
128
int res_init(res_state *state, int channels, int outfreq, int infreq, res_parameter op1, ...)
138
assert(channels > 0);
143
if (state == NULL || channels <= 0 || outfreq <= 0 || infreq <= 0 || taps <= 0)
155
gain = va_arg(argp, double);
159
cutoff = va_arg(argp, double);
160
assert(cutoff > 0.01 && cutoff <= 1.0);
164
taps = va_arg(argp, int);
165
assert(taps > 2 && taps < 1000);
169
beta = va_arg(argp, double);
173
assert("arglist" == "valid");
176
op1 = va_arg(argp, res_parameter);
177
} while (op1 != RES_END);
181
factor = hcf(infreq, outfreq);
185
/* adjust to rational values for downsampling */
186
if (outfreq < infreq)
188
/* push the cutoff frequency down to the output frequency */
189
cutoff = cutoff * outfreq / infreq;
191
/* compensate for the sharper roll-off requirement
192
* by using a bigger hammer */
193
taps = taps * infreq/outfreq;
196
assert(taps >= (infreq + outfreq - 1) / outfreq);
198
if ((state->table = calloc(outfreq * taps, sizeof(float))) == NULL)
200
if ((state->pool = calloc(channels * taps, sizeof(SAMPLE))) == NULL)
207
state->poolfill = taps / 2 + 1;
208
state->channels = channels;
209
state->outfreq = outfreq;
210
state->infreq = infreq;
214
filt_sinc(state->table, outfreq * taps, outfreq, cutoff, gain, taps);
215
win_kaiser(state->table, outfreq * taps, beta, taps);
221
static SAMPLE sum(float const *scale, int count, SAMPLE const *source, SAMPLE const *trigger, SAMPLE const *reset, int srcstep)
227
total += *source * *scale;
229
if (source == trigger)
230
source = reset, srcstep = 1;
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)
241
SAMPLE * const destbase = dest,
242
*poolhead = pool + *poolfill,
243
*poolend = pool + state->taps,
245
SAMPLE const *refill, *base, *endpoint;
255
assert(state->poolfill != -1);
257
lencheck = res_push_check(state, srclen);
259
/* fill the pool before diving in */
260
while (poolhead < poolend && srclen > 0)
262
*poolhead++ = *source;
271
endpoint = source + srclen * srcstep;
273
while (source < endpoint)
275
*dest = sum(state->table + *offset * state->taps, state->taps, source, base, poolend, srcstep);
277
*offset += state->infreq;
278
while (*offset >= state->outfreq)
280
*offset -= state->outfreq;
285
assert(dest == destbase + lencheck * dststep);
287
/* pretend that source has that underrun data we're not going to get */
288
srclen += (source - endpoint) / srcstep;
290
/* if we didn't get enough to completely replace the pool, then shift things about a bit */
291
if (srclen < state->taps)
293
refill = pool + srclen;
294
while (refill < poolend)
295
*newpool++ = *refill++;
297
refill = source - srclen * srcstep;
300
refill = source - state->taps * srcstep;
302
/* pull in fresh pool data */
303
while (refill < endpoint)
305
*newpool++ = *refill;
309
assert(newpool > pool);
310
assert(newpool <= poolend);
312
*poolfill = newpool - pool;
314
return (dest - destbase) / dststep;
318
int res_push_max_input(res_state const * const state, size_t maxoutput)
320
return maxoutput * state->infreq / state->outfreq;
324
int res_push_check(res_state const * const state, size_t srclen)
326
if (state->poolfill < state->taps)
327
srclen -= state->taps - state->poolfill;
329
return (srclen * state->outfreq - state->offset + state->infreq - 1) / state->infreq;
333
int res_push(res_state *state, SAMPLE **dstlist, SAMPLE const **srclist, size_t srclen)
335
int result = -1, poolfill = -1, offset = -1, i;
340
assert(state->poolfill >= 0);
342
for (i = 0; i < state->channels; i++)
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);
348
state->poolfill = poolfill;
349
state->offset = offset;
355
int res_push_interleaved(res_state *state, SAMPLE *dest, SAMPLE const *source, size_t srclen)
357
int result = -1, poolfill = -1, offset = -1, i;
362
assert(state->poolfill >= 0);
364
for (i = 0; i < state->channels; i++)
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);
370
state->poolfill = poolfill;
371
state->offset = offset;
377
int res_drain(res_state *state, SAMPLE **dstlist)
380
int result = -1, poolfill = -1, offset = -1, i;
384
assert(state->poolfill >= 0);
386
if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
389
for (i = 0; i < state->channels; i++)
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);
398
state->poolfill = -1;
404
int res_drain_interleaved(res_state *state, SAMPLE *dest)
407
int result = -1, poolfill = -1, offset = -1, i;
411
assert(state->poolfill >= 0);
413
if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
416
for (i = 0; i < state->channels; i++)
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);
425
state->poolfill = -1;
431
void res_clear(res_state *state)
434
assert(state->table);
439
memset(state, 0, sizeof(*state));