Ejemplo n.º 1
0
 internal static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec)
 {
     return(cwrsi(_n, _k, _dec.dec_uint(CELT_PVQ_V(_n, _k)), _y));
 }
Ejemplo n.º 2
0
        internal static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start,
                                               int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance,
                                               int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits,
                                               int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth)
        {
            int psum;
            int lo, hi;
            int i, j;
            int logM;
            int stereo;
            int codedBands = -1;
            int alloc_floor;
            int left, percoeff;
            int done;
            int balance;


            alloc_floor = C << EntropyCoder.BITRES;
            stereo      = C > 1 ? 1 : 0;

            logM = LM << EntropyCoder.BITRES;
            lo   = 0;
            hi   = 1 << ALLOC_STEPS;
            for (i = 0; i < ALLOC_STEPS; i++)
            {
                int mid = (lo + hi) >> 1;
                psum = 0;
                done = 0;
                for (j = end; j-- > start;)
                {
                    int tmp = bits1[j] + (mid * (int)bits2[j] >> ALLOC_STEPS);
                    if (tmp >= thresh[j] || done != 0)
                    {
                        done = 1;
                        /* Don't allocate more than we can actually use */
                        psum += Inlines.IMIN(tmp, cap[j]);
                    }
                    else
                    {
                        if (tmp >= alloc_floor)
                        {
                            psum += alloc_floor;
                        }
                    }
                }
                if (psum > total)
                {
                    hi = mid;
                }
                else
                {
                    lo = mid;
                }
            }
            psum = 0;
            /*printf ("interp bisection gave %d\n", lo);*/
            done = 0;
            for (j = end; j-- > start;)
            {
                int tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS);
                if (tmp < thresh[j] && done == 0)
                {
                    if (tmp >= alloc_floor)
                    {
                        tmp = alloc_floor;
                    }
                    else
                    {
                        tmp = 0;
                    }
                }
                else
                {
                    done = 1;
                }

                /* Don't allocate more than we can actually use */
                tmp     = Inlines.IMIN(tmp, cap[j]);
                bits[j] = tmp;
                psum   += tmp;
            }

            /* Decide which bands to skip, working backwards from the end. */
            for (codedBands = end; ; codedBands--)
            {
                int band_width;
                int band_bits;
                int rem;
                j = codedBands - 1;

                /* Never skip the first band, nor a band that has been boosted by
                 *  dynalloc.
                 * In the first case, we'd be coding a bit to signal we're going to waste
                 *  all the other bits.
                 * In the second case, we'd be coding a bit to redistribute all the bits
                 *  we just signaled should be cocentrated in this band. */
                if (j <= skip_start)
                {
                    /* Give the bit we reserved to end skipping back. */
                    total += skip_rsv;
                    break;
                }

                /*Figure out how many left-over bits we would be adding to this band.
                *  This can include bits we've stolen back from higher, skipped bands.*/
                left       = total - psum;
                percoeff   = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
                left      -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
                rem        = Inlines.IMAX(left - (m.eBands[j] - m.eBands[start]), 0);
                band_width = m.eBands[codedBands] - m.eBands[j];
                band_bits  = (int)(bits[j] + percoeff * band_width + rem);

                /*Only code a skip decision if we're above the threshold for this band.
                 * Otherwise it is force-skipped.
                 * This ensures that we have enough bits to code the skip flag.*/
                if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + (1 << EntropyCoder.BITRES)))
                {
                    if (encode != 0)
                    {
                        /*This if() block is the only part of the allocation function that
                         * is not a mandatory part of the bitstream: any bands we choose to
                         * skip here must be explicitly signaled.*/
                        /*Choose a threshold with some hysteresis to keep bands from
                         * fluctuating in and out.*/
#if FUZZING
                        if ((new Random().Next() & 0x1) == 0)
#else
                        if (codedBands <= start + 2 || (band_bits > ((j < prev ? 7 : 9) * band_width << LM << EntropyCoder.BITRES) >> 4 && j <= signalBandwidth))
#endif
                        {
                            ec.enc_bit_logp(1, 1);
                            break;
                        }
                        ec.enc_bit_logp(0, 1);
                    }
                    else if (ec.dec_bit_logp(1) != 0)
                    {
                        break;
                    }
                    /*We used a bit to skip this band.*/
                    psum      += 1 << EntropyCoder.BITRES;
                    band_bits -= 1 << EntropyCoder.BITRES;
                }
                /*Reclaim the bits originally allocated to this band.*/
                psum -= bits[j] + intensity_rsv;
                if (intensity_rsv > 0)
                {
                    intensity_rsv = LOG2_FRAC_TABLE[j - start];
                }
                psum += intensity_rsv;
                if (band_bits >= alloc_floor)
                {
                    /*If we have enough for a fine energy bit per channel, use it.*/
                    psum   += alloc_floor;
                    bits[j] = alloc_floor;
                }
                else
                {
                    /*Otherwise this band gets nothing at all.*/
                    bits[j] = 0;
                }
            }

            Inlines.OpusAssert(codedBands > start);
            /* Code the intensity and dual stereo parameters. */
            if (intensity_rsv > 0)
            {
                if (encode != 0)
                {
                    intensity = Inlines.IMIN(intensity, codedBands);
                    ec.enc_uint((uint)(intensity - start), (uint)(codedBands + 1 - start));
                }
                else
                {
                    intensity = start + (int)ec.dec_uint((uint)(codedBands + 1 - start));
                }
            }
            else
            {
                intensity = 0;
            }

            if (intensity <= start)
            {
                total          += dual_stereo_rsv;
                dual_stereo_rsv = 0;
            }
            if (dual_stereo_rsv > 0)
            {
                if (encode != 0)
                {
                    ec.enc_bit_logp(dual_stereo, 1);
                }
                else
                {
                    dual_stereo = ec.dec_bit_logp(1);
                }
            }
            else
            {
                dual_stereo = 0;
            }

            /* Allocate the remaining bits */
            left     = total - psum;
            percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
            left    -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
            for (j = start; j < codedBands; j++)
            {
                bits[j] += ((int)percoeff * (m.eBands[j + 1] - m.eBands[j]));
            }
            for (j = start; j < codedBands; j++)
            {
                int tmp = (int)Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]);
                bits[j] += tmp;
                left    -= tmp;
            }
            /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/

            balance = 0;
            for (j = start; j < codedBands; j++)
            {
                int N0, N, den;
                int offset;
                int NClogN;
                int excess, bit;

                Inlines.OpusAssert(bits[j] >= 0);
                N0  = m.eBands[j + 1] - m.eBands[j];
                N   = N0 << LM;
                bit = (int)bits[j] + balance;

                if (N > 1)
                {
                    excess  = Inlines.MAX32(bit - cap[j], 0);
                    bits[j] = bit - excess;

                    /* Compensate for the extra DoF in stereo */
                    den = (C * N + ((C == 2 && N > 2 && (dual_stereo == 0) && j < intensity) ? 1 : 0));

                    NClogN = den * (m.logN[j] + logM);

                    /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
                     * compared to their "fair share" of total/N */
                    offset = (NClogN >> 1) - den * CeltConstants.FINE_OFFSET;

                    /* N=2 is the only point that doesn't match the curve */
                    if (N == 2)
                    {
                        offset += den << EntropyCoder.BITRES >> 2;
                    }

                    /* Changing the offset for allocating the second and third
                     *  fine energy bit */
                    if (bits[j] + offset < den * 2 << EntropyCoder.BITRES)
                    {
                        offset += NClogN >> 2;
                    }
                    else if (bits[j] + offset < den * 3 << EntropyCoder.BITRES)
                    {
                        offset += NClogN >> 3;
                    }

                    /* Divide with rounding */
                    ebits[j] = Inlines.IMAX(0, (bits[j] + offset + (den << (EntropyCoder.BITRES - 1))));
                    ebits[j] = Inlines.celt_udiv(ebits[j], den) >> EntropyCoder.BITRES;

                    /* Make sure not to bust */
                    if (C * ebits[j] > (bits[j] >> EntropyCoder.BITRES))
                    {
                        ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
                    }

                    /* More than that is useless because that's about as far as PVQ can go */
                    ebits[j] = Inlines.IMIN(ebits[j], CeltConstants.MAX_FINE_BITS);

                    /* If we rounded down or capped this band, make it a candidate for the
                     *  final fine energy pass */
                    fine_priority[j] = (ebits[j] * (den << EntropyCoder.BITRES) >= bits[j] + offset) ? 1 : 0;

                    /* Remove the allocated fine bits; the rest are assigned to PVQ */
                    bits[j] -= C * ebits[j] << EntropyCoder.BITRES;
                }
                else
                {
                    /* For N=1, all bits go to fine energy except for a single sign bit */
                    excess           = Inlines.MAX32(0, bit - (C << EntropyCoder.BITRES));
                    bits[j]          = bit - excess;
                    ebits[j]         = 0;
                    fine_priority[j] = 1;
                }

                /* Fine energy can't take advantage of the re-balancing in
                 *  quant_all_bands().
                 * Instead, do the re-balancing here.*/
                if (excess > 0)
                {
                    int extra_fine;
                    int extra_bits;
                    extra_fine       = Inlines.IMIN(excess >> (stereo + EntropyCoder.BITRES), CeltConstants.MAX_FINE_BITS - ebits[j]);
                    ebits[j]        += extra_fine;
                    extra_bits       = extra_fine * C << EntropyCoder.BITRES;
                    fine_priority[j] = (extra_bits >= excess - balance) ? 1 : 0;
                    excess          -= extra_bits;
                }
                balance = excess;

                Inlines.OpusAssert(bits[j] >= 0);
                Inlines.OpusAssert(ebits[j] >= 0);
            }

            /* Save any remaining bits over the cap for the rebalancing in
             *  quant_all_bands(). */
            _balance = balance;

            /* The skipped bands use all their bits for fine energy. */
            for (; j < end; j++)
            {
                ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
                Inlines.OpusAssert(C * ebits[j] << EntropyCoder.BITRES == bits[j]);
                bits[j]          = 0;
                fine_priority[j] = (ebits[j] < 1) ? 1 : 0;
            }

            return(codedBands);
        }
