Realtime note(frequency) detection with Teensy

esr0159

Member
Hi Guys,

I'd like to hear your thoughts and guidance for my project. I would need to detect the note being played from an instrument (specifically a violin) and whatever note is being played I'll get the data from the micro and send it to a GUI (currently I have it coded in VB).

I had seen a similar project in the arduino forum and instructables (www.instructables.com/id/Arduino-Audio-Input/?ALLSTEPS) regarding audio input but upon checking the forum looks like teensy would better? I have no experience with Teensy but I already used arduino in the past.

Here is my current setup

audio jack <> amplifier <> arduino <> to computer

There are some shops here in our country selling the teensy 3.2 but not the audio shield.

Hoping for your input, thank you.
 
Is your project course related or just personal interest?

The Audio library has AudioAnalyzeNoteFrequency.

That same author has this one Arduino-Frequency-Detection/. This one is noted in the one below that uses a different technique.

This instructables Reliable-Frequency-Detection-Using-DSP-Techniques/ that goes to this link : reliable-frequency-detection-using-dsp-techniques/ that I played with a bit using provided static samples. IT had some obvious in-efficiencies that made it run longer than needed - but it worked.
 
Course related (which came form my interest with violins).

I'll go ahead and check the links that you posted. Thanks defragster.

Edit:

I'll try to test the 2nd link that you posted seems the author has a guitar tuner created as well.
 
Last edited:
Yes, please try File > Examples > Audio > Analysis > NoteFrequency.

As you can see in the example, so far we have guitar and tuba sound samples for testing.

If you'd be willing to contribute violin samples, I'd love to add them to the library. Please, only post samples you've recorded which are public domain (not part of any copyright protected performance or recorded material) and are single notes played on a well tuned instrument. The sounds should be approx 2 seconds or less, so they fit nicely in the leftover program memory.
 
There are some shops here in our country selling the teensy 3.2 but not the audio shield.

You can use an ADC pin on Teensy 3.2 for audio input. The quality isn't as good as the audio shield. A circuit with several resistors and capacitors is required to get the proper 0.6V DC bias.

Like all audio library objects, the documentation can be found in the design tool. Look on the right side panel. Here's a direct link:

https://www.pjrc.com/teensy/gui/?info=AudioInputAnalog
 
Hi Paul,

I'll try to record some notes using my violin and will try to update the thread asap. Bit swamped with work for now and I'll also try to see if I can get a grab of the teensy 3.2 soon.
 
Hi Everyone,

Sorry for the late update (totally swamped with work). Anyways I was able to get the teensy 3.2. Cool thing is that I tried the notefrequency example :) I recorded some notes from my violin (only used my android phone for recording) and was able to convert the wav files to sketch.

Here's the screenshot

Open A string
a-analysis.JPG

Open E String
e-analysis.JPG
Open D String
d-analysis.JPG
Open G String
g-analysis.JPG

Upon checking the frequency table online, the teensy analysis is a bit far . Example for Open Astring I should get 440, for E string 659, D string 294, G string 196.

Is it because of my wav files that I'm getting the wrong value from what I need?

Btw would notefrequency be okay for real time analysis or should I check AudioAnalyze Frequency?

Would like to get your inputs. Thanks!
 
The samples are 44100Hz 16-bit WAV, but they are not "clean" recordings of a violin. They sound more like synthesized sounds.
When I look at the A string sample with Goldwave, the spectrum shows that it is somewhere in the 415Hz range (which agrees with the results from the sketch) but with a lot of harmonics which make it sound unlike a violin (to me anyway).

Pete
 
The samples are 44100Hz 16-bit WAV, but they are not "clean" recordings of a violin. They sound more like synthesized sounds.
When I look at the A string sample with Goldwave, the spectrum shows that it is somewhere in the 415Hz range (which agrees with the results from the sketch) but with a lot of harmonics which make it sound unlike a violin (to me anyway).

Pete
I was going to ask if he was sure the violin was in tune:)
 
thanks for the feedback Pete, I'll try to record again tomorrow (its evening here already) and post my results again on this thread.

edit

@at duff
My tuner is so old :D it says its in tune but I'll check again tomorrow, will double check everything before posting :)
 
I opened the d-string file in Audacity, then clicked Analyze > Plot Spectrum, and then changed the FFT size to 4096 samples so the peaks are more easily visible. I resized the window very large to better see the low frequencies.

