Different-Range FFT Algorithm

Paul, Could you read my longer post above (12/26) and let me know if I'm on track?

I'm thinking of packaging an audio library object that wraps the fft1024, and exposes a reliable fundamental pitch, though I want to confirm that I'm on the right track in my underlying assumptions.
 
I believe you should try Duff's code first. Either grab his stand-alone library, or get the latest Audio library from Github.

Duff wrote a great example. Once you've installed the latest audio lib, open it from File > Examples > Audio > Analysis > GuitarTuneNotes. (edit, it's been renamed to NoteFrequency since this post was written) It plays and analyzes one of several recorded samples. First, get that running on your Teensy. Connect the DAC output pin to amplified computer speaker or a stereo with standard line-level input.

Just to be absolutely clear about "on the right track", my opinion is you should focus your effort on getting Duff's example running on your hardware ASAP. That may turn out to be a dead end for you, but I believe it's likely to be fruitful. Even if it's not perfect, I believe working to get something imperfect really running on hardware will do you far more good that more hours on theoretical analysis.

Once you have Duff's example working, perhaps a next step would be adding your own sound samples. You can use the wav2sketch program to convert short sound clips. Or you could connect a SD card and modify the program to play from SD instead of internal memory.

If you do any of this, I hope you'll report back here about how effective Duff's code using the YIN algorithm is when used with other instruments. Maybe you could even share some other test sounds, like the trumpet, trombone and tuba you mentioned? I'd love to add more realistic test samples for other types of instruments to that example sketch, if the sound samples can be freely shared.
 
Last edited:
Duff wrote a great example. Once you've installed the latest audio lib, open it from File > Examples > Audio > Analysis > GuitarTuneNotes. It plays and analyzes one of several recorded samples. First, get that running on your Teensy. Connect the DAC output pin to amplified computer speaker or a stereo with standard line-level input.
Just a note: the full samples where to large to fit in ram so I cut them off abrutly so maybe I should look into making them have a more graceful transistion at the end, you might notice some wierd results toward the end of the sample.

here is some pics of my tuner, It has SPI - PGA for dynamic gain control, a OLED and I plan to add a LIPO charger circuitry in the next revision, also designing of encloser in SolidWorks and use a 3d printer at our local hacker space in Little Rock.

IMG_0542.jpg
IMG_0543.jpg
IMG_0544.jpg
IMG_0545.jpg
 
OK, I've modified my test app, replacing my FFT pitch detector with the Collin Duffy's AudioTuner.

Code is at https://github.com/Davidelvig/AudioTunerTest
(first foray into Github)

Physical setup is as in these pics
AudioTunerTop.jpgAudioTunerSide.jpg

Audio Lib GUI as in this pic
Screen Shot 2015-12-29 at 3.53.16 PM.jpg

Pitch recognition works very well:
- in the tested range of about 40 Hz - 4000 Hz
- at a time cost of about 70ms per pitch detection cycle.

Sine waves are best.
Singing voice into the mic (mine) is pretty good as well.
Buzzed trumpet mouthpiece into the mic is not quite as accurate, but still pretty good.

The fundamental pitch is recognized if it is material, and if the next harmonic is not too big.
The fundamental need not be the biggest peak.

The test app will let you play with relative ratios of harmonics.

It works well, though perhaps too slow for my real-time use.

I may move on to test with other waveforms.

So, am I thinking correctly that:
- this works well for pitch recognition in the 20-4000 Hz range
- it will cost 70ms per pitch detection
?
 
Whats the lowest fundamental freq. you need? You can change the number blocks to process to speed it up at the cost of not being able detect lower frequencies. In the .h file at the top you will see where I define the number blocks the default I set was 24 so you can play around with that. Also the initialize function can be lowered to make for a deeper search for the fundamental try .1 or .05. This will add extra latency but not to much. One thing I did is cut some corners in the search algorithm to lower the CPU usage cause I wanted to be able to run a FFT, Peak, and bunch of filters but that requires some advanced programming to get it right so I'm not inclined to change that but its possibility in the future.

So to recap some theory, this algorithm needs to capture at least two cycles of the signal for it to do its work. The 70ms comes from having to find B0(flat) (30.87Hz) note on a bass. So to estimate how many blocks you need remember one block is approximately 2.9ms of the signal and freq is 1/time so you work out how many blocks with that info keeping in mind the nyquist rate thingy:) Well thats for a perfect world you might need more cycles if your signal is noisy or has lots of harmonics. I see your using a mic, is it quality mic? Some mics can shape the signal also in not such good ways, if you have an oscope check out you signal to make sure its clean. Also look at using some low pass filters.

