Ejemplo n.º 1
0
        /// <summary>
        /// Create a new resampler with fractional input/output rates. The sampling
        /// rate ratio is an arbitrary rational number with both the numerator and
        /// denominator being 32-bit integers.
        /// </summary>
        /// <param name="nb_channels">The number of channels to be processed</param>
        /// <param name="ratio_num">Numerator of sampling rate ratio</param>
        /// <param name="ratio_den">Denominator of sampling rate ratio</param>
        /// <param name="in_rate">Input sample rate rounded to the nearest integer (in hz)</param>
        /// <param name="out_rate">Output sample rate rounded to the nearest integer (in hz)</param>
        /// <param name="quality">Resampling quality, from 0 to 10</param>
        /// <returns>A newly created restampler</returns>
        public SpeexResampler(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality)
        {
            int i;

            if (quality > 10 || quality < 0)
            {
                throw new ArgumentException("Quality must be between 0 and 10");
            }
            this.initialised       = 0;
            this.started           = 0;
            this.in_rate           = 0;
            this.out_rate          = 0;
            this.num_rate          = 0;
            this.den_rate          = 0;
            this.quality           = -1;
            this.sinc_table_length = 0;
            this.mem_alloc_size    = 0;
            this.filt_len          = 0;
            this.mem           = null;
            this.resampler_ptr = null;
            this.cutoff        = 1.0f;
            this.nb_channels   = nb_channels;
            this.in_stride     = 1;
            this.out_stride    = 1;
            this.buffer_size   = 160;

            /* Per channel data */
            this.last_sample   = new int[nb_channels];
            this.magic_samples = new int[nb_channels];
            this.samp_frac_num = new int[nb_channels];
            for (i = 0; i < nb_channels; i++)
            {
                this.last_sample[i]   = 0;
                this.magic_samples[i] = 0;
                this.samp_frac_num[i] = 0;
            }

            this.Quality = quality;
            this.SetRateFraction(ratio_num, ratio_den, in_rate, out_rate);

            this.update_filter();

            this.initialised = 1;
        }
