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