cph-cachet / flutter-plugins

A collection of Flutter plugins developed by CACHET
541 stars 650 forks source link

[noise_meter] What? The computations don't make sense. #559

Open mcourteaux opened 2 years ago

mcourteaux commented 2 years ago

This noise_meter plugin does truly weird things. https://github.com/cph-cachet/flutter-plugins/blob/0a3b5e450755692cb900d70e06630caddf6c4ee9/packages/noise_meter/lib/noise_meter.dart#L13-L27

First it sorts an array (why?) then proceeds to use the largest and the smallest samples (which would probably be close to the same, just with opposite signs), and then takes the mean, which should be close to zero. Then zero is multiplied by a giant number, to then apply the formula of decibel scale on the wrong input. None of this makes sense. Depending on the randomness of the signal, half of the samples produced for "meanDecibel" will be NaN, due to negative mean value.

Looking at the formula for dB scale for audio, you need the RMS energy of the signal: image

dB = 20 * log10(sqrt(mean(square(audio_frames))))
   = 10 * log10(mean(square(audio_frames)))

Taking a minimum and a maximum single frame is insensible, and takes O(n*log(n)) time for no reason. If you would be interested in a "mean" volume and a "maximum" volume, then you should time-bin the audio samples and apply the RMS formula on those bins. You just cannot apply the decibel formula on a single sample.

hoffmatteo commented 1 year ago

Hi @mcourteaux , since I am not very familiar with this topic I tried to apply your feedback and the wikipedia information to noise_meter, but I would greatly appreciate your comments on this. When I was testing the dB numbers end up making a lot more sense than what was calculated previously.

double RMS = 0.0;

for (var volume in volumes) {
  RMS += pow(volume, 2);
}

RMS = sqrt(RMS / volumes.length);

var dB = log(RMS / 0.00002).abs() / log10e;

The 0.00002 in this case is for the reference sound pressure mentioned in the article you sent.

mcourteaux commented 1 year ago

There are several issues:

RMS = 0.0;
for (sample in audio_waveform) {
  RMS += sample * sample;
}
RMS = sqrt(RMS / audio_waveform.length);

var dB = log(RMS / 20e-6) / log(10);