Beispiel #1
0
        /// <summary>
        /// Compute Mel Frequency Filters
        /// </summary>
        /// <param name="winsize">the window size</param>
        /// <param name="sampleRate">the sample rate</param>
        /// <param name="numberFilters">number of filters in the filterbank</param>
        /// <param name="minFreq">lowest frequency in the range of interest</param>
        public MelFilter(int winsize, int sampleRate, int numberFilters, int minFreq)
        {
            // arrays to store the mel frequencies and the herz frequencies
            var mel  = new double[sampleRate / 2 - minFreq + 1];
            var freq = new double[sampleRate / 2 - minFreq + 1];

            // Mel Scale from StartFreq to SamplingRate/2, step every 1Hz
            for (int f = minFreq; f <= sampleRate / 2; f++)
            {
                mel[f - minFreq]  = MelUtils.LinToMelFreq(f);
                freq[f - minFreq] = f;
            }

            // prepare filters
            var freqs = new double[numberFilters + 2];

            melScaleFreqsIndex = new int[numberFilters + 2];

            for (int f = 0; f < freqs.Length; f++)
            {
                double melIndex = 1.0 + ((mel[mel.Length - 1] - 1.0) /
                                         (freqs.Length - 1.0) * f);
                double min = Math.Abs(mel[0] - melIndex);
                freqs[f] = freq[0];

                for (int j = 1; j < mel.Length; j++)
                {
                    double cur = Math.Abs(mel[j] - melIndex);
                    if (cur < min)
                    {
                        min      = cur;
                        freqs[f] = freq[j];
                    }
                }

                melScaleFreqsIndex[f] = MathUtils.FreqToIndex(freqs[f], sampleRate, winsize);
            }

            // triangle heights
            melScaleTriangleHeights = new double[numberFilters];
            for (int j = 0; j < melScaleTriangleHeights.Length; j++)
            {
                // Let's make the filter area equal to 1.
                // filterHeight = 2.0 / (rightEdge - leftEdge);
                melScaleTriangleHeights[j] = 2.0 / (freqs[j + 2] - freqs[j]);
            }

            var fftFreq = new double[winsize / 2 + 1];

            for (int j = 0; j < fftFreq.Length; j++)
            {
                fftFreq[j] = ((sampleRate / 2) / (fftFreq.Length - 1.0)) * j;
            }

            // Compute the mel filter Weights
            filterWeights = new Matrix(numberFilters, winsize / 2);
            for (int j = 0; j < numberFilters; j++)
            {
                for (int k = 0; k < fftFreq.Length; k++)
                {
                    if ((fftFreq[k] > freqs[j]) && (fftFreq[k] <= freqs[j + 1]))
                    {
                        filterWeights.MatrixData[j][k] = (melScaleTriangleHeights[j] *
                                                          ((fftFreq[k] - freqs[j]) / (freqs[j + 1] - freqs[j])));
                    }
                    if ((fftFreq[k] > freqs[j + 1]) &&
                        (fftFreq[k] < freqs[j + 2]))
                    {
                        filterWeights.MatrixData[j][k] += (melScaleTriangleHeights[j] *
                                                           ((freqs[j + 2] - fftFreq[k]) / (freqs[j + 2] - freqs[j + 1])));
                    }
                }
            }
        }
        /// <summary>
        /// Creates a new MelFilterBank.
        /// </summary>
        /// <param name="minFreq">The minimum frequency in hz to be considered, i.e.
        /// the left edge of the first TriangleFilter.</param>
        /// <param name="maxFreq">The maximum frequency in hz to be considered, i.e.
        /// the right edge of the last TriangleFilter.</param>
        /// <param name="numMelBands">The number of Mel bands to be calculated, i.e.
        /// the number of TriangleFilters to be applied.</param>
        /// <param name="numBins">The number of bins that are present in the fft_buffer
        /// that will be passed to the MelFilterBank.Apply method. This is also
        /// required to properly configure the TriangleFilter instances which
        /// operate on array indices only. (half the window size)</param>
        /// <param name="sampleRate">The original sample rate the FFT buffer which will
        /// be passed to MelFilterBank.Apply is based on.</param>
        /// <param name="doNormalizeFilterArea">If set to "true", the area of the
        /// created TriangleFilter will be normalized, e.g. the height of the
        /// filter's triangle shape will be configured in a way, that the area
        /// of the triangle shape equals one.</param>
        public MelFilterBank(double minFreq, double maxFreq, int numMelBands, int numBins, int sampleRate, bool doNormalizeFilterArea)
        {
            this.minFreq               = minFreq;
            this.maxFreq               = maxFreq;
            this.numMelBands           = numMelBands;
            this.numBins               = numBins;
            this.sampleRate            = sampleRate;
            this.doNormalizeFilterArea = doNormalizeFilterArea;

            // Let's do some argument checking
            if ((minFreq >= maxFreq) || (maxFreq == 0))
            {
                throw new ArgumentException(String.Format("Invalid min/max frequencies for MelFilterBank: min = '{0}' max = '{1}'", minFreq, maxFreq));
            }

            if (numMelBands == 0)
            {
                throw new ArgumentException(String.Format("Invalid number of mel bands for MelFilterBank: n = {0}", numMelBands));
            }

            if (sampleRate == 0)
            {
                throw new ArgumentException(String.Format("Invalid sample rate for MelFilterBank: s = {0}", sampleRate));
            }

            if (numBins == 0)
            {
                throw new ArgumentException(String.Format("Invalid number of bins for MelFilterBank: s = '{0}'", numBins));
            }

            // 2 * numBins should be the same as window length
            double deltaFreq = (double)sampleRate / (2 * numBins);

            double melMin = MelUtils.LinToMelFreq(minFreq);
            double melMax = MelUtils.LinToMelFreq(maxFreq);

            // We divide by #band + 1 as min / max should present the beginning / end
            // of beginng up / ending low slope, i.e. it's not the centers of each
            // band that represent min/max frequency in mel bands.
            double deltaFreqMel = (melMax - melMin) / (numMelBands + 1);

            // Fill up equidistant spacing in mel-space
            double melLeft = melMin;

            for (int i = 0; i < numMelBands; i++)
            {
                double melCenter = melLeft + deltaFreqMel;
                double melRight  = melCenter + deltaFreqMel;

                double leftHz  = MelUtils.MelToLinFreq(melLeft);
                double rightHz = MelUtils.MelToLinFreq(melRight);

                // align to closest num_bins (round)
                int leftBin  = (int)((leftHz / deltaFreq) + 0.5);
                int rightBin = (int)((rightHz / deltaFreq) + 0.5);

                // calculate normalized height
                double height = 1.0;

                if (doNormalizeFilterArea)
                {
                    height = 2.0 / (rightBin - leftBin);
                }

                // Create the actual filter
                var filter = new TriangleFilter(leftBin, rightBin, height);
                filters.Add(filter);

                // next left edge is current center
                melLeft = melCenter;
            }
        }