From bf2d648bbd7f66088c504cc9abdad0ca53a965e4 Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin Date: Fri, 23 May 2008 16:57:34 +1000 Subject: [PATCH] Implemented intensity stereo, which required changes all over the place to make sure that stereo coupling is done at the band level. Previously the stereo coupling was done all at once, but there were all kinds of interactions with the prediction and folding. --- libcelt/bands.c | 163 ++++++++++++++++++++++++++++--------------- libcelt/bands.h | 6 +- libcelt/celt.c | 22 ++---- libcelt/dump_modes.c | 1 + libcelt/modes.c | 6 +- libcelt/modes.h | 2 + libcelt/rate.c | 3 +- libcelt/vq.c | 16 +---- 8 files changed, 123 insertions(+), 96 deletions(-) diff --git a/libcelt/bands.c b/libcelt/bands.c index 05a375e8..d30876e8 100644 --- a/libcelt/bands.c +++ b/libcelt/bands.c @@ -289,8 +289,88 @@ void pitch_quant_bands(const CELTMode *m, celt_norm_t * restrict P, const celt_p P[i] = 0; } +static void intensity_band(celt_norm_t * restrict X, int len) +{ + int j; + celt_word32_t E = 1e-15; + celt_word32_t E2 = 1e-15; + for (j=0;j=0;j--) + { + X[2*j] = MULT16_16_Q15(QCONST16(.70711f,15),X[j]); + X[2*j+1] = MULT16_16_Q15(QCONST16(.70711f,15),X[j]); + } +} + +static void stereo_band_mix(const CELTMode *m, celt_norm_t *X, const celt_ener_t *bank, const int *stereo_mode, int bandID, int dir) +{ + int i = bandID; + const celt_int16_t *eBands = m->eBands; + const int C = CHANNELS(m); + { + int j; + celt_word16_t left, right; + celt_word16_t a1, a2; + celt_word16_t norm; +#ifdef FIXED_POINT + int shift = celt_zlog2(MAX32(bank[i*C], bank[i*C+1]))-13; +#endif + left = VSHR32(bank[i*C],shift); + right = VSHR32(bank[i*C+1],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = dir*DIV32_16(SHL32(EXTEND32(right),14),norm); + if (stereo_mode[i] && dir <0) + { + dup_band(X+C*eBands[i], eBands[i+1]-eBands[i]); + } else { + for (j=eBands[i];j0) + { + intensity_band(X+C*eBands[i], eBands[i+1]-eBands[i]); + } + } +} + +void stereo_decision(const CELTMode *m, celt_norm_t * restrict X, int *stereo_mode, int len) +{ + int i; + for (i=0;ieBands; @@ -336,15 +416,20 @@ void quant_bands(const CELTMode *m, celt_norm_t * restrict X, celt_norm_t *P, ce if (q > 0) { - /*int nb_rotations = q <= 2*C ? 2*C/q : 0; - if (nb_rotations != 0) + int ch=C; + if (C==2 && stereo_mode[i]==1) + ch = 1; + if (C==2) { - exp_rotation(P+C*eBands[i], C*(eBands[i+1]-eBands[i]), -1, C, nb_rotations); - exp_rotation(X+C*eBands[i], C*(eBands[i+1]-eBands[i]), -1, C, nb_rotations); - }*/ - alg_quant(X+C*eBands[i], W+C*eBands[i], C*(eBands[i+1]-eBands[i]), q, P+C*eBands[i], enc); - /*if (nb_rotations != 0) - exp_rotation(X+C*eBands[i], C*(eBands[i+1]-eBands[i]), 1, C, nb_rotations);*/ + stereo_band_mix(m, X, bandE, stereo_mode, i, 1); + stereo_band_mix(m, P, bandE, stereo_mode, i, 1); + } + alg_quant(X+C*eBands[i], W+C*eBands[i], ch*(eBands[i+1]-eBands[i]), q, P+C*eBands[i], enc); + if (C==2) + stereo_band_mix(m, X, bandE, stereo_mode, i, -1); + } else { + for (j=C*eBands[i];jeBands; @@ -394,12 +479,17 @@ void unquant_bands(const CELTMode *m, celt_norm_t * restrict X, celt_norm_t *P, if (q > 0) { - /*int nb_rotations = q <= 2*C ? 2*C/q : 0; - if (nb_rotations != 0) - exp_rotation(P+C*eBands[i], C*(eBands[i+1]-eBands[i]), -1, C, nb_rotations);*/ - alg_unquant(X+C*eBands[i], C*(eBands[i+1]-eBands[i]), q, P+C*eBands[i], dec); - /*if (nb_rotations != 0) - exp_rotation(X+C*eBands[i], C*(eBands[i+1]-eBands[i]), 1, C, nb_rotations);*/ + int ch=C; + if (C==2 && stereo_mode[i]==1) + ch = 1; + if (C==2) + stereo_band_mix(m, P, bandE, stereo_mode, i, 1); + alg_unquant(X+C*eBands[i], ch*(eBands[i+1]-eBands[i]), q, P+C*eBands[i], dec); + if (C==2) + stereo_band_mix(m, X, bandE, stereo_mode, i, -1); + } else { + for (j=C*eBands[i];jeBands; - const int C = CHANNELS(m); - for (i=0;inbEBands;i++) - { - int j; - celt_word16_t left, right; - celt_word16_t a1, a2; - celt_word16_t norm; -#ifdef FIXED_POINT - int shift = celt_zlog2(MAX32(bank[i*C], bank[i*C+1]))-13; -#endif - left = VSHR32(bank[i*C],shift); - right = VSHR32(bank[i*C+1],shift); - norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); - a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); - a2 = dir*DIV32_16(SHL32(EXTEND32(right),14),norm); - for (j=eBands[i];jmode, bandE, st->oldBandE, 20+nbCompressedBytes*8/5, st->mode->prob, &st->enc); ALLOC(stereo_mode, st->mode->nbEBands, int); - if (C==2) - { - stereo_decision(st->mode, X, stereo_mode, st->mode->nbEBands); - stereo_mix(st->mode, X, bandE, stereo_mode, 1); - stereo_mix(st->mode, P, bandE, stereo_mode, 1); - } + stereo_decision(st->mode, X, stereo_mode, st->mode->nbEBands); pitch_quant_bands(st->mode, P, gains); /*for (i=0;imode->eBands[st->mode->nbEBands];i++) - X[i] -= P[i]; /* Residual quantisation */ - quant_bands(st->mode, X, P, NULL, stereo_mode, nbCompressedBytes*8, &st->enc); + quant_bands(st->mode, X, P, NULL, bandE, stereo_mode, nbCompressedBytes*8, &st->enc); if (C==2) { - stereo_mix(st->mode, X, bandE, stereo_mode, -1); renormalise_bands(st->mode, X); } /* Synthesis */ @@ -606,20 +597,15 @@ int EXPORT celt_decode(CELTDecoder * restrict st, unsigned char *data, int len, } ALLOC(stereo_mode, st->mode->nbEBands, int); - if (C==2) - { - stereo_decision(st->mode, X, stereo_mode, st->mode->nbEBands); - stereo_mix(st->mode, P, bandE, stereo_mode, 1); - } + stereo_decision(st->mode, X, stereo_mode, st->mode->nbEBands); /* Apply pitch gains */ pitch_quant_bands(st->mode, P, gains); /* Decode fixed codebook and merge with pitch */ - unquant_bands(st->mode, X, P, stereo_mode, len*8, &dec); + unquant_bands(st->mode, X, P, bandE, stereo_mode, len*8, &dec); if (C==2) { - stereo_mix(st->mode, X, bandE, stereo_mode, -1); renormalise_bands(st->mode, X); } /* Synthesis */ diff --git a/libcelt/dump_modes.c b/libcelt/dump_modes.c index 9f00dcc1..de4e062c 100644 --- a/libcelt/dump_modes.c +++ b/libcelt/dump_modes.c @@ -156,6 +156,7 @@ void dump_modes(FILE *file, CELTMode **modes, int nb_modes) fprintf(file, "%d,\t/* nbAllocVectors */\n", mode->nbAllocVectors); fprintf(file, "allocVectors%d_%d,\t/* allocVectors */\n", mode->Fs, mode->mdctSize); fprintf(file, "allocCache%d_%d_%d,\t/* bits */\n", mode->Fs, mode->mdctSize, mode->nbChannels); + fprintf(file, "0,\t/* bits_stereo */\n"); fprintf(file, "{%d, 0, 0},\t/* mdct */\n", 2*mode->mdctSize); fprintf(file, "0,\t/* fft */\n"); fprintf(file, "window%d,\t/* window */\n", mode->overlap); diff --git a/libcelt/modes.c b/libcelt/modes.c index 89ba428f..a9a94e78 100644 --- a/libcelt/modes.c +++ b/libcelt/modes.c @@ -364,8 +364,9 @@ CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, #endif mode->window = window; - mode->bits = (const celt_int16_t **)compute_alloc_cache(mode, mode->nbChannels); + mode->bits = (const celt_int16_t **)compute_alloc_cache(mode, 1); + mode->bits_stereo = NULL; #ifndef SHORTCUTS psydecay_init(&mode->psy, MAX_PERIOD/2, mode->Fs); #endif @@ -379,6 +380,9 @@ CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, mode->prob = quant_prob_alloc(mode); compute_energy_allocation_table(mode); + if (mode->nbChannels>=2) + mode->bits_stereo = (const celt_int16_t **)compute_alloc_cache(mode, mode->nbChannels); + if (error) *error = CELT_OK; return mode; diff --git a/libcelt/modes.h b/libcelt/modes.h index dd926dc2..21ca35c7 100644 --- a/libcelt/modes.h +++ b/libcelt/modes.h @@ -89,6 +89,8 @@ struct CELTMode { const celt_int16_t * const *bits; /**< Cache for pulses->bits mapping in each band */ + const celt_int16_t * const *bits_stereo; /**< Cache for pulses->bits mapping in each band */ + /* Stuff that could go in the {en,de}coder, but we save space this way */ mdct_lookup mdct; kiss_fftr_cfg fft; diff --git a/libcelt/rate.c b/libcelt/rate.c index 09a62321..dbf2ca42 100644 --- a/libcelt/rate.c +++ b/libcelt/rate.c @@ -105,7 +105,6 @@ celt_int16_t **compute_alloc_cache(CELTMode *m, int C) bits = celt_alloc(m->nbEBands*sizeof(celt_int16_t*)); - C = m->nbChannels; prevN = -1; for (i=0;inbEBands;i++) { @@ -270,6 +269,8 @@ int compute_allocation(const CELTMode *m, int *offsets, const int *stereo_mode, for (i=0;ibits_stereo[i]; + else cache[i] = m->bits[i]; } } else { diff --git a/libcelt/vq.c b/libcelt/vq.c index 76b0ce0d..9426ff4b 100644 --- a/libcelt/vq.c +++ b/libcelt/vq.c @@ -118,6 +118,7 @@ void alg_quant(celt_norm_t *X, celt_mask_t *W, int N, int K, const celt_norm_t * sum = 0; j=0; do { + X[j] -= P[j]; if (X[j]>0) signx[j]=1; else @@ -307,14 +308,6 @@ void intra_prediction(const CELTMode *m, celt_norm_t * restrict x, celt_mask_t * pred_gain = s*MULT16_16_Q15(pred_gain,celt_rcp(SHL32(celt_sqrt(E),9))); for (j=0;j0) - { - for (j=0;j