Ejemplo n.º 2
0
        private void update_filter()
        {
            int old_length;

            old_length      = this.filt_len;
            this.oversample = QualityMapping.quality_map[this.quality].oversample;
            this.filt_len   = QualityMapping.quality_map[this.quality].base_length;

            if (this.num_rate > this.den_rate)
            {
                /* down-sampling */
                this.cutoff = QualityMapping.quality_map[this.quality].downsample_bandwidth * this.den_rate / this.num_rate;
                /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
                this.filt_len = this.filt_len * this.num_rate / this.den_rate;
                /* Round up to make sure we have a multiple of 8 */
                this.filt_len = ((this.filt_len - 1) & (~0x7)) + 8;
                if (2 * this.den_rate < this.num_rate)
                {
                    this.oversample >>= 1;
                }
                if (4 * this.den_rate < this.num_rate)
                {
                    this.oversample >>= 1;
                }
                if (8 * this.den_rate < this.num_rate)
                {
                    this.oversample >>= 1;
                }
                if (16 * this.den_rate < this.num_rate)
                {
                    this.oversample >>= 1;
                }
                if (this.oversample < 1)
                {
                    this.oversample = 1;
                }
            }
            else
            {
                /* up-sampling */
                this.cutoff = QualityMapping.quality_map[this.quality].upsample_bandwidth;
            }

            if (this.den_rate <= 16 * (this.oversample + 8))
            {
                int i;
                if (this.sinc_table == null)
                {
                    this.sinc_table = new short[this.filt_len * this.den_rate];
                }
                else if (this.sinc_table_length < this.filt_len * this.den_rate)
                {
                    this.sinc_table        = new short[this.filt_len * this.den_rate];
                    this.sinc_table_length = this.filt_len * this.den_rate;
                }
                for (i = 0; i < this.den_rate; i++)
                {
                    int j;
                    for (j = 0; j < this.filt_len; j++)
                    {
                        this.sinc_table[i * this.filt_len + j] = sinc(this.cutoff, ((j - (int)this.filt_len / 2 + 1) - ((float)i) / this.den_rate), this.filt_len, QualityMapping.quality_map[this.quality].window_func);
                    }
                }
                this.resampler_ptr = resampler_basic_direct_single;
                /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
            }
            else
            {
                int i;
                if (this.sinc_table == null)
                {
                    this.sinc_table = new short[this.filt_len * this.oversample + 8];
                }
                else if (this.sinc_table_length < this.filt_len * this.oversample + 8)
                {
                    this.sinc_table        = new short[this.filt_len * this.oversample + 8];
                    this.sinc_table_length = this.filt_len * this.oversample + 8;
                }
                for (i = -4; i < (int)(this.oversample * this.filt_len + 4); i++)
                {
                    this.sinc_table[i + 4] = sinc(this.cutoff, (i / (float)this.oversample - this.filt_len / 2), this.filt_len, QualityMapping.quality_map[this.quality].window_func);
                }
                this.resampler_ptr = resampler_basic_interpolate_single;
                /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
            }
            this.int_advance  = this.num_rate / this.den_rate;
            this.frac_advance = this.num_rate % this.den_rate;


            /* Here's the place where we update the filter memory to take into account
             * the change in filter length. It's probably the messiest part of the code
             * due to handling of lots of corner cases. */
            if (this.mem == null)
            {
                int i;
                this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
                this.mem            = new short[this.nb_channels * this.mem_alloc_size];
                for (i = 0; i < this.nb_channels * this.mem_alloc_size; i++)
                {
                    this.mem[i] = 0;
                }
                /*speex_warning("init filter");*/
            }
            else if (this.started == 0)
            {
                int i;
                this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
                this.mem            = new short[this.nb_channels * this.mem_alloc_size];
                for (i = 0; i < this.nb_channels * this.mem_alloc_size; i++)
                {
                    this.mem[i] = 0;
                }
                /*speex_warning("reinit filter");*/
            }
            else if (this.filt_len > old_length)
            {
                int i;
                /* Increase the filter length */
                /*speex_warning("increase filter size");*/
                int old_alloc_size = this.mem_alloc_size;
                if ((this.filt_len - 1 + this.buffer_size) > this.mem_alloc_size)
                {
                    this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
                    this.mem            = new short[this.nb_channels * this.mem_alloc_size];
                }
                for (i = this.nb_channels - 1; i >= 0; i--)
                {
                    int j;
                    int olen = old_length;
                    /*if (st.magic_samples[i])*/
                    {
                        /* Try and remove the magic samples as if nothing had happened */

                        /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
                        olen = old_length + 2 * this.magic_samples[i];
                        for (j = old_length - 2 + this.magic_samples[i]; j >= 0; j--)
                        {
                            this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]] = this.mem[i * old_alloc_size + j];
                        }
                        for (j = 0; j < this.magic_samples[i]; j++)
                        {
                            this.mem[i * this.mem_alloc_size + j] = 0;
                        }
                        this.magic_samples[i] = 0;
                    }
                    if (this.filt_len > olen)
                    {
                        /* If the new filter length is still bigger than the "augmented" length */
                        /* Copy data going backward */
                        for (j = 0; j < olen - 1; j++)
                        {
                            this.mem[i * this.mem_alloc_size + (this.filt_len - 2 - j)] = this.mem[i * this.mem_alloc_size + (olen - 2 - j)];
                        }
                        /* Then put zeros for lack of anything better */
                        for (; j < this.filt_len - 1; j++)
                        {
                            this.mem[i * this.mem_alloc_size + (this.filt_len - 2 - j)] = 0;
                        }
                        /* Adjust last_sample */
                        this.last_sample[i] += (this.filt_len - olen) / 2;
                    }
                    else
                    {
                        /* Put back some of the magic! */
                        this.magic_samples[i] = (olen - this.filt_len) / 2;
                        for (j = 0; j < this.filt_len - 1 + this.magic_samples[i]; j++)
                        {
                            this.mem[i * this.mem_alloc_size + j] = this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]];
                        }
                    }
                }
            }
            else if (this.filt_len < old_length)
            {
                int i;

                /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
                 * samples so they can be used directly as input the next time(s) */
                for (i = 0; i < this.nb_channels; i++)
                {
                    int j;
                    int old_magic = this.magic_samples[i];
                    this.magic_samples[i] = (old_length - this.filt_len) / 2;
                    /* We must copy some of the memory that's no longer used */
                    /* Copy data going backward */
                    for (j = 0; j < this.filt_len - 1 + this.magic_samples[i] + old_magic; j++)
                    {
                        this.mem[i * this.mem_alloc_size + j] = this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]];
                    }
                    this.magic_samples[i] += old_magic;
                }
            }
        }