On Tuesday, 8 July 2025 at 18:11:27 UTC, Matthew wrote:
>Hi,
I'm writing a program where I'm trying to decode DTMF tones. I already completed the wave file decoder and I know I'm supposed to use an FFT to transform the samples from time domain to frequency domain but I'm stuck on determining which of the DTMF frequencies are present.
Consider the following, the input is the sound wave samples as an array of floats between -1 and +1.
void decode_sound(float[] samples)
{
import std.numeric;
import std.math;
import std.complex;
import std.algorithm;
size_t fft_size = 4096;
auto f = new Fft(fft_size);
foreach(ch; samples.chunks(fft_size))
{
auto res = f.fft(ch);
// res is an array of 4096 complex numbers
}
}
I can't figure out how the 4096 results of the FFT relate to the frequencies in the input.
I tried taking the magnitude of each element, I tried taking just the real or imaginary parts. I plotted them but the graph doesn't look how I'm expecting.
What do the 4096 resulting complex numbers represent?
How should I use the result to check whether the 1209Hz, 1336Hz, 1477Hz, or 1633Hz tones are present in that part of the sound?
Thanks,
Matthew
The output is an array of "bins", each bin holds a complex number, the magnitide of the complex number is the magnitude of that bin, and the phase of the complex number is the phase of that bin. The frequency the bin represents is..
(samplerate/2) * idx/res.length
where idx is the bin index. IE the first bin = 0hz, and the last bin is samplerate/2. And they are linearly spaced across that range.
This is for a "real fft", rather than a "complex fft", looks like that's what your doing tbh. A complex FFT you get negative frequencies too i think, but i never real got my head around that.
Note that FFTs aren't perfect, unless the frequencies line up exactly on the bin frequencies you get leakage into neighbouring bins. A single sine wave between two bins will show up as peak at those two bins and leakage tailing off to some of the bins above and below it. You can adjust the distribute of this leakage by applying a window function to the sample before you FFT it, but it may or may not matter in your case, if the tones your looking for are not too close to each other.
You might need to average a few bins around the frequency of interest for best results.
I'd probably just make a few test samples with each single sine wave, and see what the FFT bins look like, and adjust my detection algo based on that. Tweaking FFT length and window function will give you enough separation between the tones your interested in.