Frequencies not adding up


#1

Hi. I’m trying to make sure that I know where certain audio frequencies are located when I load an audio clip.

The musical note A4 is 440Hz. If the frequencies of a clip with a sample rate of 44100Hz are split into 1024 bands, the 10th band should be closest to 440Hz (according to calculations given here). 10 * 44100/1024 = 430Hz

So I set up a typical frequency display, feeding in a 440Hz sine wave, but when I mark out the 10th band with a green line, I see that it’s not at the 440Hz frequency (loudest frequency). If I mark out the 20th band with a red line, I see that this is at the 440Hz line instead. Again, if I do the calculations for band to frequency, the 20th band is closest to 880Hz, which is A5, one octave up. So why am I getting this wrong?

I’ll show my code below:

import processing.sound.*;
SoundFile file;
FFT fft;
int bands = 1024;
float[] spectrum = new float[bands];

void setup() {
  size(1024, 512);
  file = new SoundFile(this, "sin440.wav");
  file.play();

  fft = new FFT(this, bands);
  fft.input(file);
}

void draw() {
  fft.analyze(spectrum);
  for (int i = 0; i < bands; i++) {

    stroke(0, 0, 0);
    if (i == 2) {
      stroke(0, 0, 255);
    }
    if (i == 5) {
      stroke(0, 255, 255);
    }
    if (i == 10) {
      stroke(0, 255, 0);
    }
    if (i == 20) {
      stroke(255, 0, 0);
    } 
    line( i, height, i, height - spectrum[i]*height*5 );
  }
}

The 440Hz sine wave can be generated and downloaded here.

My guess is I’m making a very stupid mistake, but I’ve been trying to figure this out for an embarrassing amount of time, so I hand it over to you now.


#2

ha, good find

just for reading 2 links of prior discussions
FFT frequencies ,
Not sure how to work with Minim's FFT feature ,
the link to the reference
where obviously most of your code come from
https://processing.org/reference/libraries/sound/FFT.html

and a very interesting line in the processing code
https://github.com/processing/processing-sound/blob/master/src/processing/sound/FFT.java#L39 ,

in words:
in the processing sound lib the bands are really bands,
and not samples == bands * 2
while in minim lib not.
that are the 2 codes i play with:
sound lib:

// https://discourse.processing.org/t/frequencies-not-adding-up/9170

import processing.sound.*;
SoundFile file;
FFT fft;
int bands = 1024;
float[] spectrum = new float[bands];

void setup() {
  size(1024, 512);
//  file = new SoundFile(this, "sin440.wav");
  file = new SoundFile(this, "the_a.mp3");
  file.play();

  fft = new FFT(this, bands);
  fft.input(file);
}

void draw() {
  fft.analyze(spectrum);
  for (int i = 0; i < bands; i++) {
    stroke(0, 0, 0);
/*
    if (i == 2) {
      stroke(0, 0, 255);
    }
    if (i == 5) {
      stroke(0, 255, 255);
    }
    if (i == 10) {
      stroke(0, 255, 0);
    }
    if (i == 20) {
      stroke(255, 0, 0);
    } 
*/
    line( i, height, i, height - spectrum[i]*height*5 );
    if ( keyPressed) if ( i < 30 ) println("i "+i+" amp "+nf(spectrum[i],1,1));
  }
}

minim lib

import ddf.minim.*;
import ddf.minim.analysis.*;

String soundfile = "the_a.mp3"; // "sin440.wav"

Minim minim;
AudioPlayer sound;
FFT spectrum;

float zoom =0.5;

void setup() {
  size(600, 600);
  noStroke();
  fill(255);
  minim = new Minim(this);
  sound = minim.loadFile(soundfile, 1024);
  sound.loop();
  spectrum = new FFT(sound.bufferSize(), sound.sampleRate());
  println("bufferSize() "+sound.bufferSize());
  println("sampleRate() "+sound.sampleRate());
  println("fft.specSize()"+spectrum.specSize());
}

void draw() {
  background(0);
  spectrum.forward(sound.mix);
  for (int i = 0; i < spectrum.specSize(); i++) {
    float x = map(i, 0, spectrum.specSize(), 0, width);
    rect(x, height-10, width/spectrum.specSize(), -spectrum.getBand(i)*zoom);
    if ( keyPressed) if ( i < 30) println("i "+i+" amp "+nf(spectrum.getBand(i), 1, 1));
  }
}

sound lib max amp at i 20 ( at bands = 1024 it uses 2048 samples )
minim lib max amp at i 10 ( use 1024 samples and give 513 values ( 512 bands ))

also i assume that both use DFT math,
while here
FFT of 1D array of 1024 measurements ,
i play with a complex algorithm i copy
and that does have 2 values per band.
( that was my first idea when i read your question )

i tested with my 440Hz mp3 file but
also i used your online link and did a crosscheck


#3

Ok, so as a solution for calculating frequencies, multiplying the bands by 2 works. However, I don’t understand why processing does it this way and also I don’t think it’s mentioned in the documentation.

Also, when you print all the amplitudes for bands below 30, what are you trying to show? Sorry for not getting it. Appreciate the help.


#4

yes, while the wording regarding BANDS is correct, it is not that clear
as long you not mention the samples used.

actually it might be a much better way for beginner who possibly are
not interested into samples…
just want a spectrum, anyhow a deeper understanding of FFT can not get
from a one sentence of a code example.

again pls understand that processing does not do FFT, it just sends the
sample array to the JAVA analyze function and gets back the spectrum
for what it needs you to declare how long that array should be.

now that relation:
samples FFT spectrum ( bands )
i was hoping is more clear after you read the other posts,
it has nothing to do with processing, code… it comes from the

Sampling Theorem

and is valid for all types of signal analysis.


as from any line graphic i can not count lines

  • i like the printed list ( i am more the excel type ),
    • just limited to (30) and
    • only printed at keyPressed
      ( because a conti print in draw slows down the frameRate and would not be readable anyhow )

now for the math of digital audio:
the used signal has 440Hz, so one sinus fits into 2.27 msec
for a sampling rate of the audio signal of https://en.wikipedia.org/wiki/44,100_Hz
what does a sample every 22.67 usec.
so takes 100.22 samples of that ONE 440Hz sinus.

if we use / analyze 1024 samples it contains 10.21 of that 440Hz sinus(es).
( and covers 23.2 msec == max 43 batches per sec. ) )