Exemplo n.º 1
0
        internal int celt_decode_with_ec(byte[] data, int data_ptr,
                                         int len, short[] pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum)
        {
            int c, i, N;
            int spread_decision;
            int bits;

            int[][] X;
            int[]   fine_quant;
            int[]   pulses;
            int[]   cap;
            int[]   offsets;
            int[]   fine_priority;
            int[]   tf_res;
            byte[]  collapse_masks;
            int[][] out_syn      = new int[2][];
            int[]   out_syn_ptrs = new int[2];
            int[]   oldBandE, oldLogE, oldLogE2, backgroundLogE;

            int      shortBlocks;
            int      isTransient;
            int      intra_ener;
            int      CC = this.channels;
            int      LM, M;
            int      start;
            int      end;
            int      effEnd;
            int      codedBands;
            int      alloc_trim;
            int      postfilter_pitch;
            int      postfilter_gain;
            int      intensity   = 0;
            int      dual_stereo = 0;
            int      total_bits;
            int      balance;
            int      tell;
            int      dynalloc_logp;
            int      postfilter_tapset;
            int      anti_collapse_rsv;
            int      anti_collapse_on = 0;
            int      silence;
            int      C = this.stream_channels;
            CeltMode mode; // porting note: pointer
            int      nbEBands;
            int      overlap;

            short[] eBands;

            mode        = this.mode;
            nbEBands    = mode.nbEBands;
            overlap     = mode.overlap;
            eBands      = mode.eBands;
            start       = this.start;
            end         = this.end;
            frame_size *= this.downsample;

            oldBandE       = this.oldEBands;
            oldLogE        = this.oldLogE;
            oldLogE2       = this.oldLogE2;
            backgroundLogE = this.backgroundLogE;

            {
                for (LM = 0; LM <= mode.maxLM; LM++)
                {
                    if (mode.shortMdctSize << LM == frame_size)
                    {
                        break;
                    }
                }
                if (LM > mode.maxLM)
                {
                    return(OpusError.OPUS_BAD_ARG);
                }
            }
            M = 1 << LM;

            if (len < 0 || len > 1275 || pcm == null)
            {
                return(OpusError.OPUS_BAD_ARG);
            }

            N = M * mode.shortMdctSize;
            c = 0; do
            {
                out_syn[c]      = this.decode_mem[c];
                out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N;
            } while (++c < CC);

            effEnd = end;
            if (effEnd > mode.effEBands)
            {
                effEnd = mode.effEBands;
            }

            if (data == null || len <= 1)
            {
                this.celt_decode_lost(N, LM);
                CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);

                return(frame_size / this.downsample);
            }

            if (dec == null)
            {
                // If no entropy decoder was passed into this function, we need to create
                // a new one here for local use only. It only exists in this function scope.
                dec = new EntropyCoder();
                dec.dec_init(data, data_ptr, (uint)len);
            }

            if (C == 1)
            {
                for (i = 0; i < nbEBands; i++)
                {
                    oldBandE[i] = Inlines.MAX16(oldBandE[i], oldBandE[nbEBands + i]);
                }
            }

            total_bits = len * 8;
            tell       = dec.tell();

            if (tell >= total_bits)
            {
                silence = 1;
            }
            else if (tell == 1)
            {
                silence = dec.dec_bit_logp(15);
            }
            else
            {
                silence = 0;
            }

            if (silence != 0)
            {
                /* Pretend we've read all the remaining bits */
                tell             = len * 8;
                dec.nbits_total += tell - dec.tell();
            }

            postfilter_gain   = 0;
            postfilter_pitch  = 0;
            postfilter_tapset = 0;
            if (start == 0 && tell + 16 <= total_bits)
            {
                if (dec.dec_bit_logp(1) != 0)
                {
                    int qg, octave;
                    octave           = (int)dec.dec_uint(6);
                    postfilter_pitch = (16 << octave) + (int)dec.dec_bits(4 + (uint)octave) - 1;
                    qg = (int)dec.dec_bits(3);
                    if (dec.tell() + 2 <= total_bits)
                    {
                        postfilter_tapset = dec.dec_icdf(Tables.tapset_icdf, 2);
                    }
                    postfilter_gain = ((short)(0.5 + (.09375f) * (((int)1) << (15)))) /*Inlines.QCONST16(.09375f, 15)*/ * (qg + 1);
                }
                tell = dec.tell();
            }

            if (LM > 0 && tell + 3 <= total_bits)
            {
                isTransient = dec.dec_bit_logp(3);
                tell        = dec.tell();
            }
            else
            {
                isTransient = 0;
            }

            if (isTransient != 0)
            {
                shortBlocks = M;
            }
            else
            {
                shortBlocks = 0;
            }

            /* Decode the global flags (first symbols in the stream) */
            intra_ener = tell + 3 <= total_bits?dec.dec_bit_logp(3) : 0;

            /* Get band energies */
            QuantizeBands.unquant_coarse_energy(mode, start, end, oldBandE,
                                                intra_ener, dec, C, LM);

            tf_res = new int[nbEBands];
            CeltCommon.tf_decode(start, end, isTransient, tf_res, LM, dec);

            tell            = dec.tell();
            spread_decision = Spread.SPREAD_NORMAL;
            if (tell + 4 <= total_bits)
            {
                spread_decision = dec.dec_icdf(Tables.spread_icdf, 5);
            }

            cap = new int[nbEBands];

            CeltCommon.init_caps(mode, cap, LM, C);

            offsets = new int[nbEBands];

            dynalloc_logp = 6;
            total_bits  <<= EntropyCoder.BITRES;
            tell          = (int)dec.tell_frac();
            for (i = start; i < end; i++)
            {
                int width, quanta;
                int dynalloc_loop_logp;
                int boost;
                width = C * (eBands[i + 1] - eBands[i]) << LM;

                /* quanta is 6 bits, but no more than 1 bit/sample
                 * and no less than 1/8 bit/sample */
                quanta             = Inlines.IMIN(width << EntropyCoder.BITRES, Inlines.IMAX(6 << EntropyCoder.BITRES, width));
                dynalloc_loop_logp = dynalloc_logp;
                boost = 0;
                while (tell + (dynalloc_loop_logp << EntropyCoder.BITRES) < total_bits && boost < cap[i])
                {
                    int flag;
                    flag = dec.dec_bit_logp((uint)dynalloc_loop_logp);
                    tell = (int)dec.tell_frac();
                    if (flag == 0)
                    {
                        break;
                    }
                    boost             += quanta;
                    total_bits        -= quanta;
                    dynalloc_loop_logp = 1;
                }
                offsets[i] = boost;
                /* Making dynalloc more likely */
                if (boost > 0)
                {
                    dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1);
                }
            }

            fine_quant = new int[nbEBands];
            alloc_trim = tell + (6 << EntropyCoder.BITRES) <= total_bits?
                         dec.dec_icdf(Tables.trim_icdf, 7) : 5;

            bits = (((int)len * 8) << EntropyCoder.BITRES) - (int)dec.tell_frac() - 1;
            anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= ((LM + 2) << EntropyCoder.BITRES) ? (1 << EntropyCoder.BITRES) : 0;
            bits -= anti_collapse_rsv;

            pulses        = new int[nbEBands];
            fine_priority = new int[nbEBands];

            codedBands = Rate.compute_allocation(mode, start, end, offsets, cap,
                                                 alloc_trim, ref intensity, ref dual_stereo, bits, out balance, pulses,
                                                 fine_quant, fine_priority, C, LM, dec, 0, 0, 0);

            QuantizeBands.unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C);

            c = 0;
            do
            {
                Arrays.MemMoveInt(decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + overlap / 2);
            } while (++c < CC);

            /* Decode fixed codebook */
            collapse_masks = new byte[C * nbEBands];

            X = Arrays.InitTwoDimensionalArray <int>(C, N);   /**< Interleaved normalised MDCTs */

            Bands.quant_all_bands(0, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks,
                                  null, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
                                  len * (8 << EntropyCoder.BITRES) - anti_collapse_rsv, balance, dec, LM, codedBands, ref this.rng);

            if (anti_collapse_rsv > 0)
            {
                anti_collapse_on = (int)dec.dec_bits(1);
            }

            QuantizeBands.unquant_energy_finalise(mode, start, end, oldBandE,
                                                  fine_quant, fine_priority, len * 8 - dec.tell(), dec, C);

            if (anti_collapse_on != 0)
            {
                Bands.anti_collapse(mode, X, collapse_masks, LM, C, N,
                                    start, end, oldBandE, oldLogE, oldLogE2, pulses, this.rng);
            }

            if (silence != 0)
            {
                for (i = 0; i < C * nbEBands; i++)
                {
                    oldBandE[i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
                }
            }

            CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, oldBandE, start, effEnd,
                                      C, CC, isTransient, LM, this.downsample, silence);

            c = 0; do
            {
                this.postfilter_period     = Inlines.IMAX(this.postfilter_period, CeltConstants.COMBFILTER_MINPERIOD);
                this.postfilter_period_old = Inlines.IMAX(this.postfilter_period_old, CeltConstants.COMBFILTER_MINPERIOD);
                CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c], out_syn[c], out_syn_ptrs[c], this.postfilter_period_old, this.postfilter_period, mode.shortMdctSize,
                                       this.postfilter_gain_old, this.postfilter_gain, this.postfilter_tapset_old, this.postfilter_tapset,
                                       mode.window, overlap);
                if (LM != 0)
                {
                    CeltCommon.comb_filter(
                        out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
                        out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
                        this.postfilter_period, postfilter_pitch, N - mode.shortMdctSize,
                        this.postfilter_gain, postfilter_gain, this.postfilter_tapset, postfilter_tapset,
                        mode.window, overlap);
                }
            } while (++c < CC);
            this.postfilter_period_old = this.postfilter_period;
            this.postfilter_gain_old   = this.postfilter_gain;
            this.postfilter_tapset_old = this.postfilter_tapset;
            this.postfilter_period     = postfilter_pitch;
            this.postfilter_gain       = postfilter_gain;
            this.postfilter_tapset     = postfilter_tapset;
            if (LM != 0)
            {
                this.postfilter_period_old = this.postfilter_period;
                this.postfilter_gain_old   = this.postfilter_gain;
                this.postfilter_tapset_old = this.postfilter_tapset;
            }

            if (C == 1)
            {
                Array.Copy(oldBandE, 0, oldBandE, nbEBands, nbEBands);
            }

            /* In case start or end were to change */
            if (isTransient == 0)
            {
                int max_background_increase;
                Array.Copy(oldLogE, oldLogE2, 2 * nbEBands);
                Array.Copy(oldBandE, oldLogE, 2 * nbEBands);

                /* 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 allow up to 6 dB
                 * increase for each update.*/
                if (this.loss_count < 10)
                {
                    max_background_increase = M * ((short)(0.5 + (0.001f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(0.001f, CeltConstants.DB_SHIFT)*/;
                }
                else
                {
                    max_background_increase = ((short)(0.5 + (1.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/;
                }
                for (i = 0; i < 2 * nbEBands; i++)
                {
                    backgroundLogE[i] = Inlines.MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]);
                }
            }
            else
            {
                for (i = 0; i < 2 * nbEBands; i++)
                {
                    oldLogE[i] = Inlines.MIN16(oldLogE[i], oldBandE[i]);
                }
            }
            c = 0; do
            {
                for (i = 0; i < start; i++)
                {
                    oldBandE[c * nbEBands + i] = 0;
                    oldLogE[c * nbEBands + i]  = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
                }
                for (i = end; i < nbEBands; i++)
                {
                    oldBandE[c * nbEBands + i] = 0;
                    oldLogE[c * nbEBands + i]  = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
                }
            } while (++c < 2);
            this.rng = dec.rng;

            CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);
            this.loss_count = 0;

            if (dec.tell() > 8 * len)
            {
                return(OpusError.OPUS_INTERNAL_ERROR);
            }
            if (dec.get_error() != 0)
            {
                this.error = 1;
            }
            return(frame_size / this.downsample);
        }
Exemplo n.º 2
0
        // fixme: test the perf of this alternate implementation
        //int logSum(int a, int b)
        //{
        //    return log2(pow(4, a) + pow(4, b)) / 2;
        //}

        internal static void surround_analysis <T>(CeltMode celt_mode, T[] pcm, int pcm_ptr,
                                                   int[] bandLogE, int[] mem, int[] preemph_mem,
                                                   int len, int overlap, int channels, int rate, opus_copy_channel_in_func <T> copy_channel_in
                                                   )
        {
            int c;
            int i;
            int LM;

            int[] pos = { 0, 0, 0, 0, 0, 0, 0, 0 };
            int   upsample;
            int   frame_size;
            int   channel_offset;

            int[][] bandE    = Arrays.InitTwoDimensionalArray <int>(1, 21);
            int[][] maskLogE = Arrays.InitTwoDimensionalArray <int>(3, 21);
            int[]   input;
            short[] x;
            int[][] freq;

            upsample   = CeltCommon.resampling_factor(rate);
            frame_size = len * upsample;

            for (LM = 0; LM < celt_mode.maxLM; LM++)
            {
                if (celt_mode.shortMdctSize << LM == frame_size)
                {
                    break;
                }
            }

            input = new int[frame_size + overlap];
            x     = new short[len];
            freq  = Arrays.InitTwoDimensionalArray <int>(1, frame_size);

            channel_pos(channels, pos);

            for (c = 0; c < 3; c++)
            {
                for (i = 0; i < 21; i++)
                {
                    maskLogE[c][i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
                }
            }

            for (c = 0; c < channels; c++)
            {
                Array.Copy(mem, c * overlap, input, 0, overlap);
                copy_channel_in(x, 0, 1, pcm, pcm_ptr, channels, c, len);
                BoxedValueInt boxed_preemph = new BoxedValueInt(preemph_mem[c]);
                CeltCommon.celt_preemphasis(x, input, overlap, frame_size, 1, upsample, celt_mode.preemph, boxed_preemph, 0);
                preemph_mem[c] = boxed_preemph.Val;

                MDCT.clt_mdct_forward(
                    celt_mode.mdct,
                    input,
                    0,
                    freq[0],
                    0,
                    celt_mode.window,
                    overlap,
                    celt_mode.maxLM - LM,
                    1);
                if (upsample != 1)
                {
                    int bound = len;
                    for (i = 0; i < bound; i++)
                    {
                        freq[0][i] *= upsample;
                    }
                    for (; i < frame_size; i++)
                    {
                        freq[0][i] = 0;
                    }
                }

                Bands.compute_band_energies(celt_mode, freq, bandE, 21, 1, LM);
                QuantizeBands.amp2Log2(celt_mode, 21, 21, bandE[0], bandLogE, 21 * c, 1);
                /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
                for (i = 1; i < 21; i++)
                {
                    bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i - 1] - ((short)(0.5 + (1.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/);
                }
                for (i = 19; i >= 0; i--)
                {
                    bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i + 1] - ((short)(0.5 + (2.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(2.0f, CeltConstants.DB_SHIFT)*/);
                }
                if (pos[c] == 1)
                {
                    for (i = 0; i < 21; i++)
                    {
                        maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i]);
                    }
                }
                else if (pos[c] == 3)
                {
                    for (i = 0; i < 21; i++)
                    {
                        maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i]);
                    }
                }
                else if (pos[c] == 2)
                {
                    for (i = 0; i < 21; i++)
                    {
                        maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i] - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
                        maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i] - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
                    }
                }
                Array.Copy(input, frame_size, mem, c * overlap, overlap);
            }
            for (i = 0; i < 21; i++)
            {
                maskLogE[1][i] = Inlines.MIN32(maskLogE[0][i], maskLogE[2][i]);
            }
            channel_offset = Inlines.HALF16(Inlines.celt_log2(((int)(0.5 + (2.0f) * (((int)1) << (14)))) /*Inlines.QCONST32(2.0f, 14)*/ / (channels - 1)));
            for (c = 0; c < 3; c++)
            {
                for (i = 0; i < 21; i++)
                {
                    maskLogE[c][i] += channel_offset;
                }
            }

            for (c = 0; c < channels; c++)
            {
                int[] mask;
                if (pos[c] != 0)
                {
                    mask = maskLogE[pos[c] - 1];
                    for (i = 0; i < 21; i++)
                    {
                        bandLogE[21 * c + i] = bandLogE[21 * c + i] - mask[i];
                    }
                }
                else
                {
                    for (i = 0; i < 21; i++)
                    {
                        bandLogE[21 * c + i] = 0;
                    }
                }
            }
        }