From 913a1742b960b8cb705132d1ebfcf0718bb994e7 Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin Date: Sat, 29 Jan 2011 10:00:20 -0500 Subject: [PATCH] Adding resampling support We use the MDCT as low-pass filter. --- libcelt/celt.c | 118 +++++++++++++++++++++++++++++++++++++++++-------- libcelt/celt.h | 8 ++-- 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/libcelt/celt.c b/libcelt/celt.c index 66bf4018..58d53eb1 100644 --- a/libcelt/celt.c +++ b/libcelt/celt.c @@ -63,6 +63,32 @@ static const unsigned char tapset_icdf[3]={2,1,0}; #define COMBFILTER_MAXPERIOD 1024 #define COMBFILTER_MINPERIOD 15 +static int resampling_factor(celt_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: + ret = 0; + } + return ret; +} + /** Encoder state @brief Encoder state */ @@ -73,6 +99,7 @@ struct CELTEncoder { int force_intra; int complexity; + int upsample; int start, end; celt_int32 vbr_rate_norm; /* Target number of 8th bits per frame */ @@ -127,12 +154,13 @@ int celt_encoder_get_size(const CELTMode *mode, int channels) return size; } -CELTEncoder *celt_encoder_create(int channels, int *error) +CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error) { CELTMode *mode = celt_mode_create(48000, 960, NULL); - return celt_encoder_init( + CELTEncoder *st = celt_encoder_init( (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels)), - channels, error); + sampling_rate, channels, error); + return st; } CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int *error) @@ -142,9 +170,17 @@ CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int mode, channels, error); } -CELTEncoder *celt_encoder_init(CELTEncoder *st, int channels, int *error) +CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error) { - return celt_encoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + celt_encoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + st->upsample = resampling_factor(sampling_rate); + if (st->upsample==0) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + return st; } CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int channels, int *error) @@ -169,6 +205,7 @@ CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int st->overlap = mode->overlap; st->channels = channels; + st->upsample = 1; st->start = 0; st->end = st->mode->effEBands; st->constrained_vbr = 1; @@ -385,10 +422,11 @@ static void compute_inv_mdcts(const CELTMode *mode, int shortBlocks, celt_sig *X } while (++cupsample; for (LM=0;LM<4;LM++) if (st->mode->shortMdctSize<overlap)+st->overlap; for (i=0;iupsample) + { + count=0; + pcmp+=C; + } else { + x = 0; + } /* Apply pre-emphasis */ - celt_sig tmp = MULT16_16(st->mode->preemph[2], SCALEIN(*pcmp)); + tmp = MULT16_16(st->mode->preemph[2], x); *inp = tmp + st->preemph_memE[c]; st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp) - MULT16_32_Q15(st->mode->preemph[0], tmp); silence = silence && *inp == 0; inp++; - pcmp+=C; } CELT_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); CELT_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N); @@ -1082,6 +1137,17 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i /* Compute MDCTs */ compute_mdcts(st->mode, shortBlocks, in, freq, C, LM); + if (st->upsample != 1) + { + c=0; do + { + int bound = N/st->upsample; + for (i=0;iupsample; + for (;imode, freq, bandE, effEnd, C, M); @@ -1412,7 +1478,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i } while (++cmode->preemph, st->preemph_memD); + deemphasis(out_mem, (celt_word16*)pcm, N, C, st->upsample, st->mode->preemph, st->preemph_memD); st->prefilter_period_old = st->prefilter_period; st->prefilter_gain_old = st->prefilter_gain; st->prefilter_tapset_old = st->prefilter_tapset; @@ -1651,6 +1717,7 @@ struct CELTDecoder { int overlap; int channels; + int downsample; int start, end; /* Everything beyond this point gets cleared on a reset */ @@ -1685,12 +1752,12 @@ int celt_decoder_get_size(const CELTMode *mode, int channels) return size; } -CELTDecoder *celt_decoder_create(int channels, int *error) +CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error) { const CELTMode *mode = celt_mode_create(48000, 960, NULL); return celt_decoder_init( (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels)), - channels, error); + sampling_rate, channels, error); } CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int *error) @@ -1700,9 +1767,17 @@ CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int mode, channels, error); } -CELTDecoder *celt_decoder_init(CELTDecoder *st, int channels, int *error) +CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error) { - return celt_decoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + celt_decoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + return st; } CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error) @@ -1727,6 +1802,7 @@ CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int st->overlap = mode->overlap; st->channels = channels; + st->downsample = 1; st->start = 0; st->end = st->mode->effEBands; @@ -1955,7 +2031,7 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p out_mem[c][MAX_PERIOD+i] = e[i]; } while (++cmode->preemph, st->preemph_memD); + deemphasis(out_syn, pcm, N, C, st->downsample, st->mode->preemph, st->preemph_memD); st->loss_count++; @@ -2015,6 +2091,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da if (pcm==NULL) return CELT_BAD_ARG; + frame_size *= st->downsample; for (LM=0;LM<4;LM++) if (st->mode->shortMdctSize<mode->eBands[st->start];i++) freq[c*N+i] = 0; while (++cmode->eBands[effEnd]; + if (st->downsample!=1) + bound = IMIN(bound, N/st->downsample); for (i=M*st->mode->eBands[effEnd];irng = dec->rng; - deemphasis(out_syn, pcm, N, C, st->mode->preemph, st->preemph_memD); + deemphasis(out_syn, pcm, N, C, st->downsample, st->mode->preemph, st->preemph_memD); st->loss_count = 0; RESTORE_STACK; if (ec_dec_tell(dec,0) > 8*len || ec_dec_get_error(dec)) diff --git a/libcelt/celt.h b/libcelt/celt.h index a8270d31..ba1318f0 100644 --- a/libcelt/celt.h +++ b/libcelt/celt.h @@ -167,7 +167,7 @@ EXPORT int celt_encoder_get_size(const CELTMode *mode, int channels); @param error Returns an error code @return Newly created encoder state. */ -EXPORT CELTEncoder *celt_encoder_create(int channels, int *error); +EXPORT CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error); /** Creates a new encoder state. Each stream needs its own encoder state (can't be shared across simultaneous streams). @@ -180,7 +180,7 @@ EXPORT CELTEncoder *celt_encoder_create(int channels, int *error); */ EXPORT CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int *error); -EXPORT CELTEncoder *celt_encoder_init(CELTEncoder *st, int channels, int *error); +EXPORT CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error); EXPORT CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int channels, int *error); @@ -245,7 +245,7 @@ EXPORT int celt_decoder_get_size(const CELTMode *mode, int channels); @param error Returns an error code @return Newly created decoder state. */ -EXPORT CELTDecoder *celt_decoder_create(int channels, int *error); +EXPORT CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error); /** Creates a new decoder state. Each stream needs its own decoder state (can't be shared across simultaneous streams). @@ -257,7 +257,7 @@ EXPORT CELTDecoder *celt_decoder_create(int channels, int *error); */ EXPORT CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int *error); -EXPORT CELTDecoder *celt_decoder_init(CELTDecoder *st, int channels, int *error); +EXPORT CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error); EXPORT CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error);