FftSharp
FftSharp copied to clipboard
demo request
The FFT spectrum in the demo example doesn't resemble a realistic frequency spectrum. Is it possible to visualize audio similar to the FL Studio Parametric EQ, considering a logarithmic x-scale and the equal-loudness contour? https://en.m.wikipedia.org/wiki/Equal-loudness_contour
Hi @ahmadsafi24, thank you for this question! It may be sufficient to document how to convert FFT output to equal loudness curve, and not require code change to the FFTsharp library to achieve this goal.
I am currently travelling and am writing from a smartphone so I haven't tested this, but what do you think about the strategy recommended by ChatGPT?
I have a C# function that returns the FFT power spectrum of an audio waveform. How do I convert these values to create an equal-loudness contour? Write a single function that takes the FFT values and returns the contour.
To convert FFT power spectrum values into an equal-loudness contour, you need to apply the equal-loudness weighting based on ISO 226:2003 or another reference that models the frequency-dependent sensitivity of human hearing. This process involves:
- Mapping the FFT frequencies to equal-loudness levels.
- Adjusting the FFT power values by the corresponding loudness weights.
Here's a C# function to apply equal-loudness weighting:
using System;
using System.Linq;
public static class AudioProcessing
{
public static double[] ApplyEqualLoudnessContour(double[] fftValues, double sampleRate, int fftSize)
{
// Step 1: Calculate the frequencies corresponding to each FFT bin
double[] frequencies = Enumerable.Range(0, fftValues.Length)
.Select(i => i * sampleRate / fftSize)
.ToArray();
// Step 2: Get equal-loudness weights using an approximate ISO 226 model
double[] weights = frequencies.Select(f => EqualLoudnessWeight(f)).ToArray();
// Step 3: Apply weights to FFT values
double[] adjustedValues = fftValues.Zip(weights, (fft, weight) => fft * weight).ToArray();
return adjustedValues;
}
private static double EqualLoudnessWeight(double frequency)
{
if (frequency <= 0)
return 0;
// Approximate implementation of ISO 226 equal-loudness contours (A-weighting-like)
// Use constants and equations specific to the model
double f2 = frequency * frequency;
double f4 = f2 * f2;
// Empirical formula for A-weighting
double r = Math.Pow(12200 * 12200 * f4, 2);
double numerator = r;
double denominator = ((f2 + 20.6 * 20.6) * Math.Sqrt((f2 + 107.7 * 107.7) * (f2 + 737.9 * 737.9)) * (f2 + 12200 * 12200));
double aw = numerator / denominator;
// Scale to human-perceptible range
return Math.Pow(10, aw / 20);
}
}
Explanation:
- Frequency Calculation: The function calculates the frequency corresponding to each FFT bin using the formula:
Fi = i * sampleRate / fftSize
-
Equal-Loudness Weighting: The
EqualLoudnessWeightfunction computes a weight for each frequency based on a simplified approximation of the ISO 226 equal-loudness curve. -
Apply Weights: The FFT power values are multiplied by the weights to create the equal-loudness contour.
Usage:
double[] fftValues = ...; // Your FFT power spectrum values
double sampleRate = 44100; // For example, 44.1 kHz
int fftSize = 1024; // FFT size
double[] equalLoudnessContour = AudioProcessing.ApplyEqualLoudnessContour(fftValues, sampleRate, fftSize);
Notes:
- This implementation uses a simplified equal-loudness weighting approximation. For a more precise model, consider using detailed equal-loudness curves or lookup tables based on ISO 226 data.
- Ensure the FFT values are appropriately scaled (e.g., normalized) before applying the weights.