Having captured audio over a microphone, and converted to a voltage suitable for the Arduino ADC, the next challenge is capturing the analogue data and converting it into an estimation of the frequency of the current note being heard. That's a fairly tricky problem, as it turns out.

Firstly, the default Arduino analogRead() function is way too slow. At 100 microseconds per read, that's a maximum sample rate of 10kHz - and even that is only possible when tight-looping doing reads, and nothing else. According to Nyquist's theorem, at a bare minimum I need to be able to sample at at least twice the highest note's fundamental frequency, which is probably going to be about 1kHz, so double up to 2kHz. I'd ideally like to sample at least 5-6 times the highest fundamental, and calculating the incoming frequency requires some maths too. So, I decided to look into alternative approaches.

A naive approach to frequency counting is to count zero-crossings in a given direction - i.e. observe the waveform, and everytime it goes from negative to positive, increment a counter. Counting the number of crossings in a given time directly gives you the frequency. It turns out that both the ATTiny85 and the ATmega328 (Arduino) chips both contain an analogue comparator, hooked up in such a way that zero crossing counting can be done extremely efficiently.
Continue reading "Instrument Tuner - Zero Crossing analysis"