Help with Autocorrelation in Frequency detection

I need to constantly determine the frequency a musical instrument is playing for as long as it is being played. Not the pitch of the note, just the frequency.

This thread:

https://forum.arduino.cc/index.php?topic=195085.0

talks about autocorrelation, which looks like just what I need.

However, I do not know how to modify the code so it will use an analog input? The second response asks the same question.

The OpenMusicLabs FFT demonstrations program shows a way to fetch data from an analog input. It uses the ADC in the free-running mode, with the end of each conversion triggering the next. Conversions are initiated in hardware, and are consequently evenly spaced in time, a vast improvement over trying to call analogRead() based on the value of micros(). You can see that code here: Example - Open Music Labs Wiki

The OpenMusicLabs code adjusts the input to a 16-bit value. For your purposes, you may be better served by taking only the upper eight bits of the analog. That will reduce the amount of memory required, and it will reduce the time it takes to perform the calculations.

I'd recommend that you start by developing code to capture the analog input the way that you want it, and then move on to adding and adapting autocorrelation code to your requirements. It's crazy-making to try troubleshoot the calculations when the input doesn't work.

Not the pitch of the note, just the frequency.

What, in your mind, is the difference between these two things?

It is not possible by the way just using an Arduino. An FFT will tell you all the harmonics you are receiving, but it will not tell you the frequency of the note.

What, in your mind, is the difference between these two things?

Pitch is what note is being played on the instrument. Frequency is the measured frequency being played. A tuner will tell you that the pitch of A3 is in tune with 440hz (A4), when the frequency A3 plays at is 220hz (one octave lower than A4).

I have looked at various ways to measure a music instrument's frequency as it is being played, but so far I have not gotten any to work. :frowning: From instructables, to OpenMusicLabs, to Piccolo, to FFT or FFFT or FHT... The ones that do work pick up all the harmonics and give me a wrong reading. I can verify that by running this program:

If I whistle, I get a clean wave and good hz reading. If I play a note on my clarinet, I get a fuzzy wave full of harmonics and a wrong reading (3-4K when it should be under 1K)..

I really need to get the Autocorrelation code working.

For instance, this tutorial:

looks like EXACTLY what I need up until he determines what the pitch of the frequency being played is (and everything after that). This is an amazing little project that samples the frequency being played, determines the pitch of the note, then displays that note in real-time. I have tried to download the project and strip out everything after the frequency detection but I am not that skilled.

Any way to get the code in the original post working for A0 input?

3DPiper:
Pitch is what note is being played on the instrument. Frequency is the measured frequency being played. A tuner will tell you that the pitch of A3 is in tune with 440hz (A4), when the frequency A3 plays at is 220hz (one octave lower than A4).

Not sure where you got that from but it is entirely wrong.
From:- Pitch (music) - Wikipedia

Pitch is an auditory sensation in which a listener assigns musical tones to relative positions on a musical scale based primarily on their perception of the frequency of vibration.[6] Pitch is closely related to frequency, but the two are not equivalent. Frequency is an objective, scientific attribute that can be measured. Pitch is each person's subjective perception of a sound wave, which cannot be directly measured.

What do you want to do and why? This looks like an X-Y Problem

This is an amazing little project that samples the frequency being played, determines the pitch of the note, then displays that note in real-time. I have tried to download the project and strip out everything after the frequency detection but I am not that skilled.

This is something that has been attempted for a very long time with only marginal success even when you can throw more hardware resources at it than the Arduino can bring to the party. I see that the link refers to a clarinet, it will not perform as well on more complex waveform.

Any way to get the code in the original post working for A0 input?

What code are we talking about here? Link to it directly please. But the hardware diagram shows the input is connected to A0?

Not sure where you got that from but it is entirely wrong.

How so? My answer and your wiki link look exactly the same. Pitch is ABCDEFG, frequency is a measurement of the sound based on wavelength..

What do you want to do and why?

I want to play a musical instrument and sample the sound and have an Arduino tell me the sound's fundamental frequency.

Tuners do not do this, as you set a reference frequency like 440Hz for A4. Every note you play to check tuning is based on this frequency, and the tuner tells you the note you are playing and if it is sharp/flat based on the reference frequency.

This is something that has been attempted for a very long time with only marginal success even when you can throw more hardware resources at it than the Arduino can bring to the party.

I am very open to what other hardware I would need to make this happen. I have tuners that cost $7, or phone apps that cost $1, how are they able to accomplish this? One of my tuners is based on an Arduino, so clearly this is possible. The autocorrelation code appears to directly tackle this task.

I see that the link refers to a clarinet, it will not perform as well on more complex waveform. What code are we talking about here? Link to it directly please.

