version 1.18, 2021/07/05 08:29:59 |
version 1.19, 2024/04/22 11:01:02 |
|
|
} |
} |
|
|
/* |
/* |
* resample the given number of frames |
* Return the number of input and output frame that would be consumed |
|
* by resamp_do(p, *icnt, *ocnt). |
*/ |
*/ |
void |
void |
resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo) |
resamp_getcnt(struct resamp *p, int *icnt, int *ocnt) |
{ |
{ |
|
long long idiff, odiff; |
|
int cdiff; |
|
|
|
cdiff = p->oblksz - p->diff; |
|
idiff = (long long)*icnt * p->oblksz; |
|
odiff = (long long)*ocnt * p->iblksz; |
|
if (odiff - idiff >= cdiff) |
|
*ocnt = (idiff + cdiff + p->iblksz - 1) / p->iblksz; |
|
else |
|
*icnt = (odiff + p->diff) / p->oblksz; |
|
} |
|
|
|
/* |
|
* Resample the given number of frames. The number of output frames |
|
* must match the corresponding number of input frames. Either always |
|
* use icnt and ocnt such that: |
|
* |
|
* icnt * oblksz = ocnt * iblksz |
|
* |
|
* or use resamp_getcnt() to calculate the proper numbers. |
|
*/ |
|
void |
|
resamp_do(struct resamp *p, adata_t *in, adata_t *out, int icnt, int ocnt) |
|
{ |
unsigned int nch; |
unsigned int nch; |
adata_t *idata; |
adata_t *idata; |
unsigned int oblksz; |
unsigned int oblksz; |
|
unsigned int ifr; |
int s, ds, diff; |
int s, ds, diff; |
adata_t *odata; |
adata_t *odata; |
unsigned int iblksz; |
unsigned int iblksz; |
|
unsigned int ofr; |
unsigned int c; |
unsigned int c; |
int64_t f[NCHAN_MAX]; |
int64_t f[NCHAN_MAX]; |
adata_t *ctxbuf, *ctx; |
adata_t *ctxbuf, *ctx; |
unsigned int ctx_start; |
unsigned int ctx_start; |
int q, qi, qf, n; |
int q, qi, qf, n; |
|
|
#ifdef DEBUG |
|
if (todo % p->iblksz != 0) { |
|
log_puts("resamp_do: partial blocks not supported\n"); |
|
panic(); |
|
} |
|
#endif |
|
|
|
/* |
/* |
* Partially copy structures into local variables, to avoid |
* Partially copy structures into local variables, to avoid |
* unnecessary indirections; this also allows the compiler to |
* unnecessary indirections; this also allows the compiler to |
|
|
*/ |
*/ |
idata = in; |
idata = in; |
odata = out; |
odata = out; |
diff = p->oblksz; |
diff = p->diff; |
iblksz = p->iblksz; |
iblksz = p->iblksz; |
oblksz = p->oblksz; |
oblksz = p->oblksz; |
ctxbuf = p->ctx; |
ctxbuf = p->ctx; |
ctx_start = p->ctx_start; |
ctx_start = p->ctx_start; |
nch = p->nch; |
nch = p->nch; |
|
ifr = icnt; |
|
ofr = ocnt; |
|
|
|
/* |
|
* Start conversion. |
|
*/ |
|
#ifdef DEBUG |
|
if (log_level >= 4) { |
|
log_puts("resamp: copying "); |
|
log_puti(ifr); |
|
log_puts(" -> "); |
|
log_putu(ofr); |
|
log_puts(" frames, diff = "); |
|
log_puti(diff); |
|
log_puts("\n"); |
|
} |
|
#endif |
for (;;) { |
for (;;) { |
if (diff >= oblksz) { |
if (diff >= oblksz) { |
if (todo == 0) |
if (ifr == 0) |
break; |
break; |
ctx_start = (ctx_start - 1) & (RESAMP_NCTX - 1); |
ctx_start = (ctx_start - 1) & (RESAMP_NCTX - 1); |
ctx = ctxbuf + ctx_start; |
ctx = ctxbuf + ctx_start; |
|
|
ctx += RESAMP_NCTX; |
ctx += RESAMP_NCTX; |
} |
} |
diff -= oblksz; |
diff -= oblksz; |
todo--; |
ifr--; |
} else { |
} else { |
|
if (ofr == 0) |
|
break; |
|
|
for (c = 0; c < nch; c++) |
for (c = 0; c < nch; c++) |
f[c] = 0; |
f[c] = 0; |
|
|
#endif |
#endif |
*odata++ = s; |
*odata++ = s; |
} |
} |
|
|
diff += iblksz; |
diff += iblksz; |
|
ofr--; |
} |
} |
} |
} |
|
p->diff = diff; |
p->ctx_start = ctx_start; |
p->ctx_start = ctx_start; |
|
#ifdef DEBUG |
|
if (ifr != 0) { |
|
log_puts("resamp_do: "); |
|
log_puti(ifr); |
|
log_puts(": too many input frames\n"); |
|
panic(); |
|
} |
|
if (ofr != 0) { |
|
log_puts("resamp_do: "); |
|
log_puti(ofr); |
|
log_puts(": too many output frames\n"); |
|
panic(); |
|
} |
|
#endif |
} |
} |
|
|
|
static unsigned int |
|
uint_gcd(unsigned int a, unsigned int b) |
|
{ |
|
unsigned int r; |
|
|
|
while (b > 0) { |
|
r = a % b; |
|
a = b; |
|
b = r; |
|
} |
|
return a; |
|
} |
|
|
/* |
/* |
* initialize resampler with ibufsz/obufsz factor and "nch" channels |
* initialize resampler with ibufsz/obufsz factor and "nch" channels |
*/ |
*/ |
|
|
resamp_init(struct resamp *p, unsigned int iblksz, |
resamp_init(struct resamp *p, unsigned int iblksz, |
unsigned int oblksz, int nch) |
unsigned int oblksz, int nch) |
{ |
{ |
|
unsigned int g; |
|
|
|
/* |
|
* reduce iblksz/oblksz fraction |
|
*/ |
|
g = uint_gcd(iblksz, oblksz); |
|
iblksz /= g; |
|
oblksz /= g; |
|
|
|
/* |
|
* ensure weird rates don't cause integer overflow |
|
*/ |
|
while (iblksz > ADATA_UNIT || oblksz > ADATA_UNIT) { |
|
iblksz >>= 1; |
|
oblksz >>= 1; |
|
} |
|
|
p->iblksz = iblksz; |
p->iblksz = iblksz; |
p->oblksz = oblksz; |
p->oblksz = oblksz; |
|
p->diff = 0; |
p->nch = nch; |
p->nch = nch; |
p->ctx_start = 0; |
p->ctx_start = 0; |
memset(p->ctx, 0, sizeof(p->ctx)); |
memset(p->ctx, 0, sizeof(p->ctx)); |