Ejemplo n.º 3
0
        internal int opus_decode_frame(byte[] data, int data_ptr,
                                       int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec)
        {
            SilkDecoder  silk_dec;
            CeltDecoder  celt_dec;
            int          i, silk_ret = 0, celt_ret = 0;
            EntropyCoder dec = new EntropyCoder(); // porting note: stack var
            int          silk_frame_size;
            int          pcm_silk_size;

            short[] pcm_silk;
            int     pcm_transition_silk_size;

            short[] pcm_transition_silk;
            int     pcm_transition_celt_size;

            short[] pcm_transition_celt;
            short[] pcm_transition = null;
            int     redundant_audio_size;

            short[] redundant_audio;

            int      audiosize;
            OpusMode mode;
            int      transition = 0;
            int      start_band;
            int      redundancy       = 0;
            int      redundancy_bytes = 0;
            int      celt_to_silk     = 0;
            int      c;
            int      F2_5, F5, F10, F20;

            int[] window;
            uint  redundant_rng = 0;
            int   celt_accum;

            silk_dec = this.SilkDecoder;
            celt_dec = this.Celt_Decoder;
            F20      = this.Fs / 50;
            F10      = F20 >> 1;
            F5       = F10 >> 1;
            F2_5     = F5 >> 1;
            if (frame_size < F2_5)
            {
                return(OpusError.OPUS_BUFFER_TOO_SMALL);
            }
            /* Limit frame_size to avoid excessive stack allocations. */
            frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3);
            /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
            if (len <= 1)
            {
                data = null;
                /* In that case, don't conceal more than what the ToC says */
                frame_size = Inlines.IMIN(frame_size, this.frame_size);
            }
            if (data != null)
            {
                audiosize = this.frame_size;
                mode      = this.mode;
                dec.dec_init(data, data_ptr, (uint)len);
            }
            else
            {
                audiosize = frame_size;
                mode      = this.prev_mode;

                if (mode == 0)
                {
                    /* If we haven't got any packet yet, all we can do is return zeros */
                    for (i = pcm_ptr; i < pcm_ptr + (audiosize * this.channels); i++)
                    {
                        pcm[i] = 0;
                    }

                    return(audiosize);
                }

                /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
                 * 10, or 20 (e.g. 12.5 or 30 ms). */
                if (audiosize > F20)
                {
                    do
                    {
                        int ret = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0);
                        if (ret < 0)
                        {
                            return(ret);
                        }
                        pcm_ptr   += ret * this.channels;
                        audiosize -= ret;
                    } while (audiosize > 0);

                    return(frame_size);
                }
                else if (audiosize < F20)
                {
                    if (audiosize > F10)
                    {
                        audiosize = F10;
                    }
                    else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
                    {
                        audiosize = F5;
                    }
                }
            }

            /* In fixed-point, we can tell CELT to do the accumulation on top of the
             * SILK PCM buffer. This saves some stack space. */
            celt_accum = ((mode != OpusMode.MODE_CELT_ONLY) && (frame_size >= F10)) ? 1 : 0;

            pcm_transition_silk_size = 0;
            pcm_transition_celt_size = 0;
            if (data != null && this.prev_mode > 0 && (
                    (mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && (this.prev_redundancy == 0)) ||
                    (mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY))
                )
            {
                transition = 1;
                /* Decide where to allocate the stack memory for pcm_transition */
                if (mode == OpusMode.MODE_CELT_ONLY)
                {
                    pcm_transition_celt_size = F5 * this.channels;
                }
                else
                {
                    pcm_transition_silk_size = F5 * this.channels;
                }
            }
            pcm_transition_celt = new short[pcm_transition_celt_size];
            if (transition != 0 && mode == OpusMode.MODE_CELT_ONLY)
            {
                pcm_transition = pcm_transition_celt;
                opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
            }
            if (audiosize > frame_size)
            {
                /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/

                return(OpusError.OPUS_BAD_ARG);
            }
            else
            {
                frame_size = audiosize;
            }

            /* Don't allocate any memory when in CELT-only mode */
            pcm_silk_size = (mode != OpusMode.MODE_CELT_ONLY && (celt_accum == 0)) ? Inlines.IMAX(F10, frame_size) * this.channels : 0;
            pcm_silk      = new short[pcm_silk_size];

            /* SILK processing */
            if (mode != OpusMode.MODE_CELT_ONLY)
            {
                int     lost_flag, decoded_samples;
                short[] pcm_ptr2;
                int     pcm_ptr2_ptr = 0;

                if (celt_accum != 0)
                {
                    pcm_ptr2     = pcm;
                    pcm_ptr2_ptr = pcm_ptr;
                }
                else
                {
                    pcm_ptr2     = pcm_silk;
                    pcm_ptr2_ptr = 0;
                }

                if (this.prev_mode == OpusMode.MODE_CELT_ONLY)
                {
                    DecodeAPI.silk_InitDecoder(silk_dec);
                }

                /* The SILK PLC cannot produce frames of less than 10 ms */
                this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs);

                if (data != null)
                {
                    this.DecControl.nChannelsInternal = this.stream_channels;
                    if (mode == OpusMode.MODE_SILK_ONLY)
                    {
                        if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)
                        {
                            this.DecControl.internalSampleRate = 8000;
                        }
                        else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)
                        {
                            this.DecControl.internalSampleRate = 12000;
                        }
                        else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)
                        {
                            this.DecControl.internalSampleRate = 16000;
                        }
                        else
                        {
                            this.DecControl.internalSampleRate = 16000;
                            Inlines.OpusAssert(false);
                        }
                    }
                    else
                    {
                        /* Hybrid mode */
                        this.DecControl.internalSampleRate = 16000;
                    }
                }

                lost_flag       = data == null ? 1 : 2 * decode_fec;
                decoded_samples = 0;
                do
                {
                    /* Call SILK decoder */
                    int first_frame = (decoded_samples == 0) ? 1 : 0;
                    silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl,
                                                     lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, out silk_frame_size);
                    if (silk_ret != 0)
                    {
                        if (lost_flag != 0)
                        {
                            /* PLC failure should not be fatal */
                            silk_frame_size = frame_size;
                            Arrays.MemSetWithOffset <short>(pcm_ptr2, 0, pcm_ptr2_ptr, frame_size * this.channels);
                        }
                        else
                        {
                            return(OpusError.OPUS_INTERNAL_ERROR);
                        }
                    }
                    pcm_ptr2_ptr    += (silk_frame_size * this.channels);
                    decoded_samples += silk_frame_size;
                } while (decoded_samples < frame_size);
            }

            start_band = 0;
            if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null &&
                dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len)
            {
                /* Check if we have a redundant 0-8 kHz band */
                if (mode == OpusMode.MODE_HYBRID)
                {
                    redundancy = dec.dec_bit_logp(12);
                }
                else
                {
                    redundancy = 1;
                }
                if (redundancy != 0)
                {
                    celt_to_silk = dec.dec_bit_logp(1);

                    /* redundancy_bytes will be at least two, in the non-hybrid
                     * case due to the ec_tell() check above */
                    redundancy_bytes = mode == OpusMode.MODE_HYBRID ?
                                       (int)dec.dec_uint(256) + 2 :
                                       len - ((dec.tell() + 7) >> 3);
                    len -= redundancy_bytes;

                    /* This is a sanity check. It should never happen for a valid
                     * packet, so the exact behaviour is not normative. */
                    if (len * 8 < dec.tell())
                    {
                        len = 0;
                        redundancy_bytes = 0;
                        redundancy       = 0;
                    }
                    /* Shrink decoder because of raw bits */
                    dec.storage = (uint)(dec.storage - redundancy_bytes);
                }
            }
            if (mode != OpusMode.MODE_CELT_ONLY)
            {
                start_band = 17;
            }

            {
                int endband = 21;

                switch (this.bandwidth)
                {
                case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND:
                    endband = 13;
                    break;

                case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND:
                case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND:
                    endband = 17;
                    break;

                case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND:
                    endband = 19;
                    break;

                case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND:
                    endband = 21;
                    break;
                }
                celt_dec.SetEndBand(endband);
                celt_dec.SetChannels(this.stream_channels);
            }

            if (redundancy != 0)
            {
                transition = 0;
                pcm_transition_silk_size = 0;
            }

            pcm_transition_silk = new short[pcm_transition_silk_size];

            if (transition != 0 && mode != OpusMode.MODE_CELT_ONLY)
            {
                pcm_transition = pcm_transition_silk;
                opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
            }

            /* Only allocation memory for redundancy if/when needed */
            redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0;
            redundant_audio      = new short[redundant_audio_size];

            /* 5 ms redundant frame for CELT->SILK*/
            if (redundancy != 0 && celt_to_silk != 0)
            {
                celt_dec.SetStartBand(0);
                celt_dec.celt_decode_with_ec(data, (data_ptr + len), redundancy_bytes,
                                             redundant_audio, 0, F5, null, 0);
                redundant_rng = celt_dec.GetFinalRange();
            }

            /* MUST be after PLC */
            celt_dec.SetStartBand(start_band);

            if (mode != OpusMode.MODE_SILK_ONLY)
            {
                int celt_frame_size = Inlines.IMIN(F20, frame_size);
                /* Make sure to discard any previous CELT state */
                if (mode != this.prev_mode && this.prev_mode > 0 && this.prev_redundancy == 0)
                {
                    celt_dec.ResetState();
                }
                /* Decode CELT */
                celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr,
                                                        len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum);
            }
            else
            {
                if (celt_accum == 0)
                {
                    for (i = pcm_ptr; i < (frame_size * this.channels) + pcm_ptr; i++)
                    {
                        pcm[i] = 0;
                    }
                }

                /* For hybrid -> SILK transitions, we let the CELT MDCT
                 * do a fade-out by decoding a silence frame */
                if (this.prev_mode == OpusMode.MODE_HYBRID && !(redundancy != 0 && celt_to_silk != 0 && this.prev_redundancy != 0))
                {
                    celt_dec.SetStartBand(0);
                    celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum);
                }
            }

            if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0)
            {
                for (i = 0; i < frame_size * this.channels; i++)
                {
                    pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i]));
                }
            }

            window = celt_dec.GetMode().window;

            /* 5 ms redundant frame for SILK->CELT */
            if (redundancy != 0 && celt_to_silk == 0)
            {
                celt_dec.ResetState();
                celt_dec.SetStartBand(0);

                celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0);
                redundant_rng = celt_dec.GetFinalRange();
                CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5,
                                         pcm, (pcm_ptr + this.channels * (frame_size - F2_5)), F2_5, this.channels, window, this.Fs);
            }
            if (redundancy != 0 && celt_to_silk != 0)
            {
                for (c = 0; c < this.channels; c++)
                {
                    for (i = 0; i < F2_5; i++)
                    {
                        pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c];
                    }
                }
                CodecHelpers.smooth_fade(redundant_audio, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)),
                                         pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs);
            }
            if (transition != 0)
            {
                if (audiosize >= F5)
                {
                    for (i = 0; i < this.channels * F2_5; i++)
                    {
                        pcm[i] = pcm_transition[i];
                    }
                    CodecHelpers.smooth_fade(pcm_transition, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)),
                                             pcm, (pcm_ptr + (this.channels * F2_5)), F2_5,
                                             this.channels, window, this.Fs);
                }
                else
                {
                    /* Not enough time to do a clean transition, but we do it anyway
                     * This will not preserve amplitude perfectly and may introduce
                     * a bit of temporal aliasing, but it shouldn't be too bad and
                     * that's pretty much the best we can do. In any case, generating this
                     * transition is pretty silly in the first place */
                    CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr,
                                             pcm, pcm_ptr, F2_5,
                                             this.channels, window, this.Fs);
                }
            }

            if (this.decode_gain != 0)
            {
                int gain;
                gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(((short)(0.5 + (6.48814081e-4f) * (((int)1) << (25)))) /*Inlines.QCONST16(6.48814081e-4f, 25)*/, this.decode_gain));
                for (i = pcm_ptr; i < pcm_ptr + (frame_size * this.channels); i++)
                {
                    int x;
                    x      = Inlines.MULT16_32_P16(pcm[i], gain);
                    pcm[i] = (short)Inlines.SATURATE(x, 32767);
                }
            }

            if (len <= 1)
            {
                this.rangeFinal = 0;
            }
            else
            {
                this.rangeFinal = dec.rng ^ redundant_rng;
            }

            this.prev_mode       = mode;
            this.prev_redundancy = (redundancy != 0 && celt_to_silk == 0) ? 1 : 0;

            return(celt_ret < 0 ? celt_ret : audiosize);
        }