The original code is from this Instructable called (interestingly enough) "Reliable Frequency Detection Using DSP Techniques":

He specifically says it is for detecting the frequency of a instrument being played that has many overtones and harmonics, filtering those to get the fundamental tone. This sounds like exactly what I need.

However, he uses an included pre-sampled sound. I would like to use an op-amped mic/piezo film and constantly loop to show the frequency the whole time the instrument is being played, just like a regular tuner but it will show the frequency and not the pitch.

The instructable link was posted here as well:

https://forum.arduino.cc/index.php?topic=195085.0

and even modified on to become more efficient. The second response to the post asks the same thing I am asking:

in the example as input file is used sample.h raw. How would you read samples from an analog input of Arduino?

The instructable link was posted here as well:

Instructables are written by people with an inflated view of their own ability and knowledge. That page is no exception. Hang around here long enough and you see a steady parade of people who can not get bad projects to work. The problem with that one is that the waveform is already digitized and stored as a file, it is not possible to digitize at that rate and do any processing on a Uno. Forget trying to learn anything new from instructables. Only read them if you can spot errors, like politicians instructables promises more than the ever delver.

My answer and your wiki link look exactly the same.

Then read it again and read what you wrote. For all intents and purposes pitch and frequency are exactly the same thing. You are getting confused by what a tuner does, which is to perform a FFT and measure one of the harmonics and measure its frequency and from that tell you the note over an octave range. It does that because that bit is easy as you don't have to struggle to find the fundamental of a note. The harmonic content and relative amplitude of these harmonics continuously varies over the duration of the note with the harmonic that is the biggest one changing. A tuner doesn't even begin to consider this as after all it is not what you want to know when using a tuner.

I want to play a musical instrument and sample the sound and have an Arduino tell me the sound's fundamental frequency.

Which is the what but not the why.
Normally this is so it can be converted into a stream of MIDI messages for creating other sounds. While they have got better at this over the years a device that does this is still not 100%

I have tuners that cost $7,

Which as we said will not do what you want.

or phone apps that cost $1, how are they able to accomplish this?

There are two ways they accomplish this and both apply:-

  1. They are not very good
  2. They run on a processor that has at least 1G of free memory and a clock speed in excess of 1GHz
    You want to do this on a processor with 2K of memory and a 16MHz clock!

I think I appreciate that you are 'helping', but your nick says more than your answer.

I really do want help on this project and I came here for it and seem to be only belittled, like I am taking crazy pills or something.

Instructables are written by people with an inflated view of their own ability and knowledge. That page is no exception. Hang around here long enough and you see a steady parade of people who can not get bad projects to work. Forget trying to learn anything new from instructables.

Ouch!

Well, the code was modified by people on this board to only be better. Should I ignore that as well?

The problem with that one is that the waveform is already digitized and stored as a file,

Yes, hence the question on my original post.

it is not possible to digitize at that rate and do any processing on a Uno.

?? I see other FFT sketches that interpret 8 or more channels in real-time..

Then read it again and read what you wrote. For all intents and purposes pitch and frequency are exactly the same thing.

Uh, no. Pitch is what we attribute the the frequency a musical instrument's note is playing. Is the pitch of a bamboo flute the same as a barisax? No. Now, the FREQUENCY of notes that happen to match would be the same as it is measureable. But an A on the bamboo flute is not the same as the A on the barisax.

You are getting confused by what a tuner does, which is to perform a FFT and measure one of the harmonics and measure its frequency and from that tell you the note over an octave range.

That is exactly what I said a tuner does! It gives you the Pitch (note) reference to your chosen tuning frequency, NOT the exact frequency of the note you are playing.

It does that because that bit is easy as you don't have to struggle to find the fundamental of a note. The harmonic content and relative amplitude of these harmonics continuously varies over the duration of the note with the harmonic that is the biggest one changing. A tuner doesn't even begin to consider this as after all it is not what you want to know when using a tuner.

Yes, but my point is: somewhere in the magic of the box that is a 'tuner', it is determining what the frequency is being played and comparing it to a reference frequency for tuning. If you choose A440Hz and play A3, it has to measure that it is 220hz, correct? I want to show that frequency, not that it is in tune with A440hz and is pitch A3 (what tuner do now).

Which is the what but not the why.

Who cares why I want to do this?

Normally this is so it can be converted into a stream of MIDI messages for creating other sounds. While they have got better at this over the years a device that does this is still not 100%

I have no interest in this, this project will act as a very specific tuner that shows frequency instead of pitch. If I am on a piano and I play G0, I want it to show 24.5Hz not 'G'. If I play D3, I want it to show 146.83Hz not 'D'. If I play F5, I want it to show 698.46Hz not 'F'. Does that make sense?

