liamappelbe / fftea

A simple and efficient FFT implementation for Dart
Apache License 2.0
63 stars 1 forks source link

How can I use this plugin to get volume and frequency? #49

Open tang158152 opened 2 months ago

tang158152 commented 2 months ago

How can I use this plugin to get volume and frequency? Thank You

liamappelbe commented 2 months ago

Can you be more specific? What's your use case?

What do you mean by volume? If you want the overall volume of some audio, you don't really need FFT for that. I usually just use the RMS of the signal as the volume:

RMS

What do you mean by frequency? Do you just want the Hz of the loudest frequency? That's simple enough:

final audio = ...;  // Your input audio.
final sampleRateOfAudioInHz = 44100;  // This value depends on your audio source.

final fft = FFT(audio.length);
final mags = fft.realFft(audio).discardConjugates().magnitudes();

int maxIndex = 0;
double maxAmp = 0;
for (int i = 0; i < mags.length; ++i) {
  final amp = mags[i];
  if (amp > maxAmp) {
    maxAmp = amp;
    maxIndex = i;
  }
}

double maxFreqInHz = fft.frequency(maxIndex, sampleRateOfAudioInHz);
// maxFreqInHz is the loudest frequency, and maxAmp is its amplitude (volume).
tang158152 commented 2 months ago

Thank you very much for your answer, in addition, I would like to ask what is the maximum volume returned by the maxAmp variable, we want to capture a sound through the microphone, get the real-time volume of the sound, but it will convert the volume value to between 0-100, I don't know what the maximum value of the return volume will be

liamappelbe commented 2 months ago

Just to clarify, maxAmp is the volume of just the loudest frequency. It doesn't take into account the other frequencies. So for example, white noise's volume will be underestimated by that approach. That's why usually I use RMS as volume.

Anyway, there isn't a specific maximum value it could have. For starters it depends on the range of your input sound. Is your input audio is already normalized to the range [-1, 1]? Or is it, say, 16 bit audio samples in the range [-32768, 32767]? If it's normalized then I think maxAmp would usually be below 1, but it's possible for it to go above 1 in some circumstances. Moreover, in my experience, the value will usually be way below that, so linearly mapping [0, 1] to [0, 100] probably isn't what you want.

First, you should consider switching it to a logarithmic scale, since this is how humans perceive volume (that's why we use the decibel scale). Depending on your use case, that may or may not be better.

Second, instead of trying to figure out the min/max value theoretically, just record some silence and some loud noises, and see what values you get out of whatever processing you do. Map the silence value to 0, and the loud value to 100, and clamp anything outside that range.