As you swipe your cursor across the plot, it shows the frequency of where your cursor is at, and the frequency of the nearest peak. Here's a screenshot. I've put a red circle over the peak indication...

freq.jpg
(click for full size)

Audacity is showing 275 Hz, which agrees very closely with the 275.79 to 276.76 output of the audio analysis. This very small discrepancy might be due to the fact Teensy is actually using 44117 Hz sample rate. When that data is saved to a file and later interpreted as if it were 44100 Hz, you can expect approx 0.04% lower readings. There's probably some way to tell Audacity this data really is 44117 Hz, but I'm not familiar enough with those finer points of advanced Audacity usage.

It's really looking like either your phone somehow recorded badly, or this violin simply is out of tune.
 
@esr0159. There's a good sample of a violin playing an open D string here. I used Goldwave to convert it to a WAV and then used wav2sketch to convert it to the array used by the NoteFrequency example sketch. This is a sample of the output from the sketch. You can see that it does really well.
Code:
Note: 294.68 | Probability: 0.98
Note: 294.36 | Probability: 0.98
Note: 294.31 | Probability: 0.98
Note: 294.54 | Probability: 0.97
Note: 294.33 | Probability: 0.98
Note: 294.38 | Probability: 0.98
Note: 294.16 | Probability: 0.99
Note: 293.64 | Probability: 1.00
Note: 293.23 | Probability: 1.00
Note: 293.34 | Probability: 1.00
Note: 293.05 | Probability: 1.00
Note: 292.96 | Probability: 1.00
Note: 293.03 | Probability: 1.00
Note: 293.22 | Probability: 1.00
Note: 293.12 | Probability: 1.00
Note: 293.07 | Probability: 1.00
Note: 293.67 | Probability: 0.98
Note: 293.55 | Probability: 0.99
Note: 293.74 | Probability: 0.99
Note: 293.73 | Probability: 0.99
Note: 293.85 | Probability: 0.99
Note: 293.29 | Probability: 0.99
Note: 293.22 | Probability: 0.99
Note: 293.69 | Probability: 0.99

Pete
 
Hi Paul,

Looks like it was my phone all along, here's a new recording of the A string. I recorded it directly to my laptop (built in microphone) and I'm getting a closer value to 440 (getting 436).

a-analysis2.JPG

Hi Pete,

Let me check out those samples too thanks! Will try to record again and compare my output.


Since I haven't built the audio jack to teensy ckt, can I use the note frequency for real time input? I am testing out the notefrequency with recorded sounds to familiarize myself with this microcontroller + the library itself :)

PS: I shouldn't have trusted my old clip on tuner...used the android tuner, there was a 40hz difference.
 
Last edited:
The audio library makes it easy to change inputs/outputs etc.
The code below allows you to use MIC input instead of in-memory samples.
When I play a 440Hz tone through my headphones to the mic input I get this sort of output:
Code:
Note: 439.34 | Probability: 0.96
Note: 440.56 | Probability: 0.96
Note: 443.57 | Probability: 0.92
Note: 438.79 | Probability: 0.97
Note: 439.04 | Probability: 0.97
Note: 440.27 | Probability: 0.97
Note: 439.93 | Probability: 0.95
Note: 484.66 | Probability: 0.91
Note: 440.73 | Probability: 0.96
Note: 443.48 | Probability: 0.94
Note: 439.61 | Probability: 0.97
Note: 438.56 | Probability: 0.97
Note: 439.15 | Probability: 0.97
Note: 439.30 | Probability: 0.97
Note: 439.45 | Probability: 0.95
Note: 438.99 | Probability: 0.97
Note: 444.41 | Probability: 0.96
Note: 438.79 | Probability: 0.97
Note: 439.71 | Probability: 0.96
Note: 439.94 | Probability: 0.95
Note: 439.65 | Probability: 0.94
Note: 439.72 | Probability: 0.96
Note: 438.97 | Probability: 0.97
Note: 438.76 | Probability: 0.96
Note: 438.70 | Probability: 0.96
Note: 440.68 | Probability: 0.94
Note: 438.87 | Probability: 0.97
Note: 440.31 | Probability: 0.96
Note: 441.02 | Probability: 0.96

Pete