"I have tuners that cost $7,"

Which as we said will not do what you want.

Yes, but (again) my point is a $7 piece of electronics is somehow determining the frequency being played to show you the pitch of the note, either through FFT or autocorrelation or something. Certainly this is possible with some flavor of Arduino (or combination of arduinos).

or phone apps that cost $1, how are they able to accomplish this?

There are two ways they accomplish this and both apply:-

  1. They are not very good
  2. They run on a processor that has at least 1G of free memory and a clock speed in excess of 1GHz
    You want to do this on a processor with 2K of memory and a 16MHz clock!

I'm not sure I ever said Uno, although both tutorials use one.
I have a feeling the $7 tuner I have does not use anything near the power of an Uno.

One tuner I have uses a ATMega3216AU, would that work?

I do not want to make a phone app, I want this to be a dedicated device.

Uh, no. Pitch is what we attribute the the frequency a musical instrument's note is playing. Is the pitch of a bamboo flute the same as a barisax? No. Now, the FREQUENCY of notes that happen to match would be the same as it is measureable. But an A on the bamboo flute is not the same as the A on the barisax.

like I am taking crazy pills or something.

You are.
You have a basic fundamental misunderstanding of the term pitch. An A played on any instrument will generate the same frequency for the fundamental, and a mix of changing harmonics. The mix of harmonics and how they change over time will depend on the instrument.

Yes, but (again) my point is a $7 piece of electronics is somehow determining the frequency being played to show you the pitch of the note, either through FFT or autocorrelation or something. Certainly this is possible with some flavor of Arduino (or combination of arduinos).

It is perfectly possible to do what a tuner does on an Arduino, but we have established, have we not, that this is not what you want to do.

I have no interest in this, this project will act as a very specific tuner that shows frequency instead of pitch. If I am on a piano and I play G0, I want it to show 24.5Hz not 'G'. If I play D3, I want it to show 146.83Hz not 'D'. If I play F5, I want it to show 698.46Hz not 'F'. Does that make sense?

Yes that makes sense, and that is what is difficult, if not impossible to do, that is what I have been trying to tell you. It is the same process needed to turn sound into MIDI signals. I know that this has not been done reliability. Do a search for a sound to MIDI converter and you get lots of claims of how reliable they can be, but these do not work in practice as reliable as you would need.

I see other FFT sketches that interpret 8 or more channels in real-time..

Sure you can do this but that is what a tuner is doing and we have established, have we not, that this is not what you want to do.

I feel like we are at an impasse here so I will drop out and let's see if someone else pops up and tells you how to accomplish what you want to do.

I see other FFT sketches that interpret 8 or more channels in real-time..

Were those for an Arduino? If so, I'd like a link please.

Pete

It is perfectly possible to do what a tuner does on an Arduino,

Apparently not, as you say:

Yes that makes sense, and that is what is difficult, if not impossible to do,

Once you have set your reference tuning frequency, a regular electronic tuner will do this (continually sampling the audio, in a loop):

-sample the audio
-determine the frequency
-determine the pitch of the note based on the frequency

It will show you the pitch of the note being played and if it is in 'tune' with the reference tuning frequency you chose.

I only need the first two steps.

I see other FFT sketches that interpret 8 or more channels in real-time.

I thought by "channels" you meant ADC channels, whereas the video is using an FFT size of 8 (or is it 16?).
You aren't going to be able to determine a frequency as precisely as "146.83Hz" with 8 bins.

