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