Code:
/* Detect the frequency of music notes, by Colin Duffy

   This example repeatedly plays a guitar note (output to the DAC pin)
   and prints an analysis of the frequency to the Arduino Serial Monitor

170430 Modified by Pete (El_Supremo) to allow a microphone input
  instead of the memory playback. define or comment MIC_INPUT
  
   https://forum.pjrc.com/threads/32252-Different-Range-FFT-Algorithm/page2
   https://github.com/duff2013/AudioTuner
*/
/*
  C     C#    D     Eb    E     F     F#    G     G#    A     Bb    B
  0 16.35 17.32 18.35 19.45 20.60 21.83 23.12 24.50 25.96 27.50 29.14 30.87
  1 32.70 34.65 36.71 38.89 41.20 43.65 46.25 49.00 51.91 55.00 58.27 61.74
  2 65.41 69.30 73.42 77.78 82.41 87.31 92.50 98.00 103.8 110.0 116.5 123.5
  3 130.8 138.6 146.8 155.6 164.8 174.6 185.0 196.0 207.7 220.0 233.1 246.9
  4 261.6 277.2 293.7 311.1 329.6 349.2 370.0 392.0 415.3 440.0 466.2 493.9
  5 523.3 554.4 587.3 622.3 659.3 698.5 740.0 784.0 830.6 880.0 932.3 987.8
  6 1047  1109  1175  1245  1319  1397  1480  1568  1661  1760  1865  1976
  7 2093  2217  2349  2489  2637  2794  2960  3136  3322  3520  3729  3951
  8 4186  4435  4699  4978  5274  5588  5920  6272  6645  7040  7459  7902

  Guitar strings are E2=82.41Hz, A2=110Hz, D3=146.8Hz, G3=196Hz, B3=246.9Hz, E4=329.6Hz

  Bass strings are (5th string) B0=30.87Hz, (4th string) E1=41.20Hz, A1=55Hz, D2=73.42Hz, G2=98Hz

  This example tests the yin algorithm with actual notes from nylon string guitar recorded
  as wav format at 16B @ 44100 samples/sec. Since the decay of the notes will be longer than what
  the teensy can store in flash these notes are truncated to ~120,000B or about 1/2 of the whole
  signal.
*/
#include <SerialFlash.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
//---------------------------------------------------------------------------------------
#include "guitar_e2_note.h"
#include "guitar_a2_note.h"
#include "guitar_d3_note.h"
#include "guitar_g3_note.h"
#include "guitar_b3_note.h"
#include "guitar_e4_note.h"
#include "tuba_1.h"
#include "tuba_2.h"
#include "tuba_3.h"
#include "tuba_4.h"
#include "tuba_5.h"

//>>> Choose microphone input or in-memory sample
#define MIC_INPUT

#ifndef MIC_INPUT
//---------------------------------------------------------------------------------------
AudioAnalyzeNoteFrequency notefreq;
AudioOutputAnalog         dac;
AudioPlayMemory           wav_note;
AudioMixer4               mixer;
//---------------------------------------------------------------------------------------
AudioConnection patchCord0(wav_note, 0, mixer, 0);
AudioConnection patchCord1(mixer, 0, notefreq, 0);
AudioConnection patchCord2(mixer, 0, dac, 0);
//---------------------------------------------------------------------------------------
IntervalTimer playNoteTimer;


void playNote(void) {
  if (!wav_note.isPlaying()) {
    // Uncomment one of these sounds to test notefreq
    wav_note.play(guitar_e2_note);
    //wav_note.play(guitar_a2_note);
    //wav_note.play(guitar_d3_note);
    //wav_note.play(guitar_g3_note);
    //wav_note.play(guitar_b3_note);
    //wav_note.play(guitar_e4_note);
    //wav_note.play(tuba_1);
    //wav_note.play(tuba_2);
    //wav_note.play(tuba_3);
    //wav_note.play(tuba_4);
    //wav_note.play(tuba_5);
    digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
  }
}
#else
// GUItool: begin automatically generated code
AudioInputI2S            i2s;           //xy=226,347
AudioOutputAnalog        dac;            //xy=546,362
AudioAnalyzeNoteFrequency notefreq;       //xy=551,311
AudioConnection          patchCord1(i2s, 0, notefreq, 0);
AudioConnection          patchCord2(i2s, 0, dac, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=227,273
// GUItool: end automatically generated code
#endif


//---------------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);

  AudioMemory(30);
  /*
      Initialize the yin algorithm's absolute
      threshold, this is good number.
  */
#ifdef MIC_INPUT
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.8);
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  // Mic gain for a MEMS microphone is zero
  sgtl5000_1.micGain(0);
  notefreq.begin(.15);
