/// <summary> /// Return a list of freq/gain, at the ERB centers /// Assuming you smoothed the data... /// </summary> /// <param name="data">data from ERB.smooth</param> /// <param name="sr">sample rate</param> /// <param name="scaleFactor">1.0 for ~38 bands. 0.5 for twice as many...</param> /// <returns></returns> public static FilterProfile profile(double[] data, uint sr, double scaleFactor) { FilterProfile pts = new FilterProfile(); int dl = data.Length; for (double j = 1; j < ERB.ERBVal(sr / 2) + 1; j += scaleFactor) { double f = ERB.invERBVal(j); double n = f * 2 * dl / sr; if (n < dl) { double g = data[(int)n]; pts.Add(new FreqGain(f, g)); } } return(pts); }
public static double WindowLength(int bin, int bins, double sampleRate, SmoothingType type, double resolution, out int bin0, out int bin1) { double len = 0; bin0 = bin; bin1 = bin; // Frequency (Hz) of the center of the given bin: // Bins range from 0 through sampleRate-1, // so the width of each bin is (sampleRate/bins) Hz, // and the center of bin <N> is (<N> * (sampleRate/bins)) + half a bin double binw = sampleRate / bins; double freq = (0.5 + bin) * binw; // The window goes from f0=(freq/X) to f1=(freq*X) // where the width of the window is (resolution)*(octaves or ERB bands) double bw = 0; if (type == SmoothingType.OCTAVE) { // Fraction X of an octave is f(x) = 2^x bw = freq * Math.Pow(2, resolution); } else if (type == SmoothingType.ERB) { bw = ERB.ERBWidth(freq) * resolution; } // f.x - f/x = bw // f.x.x - bw.x - f = 0 // f.x.(x-(bw/f)) = f // x.(x-(bw/f)) = 1 // x.x - bw.x - 1/ if (type == SmoothingType.OCTAVE) { // One octave is frequency*2. Two is freq*4. // Fraction X of an octave is f(x) = 2^x // double f1 = freq * (1 - Math.Pow(2, r2)); // double f2 = freq * (1 - Math.Pow(2, r2)); } return(len * resolution); }
public static double bin2f(double bin, uint sr) { double scale = (_bins / ERB.ERBVal(sr / 2)); return(ERB.invERBVal(bin / scale)); }
public static double f2bin(double f, uint sr) { double scale = (_bins / ERB.ERBVal(sr / 2)); return(ERB.ERBVal(f) * scale); }
private static double[] magbands(ISoundObj impulse, double bins) { uint nSR = impulse.SampleRate; uint nSR2 = nSR / 2; int nn = (int)bins + 1; double[] muff = new double[nn]; ushort nChannels = impulse.NumChannels; for (ushort c = 0; c < nChannels; c++) { // Read channel into a buffer SingleChannel channel = impulse.Channel(c); SoundBuffer buff = new SoundBuffer(channel); buff.ReadAll(); // And then double in length to prevent wraparound buff.PadTo(buff.Count * 2); // Pad to next higher power of two buff.PadToPowerOfTwo(); // Read out into array of complex Complex[][] data = buff.ToComplexArray(); Complex[] cdata = data[0]; // Then we're done with the buffer for this channel buff = null; GC.Collect(); // FFT in place Fourier.FFT(cdata.Length, cdata); int n = cdata.Length / 2; // Drop the FFT magnitudes into the 'muff' array // according to an ERB-based scale (near-logarithmic). // Then smoothing is easy. double binw = (nSR2 / (double)n); int prevbin = 0; int nbin = 0; double v = 0; for (int j = 0; j < n; j++) { double f = (double)j * binw; // equiv freq, Hz int bin = (int)ERB.f2bin(f, nSR, bins); // the bin we drop this sample in v += cdata[j].Magnitude; nbin++; if ((bin > prevbin) || (j == n - 1)) { muff[prevbin] += (v / nbin); v = 0; nbin = 0; prevbin = bin; } } } // Now muff is sum(all channels) of average-magnitude-per-bin. // Divide it all by the number of channels, so our gains are averaged... for (int j = 0; j < muff.Length; j++) { muff[j] = muff[j] / nChannels; } return(muff); }