Pete
(note to the Youtube guy: it's Fast Fourier Transform - not Transfer)

You aren't going to be able to determine a frequency as precisely as "146.83Hz" with 8 bins.

Do you mean for music instrument sampled audio?

Other Arduino frequency measuring samples to two places (up to 8 channels at once!), but it is not music instrument audio:

https://www.pjrc.com/teensy/td_libs_FreqMeasure.html

1/146.83 = 6810uS. I think that can me be measured pretty closely, maybe as 6812uS (multiple of 4uS). (146.8Hz)

FreqMeasure Library, for Measuring Frequencies in the 0.1 to 1000 Hz range, or RPM Tachometer Applications

That is not even close to what you've been asking to do. That is 8 channels of digital signals - not a musical instrument. It is reasonably easy (as is evident from that Youtube video) to measure the frequency of a digital signal with considerable accuracy and precision. But that is not the same as using an FFT to try to determine the frequency of a musical note.

Pete

That is not even close to what you've been asking to do.

Correct, as I said it was not sampling a music instrument.

Maybe this is a job for a Raspberry Pi, they seem much more powerful..?

You asked:

3DPiper:
Any way to get the code in the original post working for A0 input?

Yes. Below is a sketch that fetches analogs from A0, prints them to the serial monitor, waits for input, and does it all again. It's simple and straightforward, and annotated to a reasonable degree. You should be able to adapt it. The analog acquisition routine is blocking code; nothing else will happen while you're getting analogs.

If you decide to use the code from this "instructable" - http://www.instructables.com/id/Reliable-Frequency-Detection-Using-DSP-Techniques - be aware that the reported frequency has a bit of bias. The sketch looks for a peak, a value that's adjacent on either side to smaller values, and then reports the last value it examined. A better estimate would be one less than that - the lag where the highest value was calculated. The "instructable" code reports the the period as the value of the lag just beyond the peak, and it's too long.

I also think that there's no value in calculating sums for lags bigger than half the number of samples. Autocorrelation needs two cycles to have a reasonable chance of estimating the frequency. If you examine lags bigger than half the sample size, you're looking at frequencies that will autocorrelate one cycle, and part of another, and then run out of samples. I think the calculations should stop when the lag is half the number of samples.

Over at instructables, they have a "say something nice," policy, no matter how stupid the post might be. So, when something stupid gets posted, it tends to stay stupid forever. We don't have a policy like that in this forum. You may get roughed up a bit, but you'll see that erroneous code generally gets called out, and somebody fixes it. Somebody may point out something foolish in the sketch below, and you'll only benefit from that.

The sketch below has a constant definition for the analog reading when the input is zero. If you use an AGC microphone from Adafruit, like one of the projects you mentioned, you'll probably find that its quiescent value is something other than midscale on the ADC. Autocorrelation is a bit sensitive to a DC offset, so you'll want to set that value to something consistent with your hardware.

You say:

3DPiper:
One of my tuners is based on an Arduino ...

In return for this code, I hope you'll tell us about that tuner, with a link to a project somewhere, and with your impressions of how well it performs.

All that said, here's the sketch:

const uint16_t nSamples = 512;
int8_t analogs[nSamples];
const uint8_t analogZero = 128;

void setup() {
  DIDR0 = 0x01;  // A0 digital input buffer off

  Serial.begin(115200);

  ADMUX = 0x60;  // AVCC, left-justified, channel 0
  ADCSRA = 0xF5; // Set up ADC
  // Enable, Start, Auto-trigger,
  // Free-run, Clear flag, disble interrupt,
  // clock divisor 32, Rate ~ 38462/sec adc0
}

void loop() {
  acquire(analogs, nSamples);
  show(analogs, nSamples);
  waitKey();
}

void acquire(int8_t * a, uint16_t n) {
  ADCSRA = 0xF5;      // Clear intr flag, keep other settings
  for (uint16_t i = 0 ; i < n ; i++) {
    while (!(ADCSRA & 0x10)); // Wait for conversion
    ADCSRA = 0xF5;    // Clear intr flag, keep other settings
    int16_t j = ADCH; // Get high byte of ADC
    j -= analogZero;  // Subtract offset
    a[i] = (int8_t)j; // Save it
  }
}

void show(int8_t * a, uint16_t n) {
  for (uint16_t i = 0 ; i < n ; i++) {
    Serial.print(i);
    Serial.print(" ");
    Serial.print(a[i]);
    Serial.println();
  }
}

void waitKey() {
  // Wait for a character on the Serial interface
  //   Clear the buffer, discard everything
  while (!Serial.available()) {}
  while (Serial.available()) {
    Serial.read(); // Read and discard a character
    delay(4);      // Wait to see if another char comes
  }
}

You probably want the YIN algorithm, with is based on autocorrelation.

There's an implementation in the Teensy Audio Library, contributed by Collin Duffy. Here's the documentation (look at the right-side panel):

http://www.pjrc.com/teensy/gui/?info=AudioAnalyzeNoteFrequency

There's no hope of ever running this on normal 8 bit AVR-based Arduino. It's a bit taxing for Teensy 3.2, but runs well and detects the fundamental frequency quite well, even when its harmonics are very strong.

There's an example that comes with Teensyduino. With Teensy selected in the Tools > Boards menu, you can find it in File > Examples > Audio > Analysis > NoteFrequency.

The example plays a guitar sample and analyzes it. Of course you can use the design tool to connect live audio input to the notefreq analysis object... but for an example program to demonstrate how it work, recorded samples give you a good idea of its performance on known sounds, and you can just run it with only a Teensy 3.2 and Audio Shield (or even without the shield, if you connect the object to send the sound to the DAC pin).