public override void ReadFrame(float[] fftResult) { // Check output array size switch (outputFormat) { case OutputFormat.Decibel: case OutputFormat.Magnitudes: case OutputFormat.MagnitudesSquared: if (fftResult.Length != fft.Size / 2) { throw new ArgumentException("the provided FFT result array has an invalid size"); } break; default: if (fftResult.Length != fft.Size) { throw new ArgumentException("the provided FFT result array has an invalid size"); } break; } base.ReadFrame(frameBuffer); // do fourier transform fft.Forward(frameBuffer, fftBuffer); // normalize fourier results switch (outputFormat) { case OutputFormat.Decibel: // TODO check if calculation corresponds to Haitsma & Kalker paper FFTUtil.Results(fftBuffer, fftResult); break; case OutputFormat.Magnitudes: FFTUtil.CalculateMagnitudes(fftBuffer, fftResult); break; case OutputFormat.MagnitudesSquared: // TODO check if consumers of this mode really want it or if they want unsquared magnitudes instead // (e.g. OLTW; this code path returns CalculateMagnitudesSquared for some time, as a temp test for OLTW, // but originally returned CalculateMagnitudes) FFTUtil.CalculateMagnitudesSquared(fftBuffer, fftResult); break; case OutputFormat.MagnitudesAndPhases: FFTUtil.CalculateMagnitudes(fftBuffer, fftResult, 0); FFTUtil.CalculatePhases(fftBuffer, fftResult, fft.Size / 2); break; case OutputFormat.Raw: // Nothing to do here, result is already in raw format, just copy it to output buffer Buffer.BlockCopy(fftBuffer, 0, fftResult, 0, fft.Size * 4); break; } OnFrameReadSTFT(fftResult); }
public VoiceProfile() : base() { Name = "Voice"; // vocal range 80 - 1100 Hz: http://en.wikipedia.org/wiki/Vocal_range MinFrequency = 80; MaxFrequency = 1100; this.frequencyBands = FFTUtil.CalculateFrequencyBoundariesLog(MinFrequency, MaxFrequency, FrequencyBands); }
public BassProfile() : base() { Name = "Bass"; // bass range 80 - 350 Hz: http://www.listenhear.co.uk/general_acoustics.htm MinFrequency = 80; MaxFrequency = 350; this.frequencyBands = FFTUtil.CalculateFrequencyBoundariesLog(MinFrequency, MaxFrequency, FrequencyBands); }
private static void FrequencyDistributionBlockProcess(float[] buffer, double[] target, PFFFT.PFFFT fft) { windowFunction.Apply(buffer); fft.Forward(buffer); for (int i = 0; i < buffer.Length; i += 2) { buffer[i / 2] = FFTUtil.CalculateMagnitude(buffer[i], buffer[i + 1]) / buffer.Length * 2; } for (int i = 0; i < target.Length; i++) { target[i] += buffer[i]; } }
public HumanProfile() : base() { Name = "Human (slow!)"; FrameSize = 16384; FrameStep = 512; SampleRate = 44100; MinFrequency = 80; MaxFrequency = 16000; FrequencyBands = 33; HashTimeScale = 1d / SampleRate * FrameStep; this.frequencyBands = FFTUtil.CalculateFrequencyBoundariesLog(MinFrequency, MaxFrequency, FrequencyBands); }
public DefaultProfile() { Name = "Haitsma&Kalker default"; FrameSize = 2048; FrameStep = 64; SampleRate = 5512; MinFrequency = 300; MaxFrequency = 2000; FrequencyBands = 33; FlipWeakestBits = 3; HashTimeScale = 1d / SampleRate * FrameStep; this.frequencyBands = FFTUtil.CalculateFrequencyBoundariesLog(MinFrequency, MaxFrequency, FrequencyBands); }
private int[] MakeFrequencyMap() { int[] map = new int[WINDOW_SIZE / 2]; // convert FFT result to compacted frame representation // linear mapping of first bins up to 370Hz for (int i = 0; i < 17; i++) { map[i] = i; } // logarithmic mapping of 370Hz - 12.5kHz // NOTE same code pattern as in FingerprintGenerator double[] frequencyMidLogBands = FFTUtil.CalculateFrequencyBoundariesLog(370, 12500, 66); double bandWidth = SAMPLERATE / 2d / fftFreqBins.Length; for (int x = 0; x < frequencyMidLogBands.Length - 1; x++) { currentFrame[17 + x] = 0; int lowerIndex = (int)(frequencyMidLogBands[x] / bandWidth); int upperIndex = (int)(frequencyMidLogBands[x + 1] / bandWidth); for (int y = lowerIndex; y < upperIndex; y++) { map[y] = 17 + x; } } // summation of bins above 12.5kHz currentFrame[83] = 0; for (int i = 580; i < fftFreqBins.Length; i++) { map[i] = 83; } return(map); }
private void Generate(FFTLibrary fftLib) { // FFT resources: // http://www.mathworks.de/support/tech-notes/1700/1702.html // http://stackoverflow.com/questions/6627288/audio-spectrum-analysis-using-fft-algorithm-in-java // http://stackoverflow.com/questions/1270018/explain-the-fft-to-me // http://stackoverflow.com/questions/6666807/how-to-scale-fft-output-of-wave-file /* * FFT max value test: * 16Hz, 1024 samplerate, 512 samples, rectangle window * -> input min/max: -1/1 * -> FFT max: 256 * -> FFT result max: ~1 * -> FFT dB result max: ~1 * * source: "Windowing Functions Improve FFT Results, Part I" * => kann zum Normalisieren für Fensterfunktionen verwendet werden */ float frequency = float.Parse(frequencyTextBox.Text); int ws = (int)windowSize.Value; float frequencyFactor = ws / frequency; int sampleRate = int.Parse(sampleRateTextBox.Text); SineGeneratorStream sine = new SineGeneratorStream(sampleRate, frequency, new TimeSpan(0, 0, 1)); float[] input = new float[ws]; sine.Read(input, 0, ws); //// add second frequency //SineGeneratorStream sine2 = new SineGeneratorStream(44100, 700, new TimeSpan(0, 0, 1)); //float[] input2 = new float[ws]; //sine2.Read(input2, 0, ws); //for (int x = 0; x < input.Length; x++) { // input[x] += input2[x]; // input[x] /= 2; //} //// add dc offset //for (int x = 0; x < input.Length; x++) { // input[x] += 0.5f; //} inputGraph.Values = input; WindowFunction wf = WindowUtil.GetFunction((WindowType)windowTypes.SelectedValue, ws); float[] window = (float[])input.Clone(); wf.Apply(window); input2Graph.Values = window; float[] fftIO = (float[])window.Clone(); if (fftLib == FFTLibrary.ExocortexDSP) { // This function call indirection is needed to allow this method execute even when the // Exocortex FFT assembly is missing. ApplyExocortexDSP(fftIO); } else if (fftLib == FFTLibrary.FFTW) { FFTW.FFTW fftw = new FFTW.FFTW(fftIO.Length); fftw.Execute(fftIO); } else if (fftLib == FFTLibrary.PFFFT) { PFFFT.PFFFT pffft = new PFFFT.PFFFT(fftIO.Length, PFFFT.Transform.Real); pffft.Forward(fftIO, fftIO); } //// convert real input to complex input with im part set to zero //float[] fftIO = new float[ws * 2]; //int i = 0; //for (int j = 0; j < window.Length; j++) { // fftIO[i] = window[j]; // i += 2; //} //Fourier.FFT(fftIO, fftIO.Length / 2, FourierDirection.Forward); fftOutputGraph.Values = fftIO; float[] fftResult = new float[ws / 2]; //FFTUtil.Results(fftIO, fftResult); // transform complex output to magnitudes float sum = 0; int y = 0; for (int x = 0; x < fftIO.Length; x += 2) // / 2 { fftResult[y] = FFTUtil.CalculateMagnitude(fftIO[x], fftIO[x + 1]) / ws * 2; sum += fftResult[y++]; } //FFTUtil.Results(fftIO, fftResult); //// adjust values for the sum to become 1 //float sum2 = 0; //for (int x = 0; x < fftResult.Length; x++) { // fftResult[x] /= sum; // sum2 += fftResult[x]; //} //Debug.WriteLine("sum / sum2: {0} / {1}", sum, sum2); fftNormalizedOutputGraph.Values = fftResult; // convert magnitudes to decibel float[] fftResultdB = new float[fftResult.Length]; //for (int x = 0; x < fftResult.Length; x++) { // fftResultdB[x] = (float)VolumeUtil.LinearToDecibel(fftResult[x]); //} FFTUtil.Results(fftIO, fftResultdB); fftdBOutputGraph.Values = fftResultdB; summary.Text = String.Format( "input min/max: {0}/{1} -> window min/max: {2}/{3} -> fft min/max: {4}/{5} -> result min/max/bins/sum: {6}/{7}/{8}/{9} -> dB min/max: {10:0.000000}/{11:0.000000}", input.Min(), input.Max(), window.Min(), window.Max(), fftIO.Min(), fftIO.Max(), fftResult.Min(), fftResult.Max(), fftResult.Length, sum, fftResultdB.Min(), fftResultdB.Max()); }