I would say 4000Hz is not going to work so well, the range I designed this for is standard tuning notes of guitar and bass, 30.87Hz to 329.6Hz but it should be good up to 1000Hz with they way it written now because down sampling i did. I'm sure there are many improvemnts that could be made I just couldn't spend more time on it once I got it working good. I'm alway open to suggestions though.
 
Perhaps the analysis time could be made configurable? Maybe only in the begin() function would be enough? The AUDIO_GUITARTUNER_BLOCKS define could establish an upper limit, but maybe begin() could optionally allow less of the memory to be actually used for people who need faster response and don't need to detect all the way down to 31 Hz?
 
Lowest trumpet freq: 160 or so.
Trombone: 80 Hz
Tuba: 40 Hz

I cut the AUDIO_BLOCKS to 12 from 24 in AudioTuner.h
Now I can reliably detect 80Hz every 50 ms.
That's probably low and fast enough!
Good stuff.

I have always seen good recognition up though 4096Hz.
Mysteries, eh?

Perhaps you could consider an optional constructor, that would accept a number of AUDIO_BLOCKS.
Perhaps it's really a method call, such as setAudioBlocks(int blocks) or setFrequencyRange(LOW | MEDIUM | HIGH)

I can see that it would need to change the three lines where the #define is used to allocate memory on instantiation.
I can use this as is, with my local modification - I'll need to learn the impact of local modifications when updates come.

I'll also keep up with my FFT alternative.
It appears to have the advantage in speed (11ms cycle time), at the cost of not-so-low frequency (160Hz min).
I may try decimation to reduce my bin size - perhaps getting low enough.
I may also be able to play with my bin assessment to get a good-enough pitch at lower freqs.

Thanks to you and Paul for getting the YIN thing going!

Very cool!
 
Perhaps the analysis time could be made configurable? Maybe only in the begin() function would be enough? The AUDIO_GUITARTUNER_BLOCKS define could establish an upper limit, but maybe begin() could optionally allow less of the memory to be actually used for people who need faster response and don't need to detect all the way down to 31 Hz?
I see why for realtime stuff so I'll look into that when I start that 1Wamp project since I will want that also, there are some other optimizations I'm looking into also to lower the CPU usage since its pretty high now.

Lowest trumpet freq: 160 or so.
Trombone: 80 Hz
Tuba: 40 Hz

I cut the AUDIO_BLOCKS to 12 from 24 in AudioTuner.h
Now I can reliably detect 80Hz every 50 ms.
That's probably low and fast enough!
Good stuff.

I have always seen good recognition up though 4096Hz.
Mysteries, eh?

Perhaps you could consider an optional constructor, that would accept a number of AUDIO_BLOCKS.
Perhaps it's really a method call, such as setAudioBlocks(int blocks) or setFrequencyRange(LOW | MEDIUM | HIGH)

I can see that it would need to change the three lines where the #define is used to allocate memory on instantiation.
I can use this as is, with my local modification - I'll need to learn the impact of local modifications when updates come.
i'll take this into account thanks.
 
I've been wondering if we should rename this to something less guitar specific? Any ideas?

Once Teensyduino 1.27 is fully released (within the next few days), with this in the audio lib, changing the name will probably not be practical. Now's the last chance to reconsider what the name ought to be long-term.....
 
Similar seeming apps offers this thesaurus medley - and feature creep roadmap - and they are String limited it seems::
Tuna Pitch - tune guitar, bass, banjo, cello, or other musical instrument
Description :: https://itunes.apple.com/us/app/tuna-pitch-tune-guitar-bass/id313492710?mt=8
Stay in tune with this chromatic tuner and pitch pipe for your musical instrument. It tunes not only with guitars, bass guitars, and banjos, but also many other instruments and even with your voice (just sing into it!). The built-in pitch pipe lets you play a reference tone for tuning by ear.

The tuner requires microphone access, which can be granted in the Settings app, in Privacy > Microphone. For best results, use a headset or microphone separate from the device.

PerfectTune - the Ultimate String Tuner :: Description

PerfectTune is the ultimate tuner for stringed instruments. Not only does it feature a lightning fast pitch detection system, that is unparalleled by any other tuner on the AppStore, it also comes with an innovative multi-string layout that lets you tune your instrument quickly to a great variety of tunings.

PerfectTune features optimized algorithms for Guitar, Bass, Banjo, Violin, Cello, Ukelele and other stringed instruments, and for each these you can choose from a range of relevant tunings. There's dropped and open tunings for guitar, period tunings for lute, support for 5 and 6-string bass guitars and various types of banjo.
 
I've been wondering if we should rename this to something less guitar specific? Any ideas?

