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); }
/// <summary> /// Calculates a normalization offset for the current window function. Every window function leads to /// a different FFT result peak value, and since the peak value of each windowed FFT means 0dB, this /// offset can be used to adjust the calculated dB values. /// </summary> private void CalculateWindowFunctionNormalizationOffset() { if (windowFunction == null) { windowFunctionNormalizationDecibelOffset = 0; } else { SineGeneratorStream sine = new SineGeneratorStream(1024, 16, new TimeSpan(0, 0, 1)); float[] input = new float[WindowSize]; float[] output = new float[input.Length / 2]; WindowFunction wf = WindowUtil.GetFunction(windowFunction.Type, input.Length); sine.Read(input, 0, input.Length); wf.Apply(input); fft.Forward(input); int maxIndex = FFTUtil.Results(input, output); float maxValue = output[maxIndex]; windowFunctionNormalizationDecibelOffset = 1f - maxValue; } }
private static void FrequencyDistributionBlockProcess(float[] buffer, double[] target, IFFT 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]; } }