Recognizes if input is ogg or not.
[xiph.git] / vorbis-tools / oggenc / resample.c
blob68cc42f76e8c8e61ba4db34c51435d91672f8b78
1 /* resample.c: see resample.h for interesting stuff */
3 #ifdef HAVE_CONFIG_H
4 #include <config.h>
5 #endif
7 #include <math.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <assert.h>
13 #include "resample.h"
15 /* Some systems don't define this */
16 #ifndef M_PI
17 #define M_PI 3.14159265358979323846
18 #endif
20 static int hcf(int arg1, int arg2)
22 int mult = 1;
24 while (~(arg1 | arg2) & 1)
25 arg1 >>= 1, arg2 >>= 1, mult <<= 1;
27 while (arg1 > 0)
29 if (~(arg1 & arg2) & 1)
31 arg1 >>= (~arg1 & 1);
32 arg2 >>= (~arg2 & 1);
34 else if (arg1 < arg2)
35 arg2 = (arg2 - arg1) >> 1;
36 else
37 arg1 = (arg1 - arg2) >> 1;
40 return arg2 * mult;
44 static void filt_sinc(float *dest, int N, int step, double fc, double gain, int width)
46 double s = fc / step;
47 int mid, x;
48 float *endpoint = dest + N,
49 *base = dest,
50 *origdest = dest;
52 assert(width <= N);
54 if ((N & 1) == 0)
56 *dest = 0.0;
57 dest += width;
58 if (dest >= endpoint)
59 dest = ++base;
60 N--;
63 mid = N / 2;
64 x = -mid;
66 while (N--)
68 *dest = (x ? sin(x * M_PI * s) / (x * M_PI) * step : fc) * gain;
69 x++;
70 dest += width;
71 if (dest >= endpoint)
72 dest = ++base;
74 assert(dest == origdest + width);
78 static double I_zero(double x)
80 int n = 0;
81 double u = 1.0,
82 s = 1.0,
87 n += 2;
88 t = x / n;
89 u *= t * t;
90 s += u;
91 } while (u > 1e-21 * s);
93 return s;
97 static void win_kaiser(float *dest, int N, double alpha, int width)
99 double I_alpha, midsq;
100 int x;
101 float *endpoint = dest + N,
102 *base = dest,
103 *origdest = dest;
105 assert(width <= N);
107 if ((N & 1) == 0)
109 *dest = 0.0;
110 dest += width;
111 if (dest >= endpoint)
112 dest = ++base;
113 N--;
116 x = -(N / 2);
117 midsq = (double)(x - 1) * (double)(x - 1);
118 I_alpha = I_zero(alpha);
120 while (N--)
122 *dest *= I_zero(alpha * sqrt(1.0 - ((double)x * (double)x) / midsq)) / I_alpha;
123 x++;
124 dest += width;
125 if (dest >= endpoint)
126 dest = ++base;
128 assert(dest == origdest + width);
132 int res_init(res_state *state, int channels, int outfreq, int infreq, res_parameter op1, ...)
134 double beta = 16.0,
135 cutoff = 0.80,
136 gain = 1.0;
137 int taps = 45;
139 int factor;
141 assert(state);
142 assert(channels > 0);
143 assert(outfreq > 0);
144 assert(infreq > 0);
145 assert(taps > 0);
147 if (state == NULL || channels <= 0 || outfreq <= 0 || infreq <= 0 || taps <= 0)
148 return -1;
150 if (op1 != RES_END)
152 va_list argp;
153 va_start(argp, op1);
156 switch (op1)
158 case RES_GAIN:
159 gain = va_arg(argp, double);
160 break;
162 case RES_CUTOFF:
163 cutoff = va_arg(argp, double);
164 assert(cutoff > 0.01 && cutoff <= 1.0);
165 break;
167 case RES_TAPS:
168 taps = va_arg(argp, int);
169 assert(taps > 2 && taps < 1000);
170 break;
172 case RES_BETA:
173 beta = va_arg(argp, double);
174 assert(beta > 2.0);
175 break;
176 default:
177 assert("arglist" == "valid");
178 return -1;
180 op1 = va_arg(argp, res_parameter);
181 } while (op1 != RES_END);
182 va_end(argp);
185 factor = hcf(infreq, outfreq);
186 outfreq /= factor;
187 infreq /= factor;
189 /* adjust to rational values for downsampling */
190 if (outfreq < infreq)
192 /* push the cutoff frequency down to the output frequency */
193 cutoff = cutoff * outfreq / infreq;
195 /* compensate for the sharper roll-off requirement
196 * by using a bigger hammer */
197 taps = taps * infreq/outfreq;
200 assert(taps >= (infreq + outfreq - 1) / outfreq);
202 if ((state->table = calloc(outfreq * taps, sizeof(float))) == NULL)
203 return -1;
204 if ((state->pool = calloc(channels * taps, sizeof(SAMPLE))) == NULL)
206 free(state->table);
207 state->table = NULL;
208 return -1;
211 state->poolfill = taps / 2 + 1;
212 state->channels = channels;
213 state->outfreq = outfreq;
214 state->infreq = infreq;
215 state->taps = taps;
216 state->offset = 0;
218 filt_sinc(state->table, outfreq * taps, outfreq, cutoff, gain, taps);
219 win_kaiser(state->table, outfreq * taps, beta, taps);
221 return 0;
225 static SAMPLE sum(float const *scale, int count, SAMPLE const *source, SAMPLE const *trigger, SAMPLE const *reset, int srcstep)
227 float total = 0.0;
229 while (count--)
231 total += *source * *scale;
233 if (source == trigger)
234 source = reset, srcstep = 1;
235 source -= srcstep;
236 scale++;
239 return total;
243 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)
245 SAMPLE * const destbase = dest,
246 *poolhead = pool + *poolfill,
247 *poolend = pool + state->taps,
248 *newpool = pool;
249 SAMPLE const *refill, *base, *endpoint;
250 int lencheck;
253 assert(state);
254 assert(pool);
255 assert(poolfill);
256 assert(dest);
257 assert(source);
259 assert(state->poolfill != -1);
261 lencheck = res_push_check(state, srclen);
263 /* fill the pool before diving in */
264 while (poolhead < poolend && srclen > 0)
266 *poolhead++ = *source;
267 source += srcstep;
268 srclen--;
271 if (srclen <= 0)
272 return 0;
274 base = source;
275 endpoint = source + srclen * srcstep;
277 while (source < endpoint)
279 *dest = sum(state->table + *offset * state->taps, state->taps, source, base, poolend, srcstep);
280 dest += dststep;
281 *offset += state->infreq;
282 while (*offset >= state->outfreq)
284 *offset -= state->outfreq;
285 source += srcstep;
289 assert(dest == destbase + lencheck * dststep);
291 /* pretend that source has that underrun data we're not going to get */
292 srclen += (source - endpoint) / srcstep;
294 /* if we didn't get enough to completely replace the pool, then shift things about a bit */
295 if (srclen < state->taps)
297 refill = pool + srclen;
298 while (refill < poolend)
299 *newpool++ = *refill++;
301 refill = source - srclen * srcstep;
303 else
304 refill = source - state->taps * srcstep;
306 /* pull in fresh pool data */
307 while (refill < endpoint)
309 *newpool++ = *refill;
310 refill += srcstep;
313 assert(newpool > pool);
314 assert(newpool <= poolend);
316 *poolfill = newpool - pool;
318 return (dest - destbase) / dststep;
322 int res_push_max_input(res_state const * const state, size_t maxoutput)
324 return maxoutput * state->infreq / state->outfreq;
328 int res_push_check(res_state const * const state, size_t srclen)
330 if (state->poolfill < state->taps)
331 srclen -= state->taps - state->poolfill;
333 return (srclen * state->outfreq - state->offset + state->infreq - 1) / state->infreq;
337 int res_push(res_state *state, SAMPLE **dstlist, SAMPLE const **srclist, size_t srclen)
339 int result = -1, poolfill = -1, offset = -1, i;
341 assert(state);
342 assert(dstlist);
343 assert(srclist);
344 assert(state->poolfill >= 0);
346 for (i = 0; i < state->channels; i++)
348 poolfill = state->poolfill;
349 offset = state->offset;
350 result = push(state, state->pool + i * state->taps, &poolfill, &offset, dstlist[i], 1, srclist[i], 1, srclen);
352 state->poolfill = poolfill;
353 state->offset = offset;
355 return result;
359 int res_push_interleaved(res_state *state, SAMPLE *dest, SAMPLE const *source, size_t srclen)
361 int result = -1, poolfill = -1, offset = -1, i;
363 assert(state);
364 assert(dest);
365 assert(source);
366 assert(state->poolfill >= 0);
368 for (i = 0; i < state->channels; i++)
370 poolfill = state->poolfill;
371 offset = state->offset;
372 result = push(state, state->pool + i * state->taps, &poolfill, &offset, dest + i, state->channels, source + i, state->channels, srclen);
374 state->poolfill = poolfill;
375 state->offset = offset;
377 return result;
381 int res_drain(res_state *state, SAMPLE **dstlist)
383 SAMPLE *tail;
384 int result = -1, poolfill = -1, offset = -1, i;
386 assert(state);
387 assert(dstlist);
388 assert(state->poolfill >= 0);
390 if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
391 return -1;
393 for (i = 0; i < state->channels; i++)
395 poolfill = state->poolfill;
396 offset = state->offset;
397 result = push(state, state->pool + i * state->taps, &poolfill, &offset, dstlist[i], 1, tail, 1, state->taps / 2 - 1);
400 free(tail);
402 state->poolfill = -1;
404 return result;
408 int res_drain_interleaved(res_state *state, SAMPLE *dest)
410 SAMPLE *tail;
411 int result = -1, poolfill = -1, offset = -1, i;
413 assert(state);
414 assert(dest);
415 assert(state->poolfill >= 0);
417 if ((tail = calloc(state->taps, sizeof(SAMPLE))) == NULL)
418 return -1;
420 for (i = 0; i < state->channels; i++)
422 poolfill = state->poolfill;
423 offset = state->offset;
424 result = push(state, state->pool + i * state->taps, &poolfill, &offset, dest + i, state->channels, tail, 1, state->taps / 2 - 1);
427 free(tail);
429 state->poolfill = -1;
431 return result;
435 void res_clear(res_state *state)
437 assert(state);
438 assert(state->table);
439 assert(state->pool);
441 free(state->table);
442 free(state->pool);
443 memset(state, 0, sizeof(*state));