#else
  pinMode(LED_BUILTIN, OUTPUT);
  notefreq.begin(.15);
  // Audio library isr allways gets priority
  playNoteTimer.priority(144);
  playNoteTimer.begin(playNote, 1000);
#endif

}

void loop() {
  // read back fundamental frequency
  if (notefreq.available()) {
    float note = notefreq.read();
    float prob = notefreq.probability();
    Serial.printf("Note: %4.2f | Probability: %.2f\n", note, prob);
  }
}
 
The audio library makes it easy to change inputs/outputs etc.
The code below allows you to use MIC input instead of in-memory samples.
When I play a 440Hz tone through my headphones to the mic input I get this sort of output:
Check the cpu usage also, this current Audio object takes alot of cpu cycles which can distort input waveform from your mic. A good way to check is to output the waveform to the dac and use oscope to see if there is continuous waveform.

My new version of this decimates and filters the input signal before processing which can greatly reduces cpu usage. You can choose between a decimation factor of 1, 2, 4, 8 which is an effective sample rate of (~44100 Hz), (~22050Hz), (~11025 Hz), (~5512.5 Hz) though a decimation of 1 will surely blow up the cpu usage. The other thing is you need to supply the FIR filter coeff for the decimation, the examples already have the FIR coeff you can use which probably are not the best but work with the examples. This version is still beta and I plan to come back to it sometime in the future.
 
Hello again,

So here's my initial draft of the code. I'm able to enter values thru serial monitor and teensy is able to read it correctly, since I haven't created my hardware yet I decided to use the recorded audio file as a test input.

The program flow is as follow
- select scale
- note must be played correctly before proceeding to the next note of the scale.

The Note functions is based on the NoteFrequency example.

PS: +1 and -4 are just there for me to have a test range.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include "AudioSampleAstrin2.h"
// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=146,135
AudioAnalyzeNoteFrequency notefreq;      //xy=374,170
// GUItool: end automatically generated code

//for testing
AudioPlayMemory wav_note;
IntervalTimer playNoteTimer;

AudioOutputAnalog         dac;
AudioMixer4               mixer;
//---------------------------------------------------------------------------------------
AudioConnection patchCord0(wav_note, 0, mixer, 0);
AudioConnection patchCord1(mixer, 0, notefreq, 0);
AudioConnection patchCord2(mixer, 0, dac, 0);

//


int trainingdelay = 1000;
int data;
float frequencyx;


       
void setup() {
  // put your setup code here, to run once:
  AudioMemory(30);
  Serial.begin(9600);
 
  notefreq.begin(.15);

  wav_note.play(AudioSampleAstrin2);
}

void loop() {
  // put your main code here, to run repeatedly:
   
  if(Serial.available())
  {
    data = Serial.read()-'0';
    if(data == 49) //GUI sends character a
    {
       Serial.println("Entering A Major");
       AMajor(); 
       
    }
  }
  
}

void AMajor()
{
  
  Serial.println(23); //send data to GUI
 
  Note(440); //A
  delay(trainingdelay); 
  Serial.println("A note played");
  Serial.println(24);
  Note(493.883); //B
  delay(trainingdelay);
  //more notes here, trimmed for forum post 
  Serial.print("done");

}

void Note (float noteval)
{
  float note;
  float  x; 

  float noteLow;
  float noteHigh;
  
  noteLow = noteval - 4;
  noteHigh = noteval + 1;
  while (note!=noteval)
  {
    if (notefreq.available())
    {
      note = notefreq.read();
      if(noteHigh<= note || note >= noteLow)
      {
        Serial.println("correct note played");
        break;
      }
    }
  }
monitor2.JPG

Here's the updated A string https://www.dropbox.com/s/ggxka9k74v4drt9/astrin2.wav?dl=0

And seems I'm able to make it work realized my sample is reading at around 436~ adjusted the noteval ranges

I'm so having fun with this :)
 
Last edited:
Hi!
Great stuff!
I was wondering, is there any way to determine to what note an entire song is tuned?
Would love to hear your thoughts!
 
Back
Top