cannam@154: /* Copyright (c) 2007-2008 CSIRO cannam@154: Copyright (c) 2007-2010 Xiph.Org Foundation cannam@154: Copyright (c) 2008 Gregory Maxwell cannam@154: Written by Jean-Marc Valin and Gregory Maxwell */ cannam@154: /* cannam@154: Redistribution and use in source and binary forms, with or without cannam@154: modification, are permitted provided that the following conditions cannam@154: are met: cannam@154: cannam@154: - Redistributions of source code must retain the above copyright cannam@154: notice, this list of conditions and the following disclaimer. cannam@154: cannam@154: - Redistributions in binary form must reproduce the above copyright cannam@154: notice, this list of conditions and the following disclaimer in the cannam@154: documentation and/or other materials provided with the distribution. cannam@154: cannam@154: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS cannam@154: ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT cannam@154: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR cannam@154: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER cannam@154: OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, cannam@154: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, cannam@154: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR cannam@154: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF cannam@154: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING cannam@154: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS cannam@154: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cannam@154: */ cannam@154: cannam@154: #ifdef HAVE_CONFIG_H cannam@154: #include "config.h" cannam@154: #endif cannam@154: cannam@154: #define CELT_DECODER_C cannam@154: cannam@154: #include "cpu_support.h" cannam@154: #include "os_support.h" cannam@154: #include "mdct.h" cannam@154: #include cannam@154: #include "celt.h" cannam@154: #include "pitch.h" cannam@154: #include "bands.h" cannam@154: #include "modes.h" cannam@154: #include "entcode.h" cannam@154: #include "quant_bands.h" cannam@154: #include "rate.h" cannam@154: #include "stack_alloc.h" cannam@154: #include "mathops.h" cannam@154: #include "float_cast.h" cannam@154: #include cannam@154: #include "celt_lpc.h" cannam@154: #include "vq.h" cannam@154: cannam@154: /* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save cannam@154: CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The cannam@154: current value corresponds to a pitch of 66.67 Hz. */ cannam@154: #define PLC_PITCH_LAG_MAX (720) cannam@154: /* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a cannam@154: pitch of 480 Hz. */ cannam@154: #define PLC_PITCH_LAG_MIN (100) cannam@154: cannam@154: #if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT) cannam@154: #define NORM_ALIASING_HACK cannam@154: #endif cannam@154: /**********************************************************************/ cannam@154: /* */ cannam@154: /* DECODER */ cannam@154: /* */ cannam@154: /**********************************************************************/ cannam@154: #define DECODE_BUFFER_SIZE 2048 cannam@154: cannam@154: /** Decoder state cannam@154: @brief Decoder state cannam@154: */ cannam@154: struct OpusCustomDecoder { cannam@154: const OpusCustomMode *mode; cannam@154: int overlap; cannam@154: int channels; cannam@154: int stream_channels; cannam@154: cannam@154: int downsample; cannam@154: int start, end; cannam@154: int signalling; cannam@154: int disable_inv; cannam@154: int arch; cannam@154: cannam@154: /* Everything beyond this point gets cleared on a reset */ cannam@154: #define DECODER_RESET_START rng cannam@154: cannam@154: opus_uint32 rng; cannam@154: int error; cannam@154: int last_pitch_index; cannam@154: int loss_count; cannam@154: int skip_plc; cannam@154: int postfilter_period; cannam@154: int postfilter_period_old; cannam@154: opus_val16 postfilter_gain; cannam@154: opus_val16 postfilter_gain_old; cannam@154: int postfilter_tapset; cannam@154: int postfilter_tapset_old; cannam@154: cannam@154: celt_sig preemph_memD[2]; cannam@154: cannam@154: celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ cannam@154: /* opus_val16 lpc[], Size = channels*LPC_ORDER */ cannam@154: /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ cannam@154: /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ cannam@154: /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ cannam@154: /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ cannam@154: }; cannam@154: cannam@154: #if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) cannam@154: /* Make basic checks on the CELT state to ensure we don't end cannam@154: up writing all over memory. */ cannam@154: void validate_celt_decoder(CELTDecoder *st) cannam@154: { cannam@154: #ifndef CUSTOM_MODES cannam@154: celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); cannam@154: celt_assert(st->overlap == 120); cannam@154: #endif cannam@154: celt_assert(st->channels == 1 || st->channels == 2); cannam@154: celt_assert(st->stream_channels == 1 || st->stream_channels == 2); cannam@154: celt_assert(st->downsample > 0); cannam@154: celt_assert(st->start == 0 || st->start == 17); cannam@154: celt_assert(st->start < st->end); cannam@154: celt_assert(st->end <= 21); cannam@154: #ifdef OPUS_ARCHMASK cannam@154: celt_assert(st->arch >= 0); cannam@154: celt_assert(st->arch <= OPUS_ARCHMASK); cannam@154: #endif cannam@154: celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX); cannam@154: celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0); cannam@154: celt_assert(st->postfilter_period < MAX_PERIOD); cannam@154: celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0); cannam@154: celt_assert(st->postfilter_period_old < MAX_PERIOD); cannam@154: celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0); cannam@154: celt_assert(st->postfilter_tapset <= 2); cannam@154: celt_assert(st->postfilter_tapset >= 0); cannam@154: celt_assert(st->postfilter_tapset_old <= 2); cannam@154: celt_assert(st->postfilter_tapset_old >= 0); cannam@154: } cannam@154: #endif cannam@154: cannam@154: int celt_decoder_get_size(int channels) cannam@154: { cannam@154: const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); cannam@154: return opus_custom_decoder_get_size(mode, channels); cannam@154: } cannam@154: cannam@154: OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) cannam@154: { cannam@154: int size = sizeof(struct CELTDecoder) cannam@154: + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) cannam@154: + channels*LPC_ORDER*sizeof(opus_val16) cannam@154: + 4*2*mode->nbEBands*sizeof(opus_val16); cannam@154: return size; cannam@154: } cannam@154: cannam@154: #ifdef CUSTOM_MODES cannam@154: CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) cannam@154: { cannam@154: int ret; cannam@154: CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); cannam@154: ret = opus_custom_decoder_init(st, mode, channels); cannam@154: if (ret != OPUS_OK) cannam@154: { cannam@154: opus_custom_decoder_destroy(st); cannam@154: st = NULL; cannam@154: } cannam@154: if (error) cannam@154: *error = ret; cannam@154: return st; cannam@154: } cannam@154: #endif /* CUSTOM_MODES */ cannam@154: cannam@154: int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) cannam@154: { cannam@154: int ret; cannam@154: ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); cannam@154: if (ret != OPUS_OK) cannam@154: return ret; cannam@154: st->downsample = resampling_factor(sampling_rate); cannam@154: if (st->downsample==0) cannam@154: return OPUS_BAD_ARG; cannam@154: else cannam@154: return OPUS_OK; cannam@154: } cannam@154: cannam@154: OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) cannam@154: { cannam@154: if (channels < 0 || channels > 2) cannam@154: return OPUS_BAD_ARG; cannam@154: cannam@154: if (st==NULL) cannam@154: return OPUS_ALLOC_FAIL; cannam@154: cannam@154: OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); cannam@154: cannam@154: st->mode = mode; cannam@154: st->overlap = mode->overlap; cannam@154: st->stream_channels = st->channels = channels; cannam@154: cannam@154: st->downsample = 1; cannam@154: st->start = 0; cannam@154: st->end = st->mode->effEBands; cannam@154: st->signalling = 1; cannam@154: #ifndef DISABLE_UPDATE_DRAFT cannam@154: st->disable_inv = channels == 1; cannam@154: #else cannam@154: st->disable_inv = 0; cannam@154: #endif cannam@154: st->arch = opus_select_arch(); cannam@154: cannam@154: opus_custom_decoder_ctl(st, OPUS_RESET_STATE); cannam@154: cannam@154: return OPUS_OK; cannam@154: } cannam@154: cannam@154: #ifdef CUSTOM_MODES cannam@154: void opus_custom_decoder_destroy(CELTDecoder *st) cannam@154: { cannam@154: opus_free(st); cannam@154: } cannam@154: #endif /* CUSTOM_MODES */ cannam@154: cannam@154: #ifndef CUSTOM_MODES cannam@154: /* Special case for stereo with no downsampling and no accumulation. This is cannam@154: quite common and we can make it faster by processing both channels in the cannam@154: same loop, reducing overhead due to the dependency loop in the IIR filter. */ cannam@154: static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0, cannam@154: celt_sig *mem) cannam@154: { cannam@154: celt_sig * OPUS_RESTRICT x0; cannam@154: celt_sig * OPUS_RESTRICT x1; cannam@154: celt_sig m0, m1; cannam@154: int j; cannam@154: x0=in[0]; cannam@154: x1=in[1]; cannam@154: m0 = mem[0]; cannam@154: m1 = mem[1]; cannam@154: for (j=0;j1) cannam@154: { cannam@154: /* Shortcut for the standard (non-custom modes) case */ cannam@154: for (j=0;joverlap; cannam@154: nbEBands = mode->nbEBands; cannam@154: N = mode->shortMdctSize<shortMdctSize; cannam@154: shift = mode->maxLM; cannam@154: } else { cannam@154: B = 1; cannam@154: NB = mode->shortMdctSize<maxLM-LM; cannam@154: } cannam@154: cannam@154: if (CC==2&&C==1) cannam@154: { cannam@154: /* Copying a mono streams to two channels */ cannam@154: celt_sig *freq2; cannam@154: denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, cannam@154: downsample, silence); cannam@154: /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ cannam@154: freq2 = out_syn[1]+overlap/2; cannam@154: OPUS_COPY(freq2, freq, N); cannam@154: for (b=0;bmdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); cannam@154: for (b=0;bmdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch); cannam@154: } else if (CC==1&&C==2) cannam@154: { cannam@154: /* Downmixing a stereo stream to mono */ cannam@154: celt_sig *freq2; cannam@154: freq2 = out_syn[0]+overlap/2; cannam@154: denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, cannam@154: downsample, silence); cannam@154: /* Use the output buffer as temp array before downmixing. */ cannam@154: denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, cannam@154: downsample, silence); cannam@154: for (i=0;imdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); cannam@154: } else { cannam@154: /* Normal case (mono or stereo) */ cannam@154: c=0; do { cannam@154: denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M, cannam@154: downsample, silence); cannam@154: for (b=0;bmdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); cannam@154: } while (++cstorage*8; cannam@154: tell = ec_tell(dec); cannam@154: logp = isTransient ? 2 : 4; cannam@154: tf_select_rsv = LM>0 && tell+logp+1<=budget; cannam@154: budget -= tf_select_rsv; cannam@154: tf_changed = curr = 0; cannam@154: for (i=start;i>1, opus_val16 ); cannam@154: pitch_downsample(decode_mem, lp_pitch_buf, cannam@154: DECODE_BUFFER_SIZE, C, arch); cannam@154: pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, cannam@154: DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX, cannam@154: PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); cannam@154: pitch_index = PLC_PITCH_LAG_MAX-pitch_index; cannam@154: RESTORE_STACK; cannam@154: return pitch_index; cannam@154: } cannam@154: cannam@154: static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) cannam@154: { cannam@154: int c; cannam@154: int i; cannam@154: const int C = st->channels; cannam@154: celt_sig *decode_mem[2]; cannam@154: celt_sig *out_syn[2]; cannam@154: opus_val16 *lpc; cannam@154: opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; cannam@154: const OpusCustomMode *mode; cannam@154: int nbEBands; cannam@154: int overlap; cannam@154: int start; cannam@154: int loss_count; cannam@154: int noise_based; cannam@154: const opus_int16 *eBands; cannam@154: SAVE_STACK; cannam@154: cannam@154: mode = st->mode; cannam@154: nbEBands = mode->nbEBands; cannam@154: overlap = mode->overlap; cannam@154: eBands = mode->eBands; cannam@154: cannam@154: c=0; do { cannam@154: decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); cannam@154: out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; cannam@154: } while (++c_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C); cannam@154: oldBandE = lpc+C*LPC_ORDER; cannam@154: oldLogE = oldBandE + 2*nbEBands; cannam@154: oldLogE2 = oldLogE + 2*nbEBands; cannam@154: backgroundLogE = oldLogE2 + 2*nbEBands; cannam@154: cannam@154: loss_count = st->loss_count; cannam@154: start = st->start; cannam@154: noise_based = loss_count >= 5 || start != 0 || st->skip_plc; cannam@154: if (noise_based) cannam@154: { cannam@154: /* Noise-based PLC/CNG */ cannam@154: #ifdef NORM_ALIASING_HACK cannam@154: celt_norm *X; cannam@154: #else cannam@154: VARDECL(celt_norm, X); cannam@154: #endif cannam@154: opus_uint32 seed; cannam@154: int end; cannam@154: int effEnd; cannam@154: opus_val16 decay; cannam@154: end = st->end; cannam@154: effEnd = IMAX(start, IMIN(end, mode->effEBands)); cannam@154: cannam@154: #ifdef NORM_ALIASING_HACK cannam@154: /* This is an ugly hack that breaks aliasing rules and would be easily broken, cannam@154: but it saves almost 4kB of stack. */ cannam@154: X = (celt_norm*)(out_syn[C-1]+overlap/2); cannam@154: #else cannam@154: ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ cannam@154: #endif cannam@154: cannam@154: /* Energy decay */ cannam@154: decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); cannam@154: c=0; do cannam@154: { cannam@154: for (i=start;irng; cannam@154: for (c=0;c>20); cannam@154: } cannam@154: renormalise_vector(X+boffs, blen, Q15ONE, st->arch); cannam@154: } cannam@154: } cannam@154: st->rng = seed; cannam@154: cannam@154: c=0; do { cannam@154: OPUS_MOVE(decode_mem[c], decode_mem[c]+N, cannam@154: DECODE_BUFFER_SIZE-N+(overlap>>1)); cannam@154: } while (++cdownsample, 0, st->arch); cannam@154: } else { cannam@154: int exc_length; cannam@154: /* Pitch-based PLC */ cannam@154: const opus_val16 *window; cannam@154: opus_val16 *exc; cannam@154: opus_val16 fade = Q15ONE; cannam@154: int pitch_index; cannam@154: VARDECL(opus_val32, etmp); cannam@154: VARDECL(opus_val16, _exc); cannam@154: VARDECL(opus_val16, fir_tmp); cannam@154: cannam@154: if (loss_count == 0) cannam@154: { cannam@154: st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch); cannam@154: } else { cannam@154: pitch_index = st->last_pitch_index; cannam@154: fade = QCONST16(.8f,15); cannam@154: } cannam@154: cannam@154: /* We want the excitation for 2 pitch periods in order to look for a cannam@154: decaying signal, but we can't get more than MAX_PERIOD. */ cannam@154: exc_length = IMIN(2*pitch_index, MAX_PERIOD); cannam@154: cannam@154: ALLOC(etmp, overlap, opus_val32); cannam@154: ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16); cannam@154: ALLOC(fir_tmp, exc_length, opus_val16); cannam@154: exc = _exc+LPC_ORDER; cannam@154: window = mode->window; cannam@154: c=0; do { cannam@154: opus_val16 decay; cannam@154: opus_val16 attenuation; cannam@154: opus_val32 S1=0; cannam@154: celt_sig *buf; cannam@154: int extrapolation_offset; cannam@154: int extrapolation_len; cannam@154: int j; cannam@154: cannam@154: buf = decode_mem[c]; cannam@154: for (i=0;iarch); cannam@154: /* Add a noise floor of -40 dB. */ cannam@154: #ifdef FIXED_POINT cannam@154: ac[0] += SHR32(ac[0],13); cannam@154: #else cannam@154: ac[0] *= 1.0001f; cannam@154: #endif cannam@154: /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ cannam@154: for (i=1;i<=LPC_ORDER;i++) cannam@154: { cannam@154: /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ cannam@154: #ifdef FIXED_POINT cannam@154: ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); cannam@154: #else cannam@154: ac[i] -= ac[i]*(0.008f*0.008f)*i*i; cannam@154: #endif cannam@154: } cannam@154: _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); cannam@154: #ifdef FIXED_POINT cannam@154: /* For fixed-point, apply bandwidth expansion until we can guarantee that cannam@154: no overflow can happen in the IIR filter. This means: cannam@154: 32768*sum(abs(filter)) < 2^31 */ cannam@154: while (1) { cannam@154: opus_val16 tmp=Q15ONE; cannam@154: opus_val32 sum=QCONST16(1., SIG_SHIFT); cannam@154: for (i=0;iarch); cannam@154: OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); cannam@154: } cannam@154: cannam@154: /* Check if the waveform is decaying, and if so how fast. cannam@154: We do this to avoid adding energy when concealing in a segment cannam@154: with decaying energy. */ cannam@154: { cannam@154: opus_val32 E1=1, E2=1; cannam@154: int decay_length; cannam@154: #ifdef FIXED_POINT cannam@154: int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20); cannam@154: #endif cannam@154: decay_length = exc_length>>1; cannam@154: for (i=0;i= pitch_index) { cannam@154: j -= pitch_index; cannam@154: attenuation = MULT16_16_Q15(attenuation, decay); cannam@154: } cannam@154: buf[DECODE_BUFFER_SIZE-N+i] = cannam@154: SHL32(EXTEND32(MULT16_16_Q15(attenuation, cannam@154: exc[extrapolation_offset+j])), SIG_SHIFT); cannam@154: /* Compute the energy of the previously decoded signal whose cannam@154: excitation we're copying. */ cannam@154: tmp = ROUND16( cannam@154: buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], cannam@154: SIG_SHIFT); cannam@154: S1 += SHR32(MULT16_16(tmp, tmp), 10); cannam@154: } cannam@154: { cannam@154: opus_val16 lpc_mem[LPC_ORDER]; cannam@154: /* Copy the last decoded samples (prior to the overlap region) to cannam@154: synthesis filter memory so we can have a continuous signal. */ cannam@154: for (i=0;iarch); cannam@154: #ifdef FIXED_POINT cannam@154: for (i=0; i < extrapolation_len; i++) cannam@154: buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT); cannam@154: #endif cannam@154: } cannam@154: cannam@154: /* Check if the synthesis energy is higher than expected, which can cannam@154: happen with the signal changes during our window. If so, cannam@154: attenuate. */ cannam@154: { cannam@154: opus_val32 S2=0; cannam@154: for (i=0;i SHR32(S2,2))) cannam@154: #else cannam@154: /* The float test is written this way to catch NaNs in the output cannam@154: of the IIR filter at the same time. */ cannam@154: if (!(S1 > 0.2f*S2)) cannam@154: #endif cannam@154: { cannam@154: for (i=0;ipostfilter_period, st->postfilter_period, overlap, cannam@154: -st->postfilter_gain, -st->postfilter_gain, cannam@154: st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch); cannam@154: cannam@154: /* Simulate TDAC on the concealed audio so that it blends with the cannam@154: MDCT of the next frame. */ cannam@154: for (i=0;iloss_count = loss_count+1; cannam@154: cannam@154: RESTORE_STACK; cannam@154: } cannam@154: cannam@154: int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, cannam@154: int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum) cannam@154: { cannam@154: int c, i, N; cannam@154: int spread_decision; cannam@154: opus_int32 bits; cannam@154: ec_dec _dec; cannam@154: #ifdef NORM_ALIASING_HACK cannam@154: celt_norm *X; cannam@154: #else cannam@154: VARDECL(celt_norm, X); cannam@154: #endif cannam@154: VARDECL(int, fine_quant); cannam@154: VARDECL(int, pulses); cannam@154: VARDECL(int, cap); cannam@154: VARDECL(int, offsets); cannam@154: VARDECL(int, fine_priority); cannam@154: VARDECL(int, tf_res); cannam@154: VARDECL(unsigned char, collapse_masks); cannam@154: celt_sig *decode_mem[2]; cannam@154: celt_sig *out_syn[2]; cannam@154: opus_val16 *lpc; cannam@154: opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; cannam@154: cannam@154: int shortBlocks; cannam@154: int isTransient; cannam@154: int intra_ener; cannam@154: const int CC = st->channels; cannam@154: int LM, M; cannam@154: int start; cannam@154: int end; cannam@154: int effEnd; cannam@154: int codedBands; cannam@154: int alloc_trim; cannam@154: int postfilter_pitch; cannam@154: opus_val16 postfilter_gain; cannam@154: int intensity=0; cannam@154: int dual_stereo=0; cannam@154: opus_int32 total_bits; cannam@154: opus_int32 balance; cannam@154: opus_int32 tell; cannam@154: int dynalloc_logp; cannam@154: int postfilter_tapset; cannam@154: int anti_collapse_rsv; cannam@154: int anti_collapse_on=0; cannam@154: int silence; cannam@154: int C = st->stream_channels; cannam@154: const OpusCustomMode *mode; cannam@154: int nbEBands; cannam@154: int overlap; cannam@154: const opus_int16 *eBands; cannam@154: ALLOC_STACK; cannam@154: cannam@154: VALIDATE_CELT_DECODER(st); cannam@154: mode = st->mode; cannam@154: nbEBands = mode->nbEBands; cannam@154: overlap = mode->overlap; cannam@154: eBands = mode->eBands; cannam@154: start = st->start; cannam@154: end = st->end; cannam@154: frame_size *= st->downsample; cannam@154: cannam@154: lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC); cannam@154: oldBandE = lpc+CC*LPC_ORDER; cannam@154: oldLogE = oldBandE + 2*nbEBands; cannam@154: oldLogE2 = oldLogE + 2*nbEBands; cannam@154: backgroundLogE = oldLogE2 + 2*nbEBands; cannam@154: cannam@154: #ifdef CUSTOM_MODES cannam@154: if (st->signalling && data!=NULL) cannam@154: { cannam@154: int data0=data[0]; cannam@154: /* Convert "standard mode" to Opus header */ cannam@154: if (mode->Fs==48000 && mode->shortMdctSize==120) cannam@154: { cannam@154: data0 = fromOpus(data0); cannam@154: if (data0<0) cannam@154: return OPUS_INVALID_PACKET; cannam@154: } cannam@154: st->end = end = IMAX(1, mode->effEBands-2*(data0>>5)); cannam@154: LM = (data0>>3)&0x3; cannam@154: C = 1 + ((data0>>2)&0x1); cannam@154: data++; cannam@154: len--; cannam@154: if (LM>mode->maxLM) cannam@154: return OPUS_INVALID_PACKET; cannam@154: if (frame_size < mode->shortMdctSize<shortMdctSize<maxLM;LM++) cannam@154: if (mode->shortMdctSize<mode->maxLM) cannam@154: return OPUS_BAD_ARG; cannam@154: } cannam@154: M=1<1275 || pcm==NULL) cannam@154: return OPUS_BAD_ARG; cannam@154: cannam@154: N = M*mode->shortMdctSize; cannam@154: c=0; do { cannam@154: decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); cannam@154: out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; cannam@154: } while (++c mode->effEBands) cannam@154: effEnd = mode->effEBands; cannam@154: cannam@154: if (data == NULL || len<=1) cannam@154: { cannam@154: celt_decode_lost(st, N, LM); cannam@154: deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); cannam@154: RESTORE_STACK; cannam@154: return frame_size/st->downsample; cannam@154: } cannam@154: cannam@154: /* Check if there are at least two packets received consecutively before cannam@154: * turning on the pitch-based PLC */ cannam@154: st->skip_plc = st->loss_count != 0; cannam@154: cannam@154: if (dec == NULL) cannam@154: { cannam@154: ec_dec_init(&_dec,(unsigned char*)data,len); cannam@154: dec = &_dec; cannam@154: } cannam@154: cannam@154: if (C==1) cannam@154: { cannam@154: for (i=0;i= total_bits) cannam@154: silence = 1; cannam@154: else if (tell==1) cannam@154: silence = ec_dec_bit_logp(dec, 15); cannam@154: else cannam@154: silence = 0; cannam@154: if (silence) cannam@154: { cannam@154: /* Pretend we've read all the remaining bits */ cannam@154: tell = len*8; cannam@154: dec->nbits_total+=tell-ec_tell(dec); cannam@154: } cannam@154: cannam@154: postfilter_gain = 0; cannam@154: postfilter_pitch = 0; cannam@154: postfilter_tapset = 0; cannam@154: if (start==0 && tell+16 <= total_bits) cannam@154: { cannam@154: if(ec_dec_bit_logp(dec, 1)) cannam@154: { cannam@154: int qg, octave; cannam@154: octave = ec_dec_uint(dec, 6); cannam@154: postfilter_pitch = (16< 0 && tell+3 <= total_bits) cannam@154: { cannam@154: isTransient = ec_dec_bit_logp(dec, 3); cannam@154: tell = ec_tell(dec); cannam@154: } cannam@154: else cannam@154: isTransient = 0; cannam@154: cannam@154: if (isTransient) cannam@154: shortBlocks = M; cannam@154: else cannam@154: shortBlocks = 0; cannam@154: cannam@154: /* Decode the global flags (first symbols in the stream) */ cannam@154: intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; cannam@154: /* Get band energies */ cannam@154: unquant_coarse_energy(mode, start, end, oldBandE, cannam@154: intra_ener, dec, C, LM); cannam@154: cannam@154: ALLOC(tf_res, nbEBands, int); cannam@154: tf_decode(start, end, isTransient, tf_res, LM, dec); cannam@154: cannam@154: tell = ec_tell(dec); cannam@154: spread_decision = SPREAD_NORMAL; cannam@154: if (tell+4 <= total_bits) cannam@154: spread_decision = ec_dec_icdf(dec, spread_icdf, 5); cannam@154: cannam@154: ALLOC(cap, nbEBands, int); cannam@154: cannam@154: init_caps(mode,cap,LM,C); cannam@154: cannam@154: ALLOC(offsets, nbEBands, int); cannam@154: cannam@154: dynalloc_logp = 6; cannam@154: total_bits<<=BITRES; cannam@154: tell = ec_tell_frac(dec); cannam@154: for (i=start;i0) cannam@154: dynalloc_logp = IMAX(2, dynalloc_logp-1); cannam@154: } cannam@154: cannam@154: ALLOC(fine_quant, nbEBands, int); cannam@154: alloc_trim = tell+(6<=2&&bits>=((LM+2)<rng, 0, cannam@154: st->arch, st->disable_inv); cannam@154: cannam@154: if (anti_collapse_rsv > 0) cannam@154: { cannam@154: anti_collapse_on = ec_dec_bits(dec, 1); cannam@154: } cannam@154: cannam@154: unquant_energy_finalise(mode, start, end, oldBandE, cannam@154: fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); cannam@154: cannam@154: if (anti_collapse_on) cannam@154: anti_collapse(mode, X, collapse_masks, LM, C, N, cannam@154: start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch); cannam@154: cannam@154: if (silence) cannam@154: { cannam@154: for (i=0;idownsample, silence, st->arch); cannam@154: cannam@154: c=0; do { cannam@154: st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); cannam@154: st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); cannam@154: comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize, cannam@154: st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, cannam@154: mode->window, overlap, st->arch); cannam@154: if (LM!=0) cannam@154: comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize, cannam@154: st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, cannam@154: mode->window, overlap, st->arch); cannam@154: cannam@154: } while (++cpostfilter_period_old = st->postfilter_period; cannam@154: st->postfilter_gain_old = st->postfilter_gain; cannam@154: st->postfilter_tapset_old = st->postfilter_tapset; cannam@154: st->postfilter_period = postfilter_pitch; cannam@154: st->postfilter_gain = postfilter_gain; cannam@154: st->postfilter_tapset = postfilter_tapset; cannam@154: if (LM!=0) cannam@154: { cannam@154: st->postfilter_period_old = st->postfilter_period; cannam@154: st->postfilter_gain_old = st->postfilter_gain; cannam@154: st->postfilter_tapset_old = st->postfilter_tapset; cannam@154: } cannam@154: cannam@154: if (C==1) cannam@154: OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); cannam@154: cannam@154: /* In case start or end were to change */ cannam@154: if (!isTransient) cannam@154: { cannam@154: opus_val16 max_background_increase; cannam@154: OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands); cannam@154: OPUS_COPY(oldLogE, oldBandE, 2*nbEBands); cannam@154: /* In normal circumstances, we only allow the noise floor to increase by cannam@154: up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB cannam@154: increase for each update.*/ cannam@154: if (st->loss_count < 10) cannam@154: max_background_increase = M*QCONST16(0.001f,DB_SHIFT); cannam@154: else cannam@154: max_background_increase = QCONST16(1.f,DB_SHIFT); cannam@154: for (i=0;i<2*nbEBands;i++) cannam@154: backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); cannam@154: } else { cannam@154: for (i=0;i<2*nbEBands;i++) cannam@154: oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); cannam@154: } cannam@154: c=0; do cannam@154: { cannam@154: for (i=0;irng = dec->rng; cannam@154: cannam@154: deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); cannam@154: st->loss_count = 0; cannam@154: RESTORE_STACK; cannam@154: if (ec_tell(dec) > 8*len) cannam@154: return OPUS_INTERNAL_ERROR; cannam@154: if(ec_get_error(dec)) cannam@154: st->error = 1; cannam@154: return frame_size/st->downsample; cannam@154: } cannam@154: cannam@154: cannam@154: #ifdef CUSTOM_MODES cannam@154: cannam@154: #ifdef FIXED_POINT cannam@154: int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) cannam@154: { cannam@154: return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0); cannam@154: } cannam@154: cannam@154: #ifndef DISABLE_FLOAT_API cannam@154: int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) cannam@154: { cannam@154: int j, ret, C, N; cannam@154: VARDECL(opus_int16, out); cannam@154: ALLOC_STACK; cannam@154: cannam@154: if (pcm==NULL) cannam@154: return OPUS_BAD_ARG; cannam@154: cannam@154: C = st->channels; cannam@154: N = frame_size; cannam@154: cannam@154: ALLOC(out, C*N, opus_int16); cannam@154: ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); cannam@154: if (ret>0) cannam@154: for (j=0;jchannels; cannam@154: N = frame_size; cannam@154: ALLOC(out, C*N, celt_sig); cannam@154: cannam@154: ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); cannam@154: cannam@154: if (ret>0) cannam@154: for (j=0;j=st->mode->nbEBands) cannam@154: goto bad_arg; cannam@154: st->start = value; cannam@154: } cannam@154: break; cannam@154: case CELT_SET_END_BAND_REQUEST: cannam@154: { cannam@154: opus_int32 value = va_arg(ap, opus_int32); cannam@154: if (value<1 || value>st->mode->nbEBands) cannam@154: goto bad_arg; cannam@154: st->end = value; cannam@154: } cannam@154: break; cannam@154: case CELT_SET_CHANNELS_REQUEST: cannam@154: { cannam@154: opus_int32 value = va_arg(ap, opus_int32); cannam@154: if (value<1 || value>2) cannam@154: goto bad_arg; cannam@154: st->stream_channels = value; cannam@154: } cannam@154: break; cannam@154: case CELT_GET_AND_CLEAR_ERROR_REQUEST: cannam@154: { cannam@154: opus_int32 *value = va_arg(ap, opus_int32*); cannam@154: if (value==NULL) cannam@154: goto bad_arg; cannam@154: *value=st->error; cannam@154: st->error = 0; cannam@154: } cannam@154: break; cannam@154: case OPUS_GET_LOOKAHEAD_REQUEST: cannam@154: { cannam@154: opus_int32 *value = va_arg(ap, opus_int32*); cannam@154: if (value==NULL) cannam@154: goto bad_arg; cannam@154: *value = st->overlap/st->downsample; cannam@154: } cannam@154: break; cannam@154: case OPUS_RESET_STATE: cannam@154: { cannam@154: int i; cannam@154: opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; cannam@154: lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); cannam@154: oldBandE = lpc+st->channels*LPC_ORDER; cannam@154: oldLogE = oldBandE + 2*st->mode->nbEBands; cannam@154: oldLogE2 = oldLogE + 2*st->mode->nbEBands; cannam@154: OPUS_CLEAR((char*)&st->DECODER_RESET_START, cannam@154: opus_custom_decoder_get_size(st->mode, st->channels)- cannam@154: ((char*)&st->DECODER_RESET_START - (char*)st)); cannam@154: for (i=0;i<2*st->mode->nbEBands;i++) cannam@154: oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); cannam@154: st->skip_plc = 1; cannam@154: } cannam@154: break; cannam@154: case OPUS_GET_PITCH_REQUEST: cannam@154: { cannam@154: opus_int32 *value = va_arg(ap, opus_int32*); cannam@154: if (value==NULL) cannam@154: goto bad_arg; cannam@154: *value = st->postfilter_period; cannam@154: } cannam@154: break; cannam@154: case CELT_GET_MODE_REQUEST: cannam@154: { cannam@154: const CELTMode ** value = va_arg(ap, const CELTMode**); cannam@154: if (value==0) cannam@154: goto bad_arg; cannam@154: *value=st->mode; cannam@154: } cannam@154: break; cannam@154: case CELT_SET_SIGNALLING_REQUEST: cannam@154: { cannam@154: opus_int32 value = va_arg(ap, opus_int32); cannam@154: st->signalling = value; cannam@154: } cannam@154: break; cannam@154: case OPUS_GET_FINAL_RANGE_REQUEST: cannam@154: { cannam@154: opus_uint32 * value = va_arg(ap, opus_uint32 *); cannam@154: if (value==0) cannam@154: goto bad_arg; cannam@154: *value=st->rng; cannam@154: } cannam@154: break; cannam@154: case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: cannam@154: { cannam@154: opus_int32 value = va_arg(ap, opus_int32); cannam@154: if(value<0 || value>1) cannam@154: { cannam@154: goto bad_arg; cannam@154: } cannam@154: st->disable_inv = value; cannam@154: } cannam@154: break; cannam@154: case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: cannam@154: { cannam@154: opus_int32 *value = va_arg(ap, opus_int32*); cannam@154: if (!value) cannam@154: { cannam@154: goto bad_arg; cannam@154: } cannam@154: *value = st->disable_inv; cannam@154: } cannam@154: break; cannam@154: default: cannam@154: goto bad_request; cannam@154: } cannam@154: va_end(ap); cannam@154: return OPUS_OK; cannam@154: bad_arg: cannam@154: va_end(ap); cannam@154: return OPUS_BAD_ARG; cannam@154: bad_request: cannam@154: va_end(ap); cannam@154: return OPUS_UNIMPLEMENTED; cannam@154: }