Once Teensyduino 1.27 is fully released (within the next few days), with this in the audio lib, changing the name will probably not be practical. Now's the last chance to reconsider what the name ought to be long-term.....
How about frequencyDetect or fundamentalDetect or just Yin?

I'm thinking the AudioLibrary version needs to be of broader scope anyway. I hoping some of DSP gurus can look at this and speed it up also. I know one library uses some cool FFT tricks to speed it up but its beyond me right now. But by all means hack away at it, i'll just keep my github version for specifically guitar tuning for now. Really right now the Snooze library is getting some t.l.c from me so but i'll get back to this soon.
 
Last edited:
I've been wondering if we should rename this to something less guitar specific? Any ideas?

Once Teensyduino 1.27 is fully released (within the next few days), with this in the audio lib, changing the name will probably not be practical. Now's the last chance to reconsider what the name ought to be long-term.....
I suggest Frequency detector or tone detector...
 
Similar seeming apps offers this thesaurus medley - and feature creep roadmap - and they are String limited it seems::
The changes paul and david proposed would make it more functional for sure like these apps. But I'm not sure it has to be geared just for tuning?

I suggest Frequency detector or tone detector...
To keep in spirt with the current naming scheme it should have "analyze_" in front of the file name. There is already analyze_tonedetect.h and cpp so the class name should probably follow the same too - "AudioAnalyze"xxxx also?
 
Last edited:
Is it a safe assumption (for naming purposes) to assume this is mostly intended for detecting the frequency of musical notes?
 
Is it a safe assumption (for naming purposes) to assume this is mostly intended for detecting the frequency of musical notes?
Yes

I just meant by "broader scope" is that it's not just used for tuning guitars. I know one person that uses it for converting what notes he plays to midi.
 
How would you feel about naming it AudioAnalyzeNoteFrequency?

The object class would be AudioAnalyzeNoteFrequency, the file name would be analyze_notefreq.cpp, and the short default name in the design tool would be either "notefrequency" or just "notefreq".

Really, I'm open to suggestions here. I'm also note terribly worried about leaving it named AudioAnalyzeGuitarTuner. But after 1.27 releases, the name really needs to stay fixed.
 
I'm sold, AudioAnalyzeNoteFrequency works and go a head pick between the other two, I'm not sure if you want short or long name forms but both are clear to what they do to me.
 
not sure if you want short or long name forms but both are clear to what they do to me.

Every object has a default short name in the design tool. When you drag the object onto the canvas, it starts with that name plus an incrementing number appended.
 
How about AudioAnalyzeYIN.... or just YIN.
That said, there is a "market" for a lower and higher pitch version of this - differing only in their number of AUDIO_BLOCKS, and being slower-lower and faster-higher.
In the spirit of FFT256 and FFT1024, how about
  • AudioAnalyzeYINLow YINLow
  • AudioAnalyzeYINHigh YINHigh

The "YIN" part is what got me.

With time, a "adjustable" YIN would flex for speed and pitch range.
 
Not as well-know as FFT, but I've found YIN mentioned more than once in web searches related to pitch detection.
There's one source paper that I'm aware of, but I been guided to it from 2-3 tracks.
It's autocorrelation plus corrections...
Anyone else heard of Yin before this thread?
 
Then I would rather have AudioAnalyzeAutocorrelation instead of Yin. Autocorrelation is a known term in many fields. But I think your suggestion Paul is very good and describing in this case. Go for it!
 
One last thought before you choose an object name, Paul.
Because of my need for speed (rapid cycles) I've polished up my FFT frequency finder.
Now it's in sketch code. I may try to make a pluggable audio library object out of it later.
It will likely be a skosh less precise in frequency matching, and not have good freq finding below 100 Hz, though it is much quicker.
As an audio library object, it would be another flavor of tuner, freq finder, note finder.
(In the event that influences your naming)
I know these object names need to stick, once published.

Thanks, all, for the great discussion!
 
Oh my gosh! This is incredibly helpful; and I've never seen a forum response this quick or in-depth! This is quite the community.
I have my college applications due tomorrow, so I won't be able to answer a bunch of the questions that my original lack of detail warranted. I'll get back on here as soon as I'm not sweating a 24-hour deadline. Again, thanks so much, guys!
 
The key point is you absolutely must digitally filter the signal before you discard 21 of every 22 samples. The digital filtering is what causes every 22nd sample to properly represent your signal. If you just take every 22nd sample without filter filtering, you'll get absolutely horrible results (assuming your signal is common audio or other content with higher frequencies present).

If I have a single-order analog low-pass filter (at around 1 kHz) on the signal before I pass it to the Teensy, would that obviate using a digital filter, or would you recommend it anyway?
 
Back
Top