Pitch detection

Status
Not open for further replies.
Hello again,
I changes the code and now I'm trying to detect the pitch of a 5sec and 100Hz sine, I stored as a wav file on the SD card. I only use the detect-button to check if a note frequency is available.
This is my code

Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioInputI2S                 LineIn;
AudioOutputI2S                LineOut;
AudioRecordQueue              queue1;
//AudioPlaySdRaw                playRaw;
AudioPlaySdWav                playWav;
AudioAnalyzeNoteFrequency     notefreq;
AudioConnection               patchCord1(LineIn,0,queue1,0);
//AudioConnection               patchCord2(playRaw, notefreq);
//AudioConnection               patchCord3(playRaw, 0, LineOut, 0);
//AudioConnection               patchCord4(playRaw, 0, LineOut, 1);
AudioConnection               patchCord2(playWav, notefreq);
AudioConnection               patchCord3(playWav, 0, LineOut, 0);
AudioConnection               patchCord4(playWav, 0, LineOut, 1);
AudioControlSGTL5000          sgtl5000_1;

Bounce buttonRecord = Bounce(0,8);
Bounce buttonDetect = Bounce(1,8);
Bounce buttonStop   = Bounce(2,8);

const int myInput = AUDIO_INPUT_MIC;

int mode = 0;           // 0=Stop, 1=Recording, 2=Detecting

File frec;

void setup()
{
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  AudioMemory(60);
  notefreq.begin(.15);

  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.9);

  SPI.setMOSI(7);
  SPI.setSCK(14);
  if (!(SD.begin(10)))
  {
    while(1)
    {
      Serial.println("Unable to access the SC card");
      delay(500);
    }
  }
}

void loop()
{
  buttonRecord.update();
  buttonDetect.update();
  buttonStop.update();
  if (buttonRecord.fallingEdge())
  {
    Serial.println("Record Button Press");
    if (mode == 0) startRecording();
  }
  if (buttonDetect.fallingEdge())
  {
    Serial.println("Detect Button Press");
    if (mode == 0) Detecting();
  }
  if (buttonStop.fallingEdge())
  {
    Serial.println("Stop Button Press");
    if (mode == 1) stopRecording();
    if (mode == 2) mode = 0;
  }
  if (mode == 1) 
  {
    Serial.println("continue Recording");
    continueRecording();
  }
  if (mode == 2)
  {
    Serial.println("continue Detecting");
    continueDetecting();
  }
  
}
void startRecording()
{
  Serial.println("startRecording");
  if (SD.exists("RECORD.RAW"))
  {
    SD.remove("RECORD.RAW");
  }
  frec = SD.open("RECORD.RAW", FILE_WRITE);
  if (frec)
  {
    queue1.begin();
    mode = 1;
  }
}

void continueRecording()
{
  if(queue1.available() >= 2)
  {
    byte buffer[512];
    memcpy(buffer,queue1.readBuffer(),256);
    queue1.freeBuffer();
    memcpy(buffer+256,queue1.readBuffer(),256);
    queue1.freeBuffer();
    elapsedMicros usec = 0;
    frec.write(buffer,512);
  }
}

void stopRecording() 
{
  Serial.println("stopRecording");
  queue1.end();
  if (mode == 1) 
  {
    while (queue1.available() > 0) 
    {
      frec.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
    }
    frec.close();
  }
  mode = 0;
}
void Detecting()
{
  Serial.println("Detecting");
  playWav.play("100Hz.WAV");
  if (notefreq.available())
  {
    Serial.println("test");
  }
  if(!playWav.isPlaying())
  {
    playWav.stop();
  }
  mode = 2;
}
void continueDetecting()
{
  playWav.play("100Hz.WAV");
  if (notefreq.available())
  {
    Serial.println("test");
  }
  if(!playWav.isPlaying())
  {
    playWav.stop();
    mode = 0;
  }
}

and thats my serial output:

Code:
Detect Button Press
Detecting
continue Detecting

Can anyone help me to fix it? I don't know why there is no note frequency available....
Thanks a lot!
 
Hello, I'm trying to make it easier. This is the Playing Music Tutorial.

Code:
// Advanced Microcontroller-based Audio Workshop
//
// https://github.com/PaulStoffregen/AudioWorkshop2015/raw/master/workshop.pdf
// https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015
// 
// Part 1-3: First "Hello World" program, play a music file
//
// WAV files for this and other Tutorials are here:
// http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioPlaySdWav            playSdWav1;
AudioOutputI2S            i2S1;
AudioAnalyzeNoteFrequency notefreq;
AudioMixer4               mixer;

AudioConnection           patchCord1(playSdWav1, 0, mixer, 0);
//AudioConnection           patchCord2(mixer, 0, notefreq, 0);
AudioConnection           patchCord3(mixer, 0, i2S1, 0);

AudioControlSGTL5000      sgtl5000_1;

void setup() 
{
  Serial.begin(9600);
  AudioMemory(8);
  notefreq.begin(.15);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.2);
  SPI.setMOSI(7);
  SPI.setSCK(14);
  if (!(SD.begin(10))) 
  {
    while (1) 
    {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  if (playSdWav1.isPlaying() == false) 
  {
    Serial.println("Start playing");
    playSdWav1.play("100Hz.WAV");
    delay(10); // wait for library to parse WAV info
  }
  delay(1000);
}

void loop() 
{
  
  if (notefreq.available()) 
  {
    float note = notefreq.read();
    float prob = notefreq.probability();
    Serial.printf("Note: %3.2f | Probability: %.2f\n", note, prob);
  }
}

So I play my 100Hz Sine Wave from the SD Card and want to detect the pitch. But I can only hear the tone when I comment this line:

Code:
AudioConnection           patchCord2(mixer, 0, notefreq, 0);

And the detecting is not working. I think it should be quite simple but I can't get it working...Who can help me please!
 
Your best bet on understanding the signal flow would be to lay this out in the audio design tool.
One possible solution would be to replace:
AudioConnection patchCord2(mixer, 0, notefreq, 0);
with
AudioConnection patchCord2(playSdWav1, 0, notefreq, 0);
 
I would like to try it here. Can you post a zip file with the 100Hz.WAV file?

Edit: does the file play correctly in any cases? I see you have a lowercase "z" in the name. Normally the 8.3 filenames used by the SD library are all uppercase.
 
Code:
// 
// Part 2-1: Using the Microphone


///////////////////////////////////
// copy the Design Tool code here
///////////////////////////////////


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=177,216
AudioAnalyzeNoteFrequency notefreq1;      //xy=418,374
AudioOutputI2S           i2s2;           //xy=438,227
AudioConnection          patchCord1(i2s1, 0, notefreq1, 0);
AudioConnection          patchCord2(i2s1, 0, i2s2, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=176,656
// GUItool: end automatically generated code

void setup() {
  Serial.begin(9600);
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(36);
  notefreq1.begin(.15);
  delay(1000);
}
float note, prob;
void loop() {

 if (notefreq1.available()) {
        note = notefreq1.read();
        prob = notefreq1.probability();
        Serial.printf("Note: %3.2f | Probability: %.2f\n", note, prob);
  }
 
}

Tested code using the mic input. One difference I see is the amount of AudioMemory.
 
Okay it works without the SD Card. Better for me :)

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=177,216
AudioAnalyzeNoteFrequency notefreq1;      //xy=418,374
AudioAnalyzePeak         peak1;          //xy=317,123
AudioOutputI2S           i2s2;           //xy=438,227
AudioConnection          patchCord1(i2s1, 0, notefreq1, 0);
AudioConnection          patchCord2(i2s1, 0, i2s2, 0);
AudioConnection          patchCord3(i2s1, 0, peak1, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=176,656
// GUItool: end automatically generated code

float note;

void setup() 
{
  Serial.begin(9600);
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
  sgtl5000_1.micGain(36);
  notefreq1.begin(.15);
  delay(1000);
  pinMode(0, INPUT_PULLUP);
}
void loop()
{
  if(peak1.available())
  {
    int monoPeak = peak1.read() * 300.0;
    if(monoPeak >1)
    {
      noteFreq();
    }
  }
}
void noteFreq() 
{
  if (notefreq1.available()) 
  {
    for(int i=0;i<10;i++)
    {
      note = notefreq1.read();
      Serial.printf("Note: %3.2f\n", note);
      delay(50);
     }
     Serial.println("-------------");
  }
}

The code can now detect the frequency of the audiosignal on line in. It only detects when the peak is high enough. (I also have to involve a button for the detection mode.) When I tap on the loudspeaker i used as a microphone, I get the same frequency that I measure in this Thread:

https://forum.pjrc.com/threads/33319-Resonant-frequency-of-an-oscillating-circuit

So everything i finde.
Now I have to convert the loudspeaker to a pressure microphone the measure the note frequency of a bass drum and not the own resonance frequency.

Thanks for all your help.
 
Hello again. I nearly finished my project but i have one more problem. Now I can detect the fundamental frequency of a bass drum, using a loudspeaker. and i am able to measure its resonance frequency. I use audioanalyzerms, audioanalyzepeak and audioanalyzenotefrequency but it doesn't word in the same code. when i put notefreq.begin in the code, the rms and peak doesn't work anymore. Does anyone know this problem and how to solve it? Do I need more audio memory or something?

Code:
////////////////////////////////////////////////////////////////--Libraries
#include <Audio.h>                                              // 
#include <Wire.h>                                               //
#include <SPI.h>                                                //
#include <SD.h>                                                 //
#include <SerialFlash.h>                                        //
#include <LiquidCrystal.h>                                      //
#include <Bounce.h>                                             //
////////////////////////////////////////////////////////////////--Objects--
AudioSynthWaveformSine    sine;                                 // Sinus
AudioOutputI2S            LineOut;                              // Output = LineOut
AudioAnalyzeRMS           RMS;                                  // RMS for the voltage on the 
                                                                // resistor
AudioAnalyzeNoteFrequency notefreq1;                            //
AudioAnalyzePeak          peak1;                                //
AudioInputI2S             LineIn;                               // Input for RMS;
AudioConnection           patchCord1(sine, 0, LineOut, 1);      // Sinus -> LineOut
AudioConnection           patchCord2(sine, 0, LineOut, 0);      // Sinus -> LineOut
AudioConnection           patchCord3(LineIn, 0, RMS, 0);        // RMS -> Input_RMS;
AudioConnection           patchCord4(LineIn, 0, notefreq1, 0);  //
AudioConnection           patchCord5(LineIn, 0, peak1, 0);      //
AudioControlSGTL5000      sgtl5000_1;                           // Audioshield
LiquidCrystal             lcd(5, 4, 3, 2, 1, 0);                // lcd( )
////////////////////////////////////////////////////////////////-- Variables----------------
int f0=0;                                                       // fundamental freuquency of 
                                                                // the kickdrum
int f_i;                                                        // runningindex for f
int f_start = 20;                                               // startfrequency
int f_Res = 0;                                                  // resonancefrequency
int f_end = 60;                                                 // stopfrequency
double z_max = 0.000;                                           // highest impedance
double z = 0.00000000;                                          // voltage at the resistor
int f_intervall = 0;                                            // relation of fRes & f0
int f_diff = 0;                                                 // differance of fRes & f0
const int myInput = AUDIO_INPUT_LINEIN;                         // Input = LineIn
const int buttonPin1 = 8;                                       // Pushbutton 1 on pin 20
const int buttonPin2 = 20;                                      // Pushbutton 2 on pin 21
Bounce button1 = Bounce(buttonPin1, 5);                         // 10 ms debounce
Bounce button2 = Bounce(buttonPin2, 30);                        // 10 m debounce
int buttoncounter = 1;                                          // 1= f0; 2= f_Res; 3= Rec
////////////////////////////////////////////////////////////////--Setup----------------------
void setup()                                                    //
{                                                               //
  AudioMemory(22);                                              // 20*128Bit served
  sgtl5000_1.enable();                                          // activate Audio Shield
  sgtl5000_1.volume(1);                                         // volume between 0-1
  sgtl5000_1.inputSelect(myInput);                              // Input = myInput
  //notefreq1.begin(0.15);
  delay(1000);
  sine.amplitude(1);                                            // amplitude of Sine
  //sgtl5000_1.micGain(36);
  Serial.begin(9600);                                           //
  pinMode(buttonPin1, INPUT_PULLUP);                            // 
  pinMode(buttonPin2, INPUT_PULLUP);                            //
  pinMode(16, OUTPUT);                                          // Output for Relais
  lcd.begin(16, 2);                                             // set Display Size
  lcd.setCursor(9,0);                                           //
  lcd.print("|");                                               //
  lcd.setCursor(9,1);                                           //
  lcd.print("|");                                               // 
}                                                               //
////////////////////////////////////////////////////////////////--Loop------------------------
void loop()                                                     //
{                                                               //
  if(button1.update())                                          // 
  {                                                             //
    if(button1.risingEdge())                                    // If button 1 is pushed
    {                                                           // counts up from 1 to 3
      buttoncounter++;                                          //
    }                                                           //
    if(buttoncounter > 3)                                       //
    {                                                           //
      buttoncounter = 1;                                        //
    }                                                           //
  }                                                             //
  switch (buttoncounter)                                        // If buttoncounter is:
      {                                                         // 
        case 1:                                                 // 1
          FundamentalFrequency();                               //open BD mode
          //Serial.println("measure fundamental Frequency");      //
          break;                                                //
        case 2:                                                 // 2
          ResonanceFrequency();                                 // open SK mode
          //Serial.println("resonance");                          //
          break;                                                //
        case 3:                                                 // 3 
          RecordingMode();                                      // open recording mode
          //Serial.println("recording");                          //
          break;                                                //
      }                                                         //               
}                                                               //
////////////////////////////////////////////////////////////////--Measures Kickdrum-----------
void FundamentalFrequency()                                     //
{                                                               //
  digitalWrite(16, HIGH);                                       // set the relais
  lcd.setCursor(0, 0);                                          // |>BD=            |
  lcd.print(">BD=");                                            // | SK=            |
  lcd.setCursor(0, 1);                                          //
  lcd.print(" SK=");                                            //
  ////////////////////////////////////////////////////////////////
  //Serial.println("f0");                                       //
  if(button2.update())                                          // S3 pressed
  {                                                             //
    if(button2.fallingEdge())                                   //
    {                                                           //
      //Serial.println("measure fundamental Frequency");        //
      while(button1.update()==false)                            // record everytime S3 is
      {                                                         // pressed
        if (peak1.available())                                  // is there is signal
        {                                                       //
          float monoPeak = peak1.read() * 100.0;                  // 
          if (monoPeak > 1)                                   // is the signal loud enough?
          {                                                     //
           //Serial.println(monoPeak);
           if (notefreq1.available())                           // is a fundamental frequency
           {                                                    // aviable?
            //Serial.println("f0 da");
            delay(800);                                         //
            f0 = notefreq1.read();                              // save it to int f0
            Serial.printf("Note: %3.2df\n", f0);                 //
            lcd.setCursor(5, 0);                                // |   50 Hz       |
            lcd.print(f0);                                      // |               |
            lcd.setCursor(7, 0);                                //
            lcd.print("Hz");                                    //
            delay(1000);                                        // wait 1sec.
            }                                                   //
          delay(100);
          }                                                     //
        }                                                       //
        //buttoncounter = 3;                                      //
      }                                                         //
    }                                                           //
  }                                                             //
}                                                               //
////////////////////////////////////////////////////////////////--Shows to Resonance frequency
void ResonanceFrequency()                                       //
{                                                               //
  lcd.setCursor(0, 0);                                          // | BD=            |
  lcd.print(" BD=");                                            // |>SK=            |
  lcd.setCursor(0, 1);                                          //
  lcd.print(">SK=");                                            //
  ////////////////////////////////////////////////////////////////
  //Serial.println("f_Res");                                    //
  {                                                             //
    if(button2.update())                                        // S3 pressed
      {                                                         //
        if(button2.fallingEdge())                               //
        {                                                       //
          //Serial.println("resonance");                        //
          sine.amplitude(1);                                    // Set the amplitude to 1
          z_max = 0;                                            //
          f_Res = 0;                                            //
          for (f_i = f_start; f_i <= f_end; f_i++)              // Loop from start- to
          {                                                     // stopfrequency
            sine.frequency(f_i);                                // frequency of sweep
            delay(2000 / f_i);                                  // play f for T=2/f
            z = RMS.read();                                     // Calcu V_RMS,store in z
            z = z * 715;                                        // multiply get the real v
            if (z >= z_max)                                     // Detecting the maximum
            {                                                   //
              z_max = z;                                        // Save the the f_0 and Vmax
              f_Res = f_i;                                      //
            }                                                   //
          }                                                     //
          //Serial.println(f_Res);                                // 
          lcd.setCursor(5, 1);                                  // example:
          lcd.print(f_Res);                                     // |        |       |
          lcd.setCursor(7, 1);                                  // |    26Hz|       |
          lcd.print("Hz");                                      //
          sine.amplitude(0);                                    // Set the amplitude to zero
          Intervall();                                          // mesurement for intervall
        }                                                       //
      }                                                         //
    }                                                           //
}                                                               //
////////////////////////////////////////////////////////////////--Record Mode---------------
void RecordingMode()                                            //
{                                                               //
 lcd.setCursor(0,0);                                            // | BD=            |
 lcd.print(" ");                                                // | SK=            |
 lcd.setCursor(0,1);                                            //
 lcd.print(" ");                                                //
 //Serial.println("record");                                    //
 if(buttoncounter==3)                                           //
 {                                                              //
  digitalWrite(16, LOW);                                        // no voltage on
  delay(100);                                                   // the relais
 }                                                              //
}                                                               //
////////////////////////////////////////////////////////////////--Interval------------------
void Intervall()                                                //
{                                                               //
  f_diff = f0-f_Res;                                            // 
   if (0 > f_diff-(f0/8))                                     //// Prime
   {                                                            //
    f_intervall = -1*(f_diff);                                  //
    //Serial.printf("Prime %3d\n",f_intervall);                   //
    lcd.setCursor(10,0);                                        //
    lcd.print("Prime ");                                        //
   }                                                            //
   else if (0 < f_diff-(f0/8) && 0 > f_diff-(3*f0/8))        //// Quarte
   {                                                            //
    f_intervall = -1*(f_diff-(f0/4));                           //
    //Serial.printf("Quarte %3d\n",f_intervall);                  //
    lcd.setCursor(10,0);                                        //
    lcd.print("Quarte");                                        //
   }                                                            //
    else if (0 <= f_diff-(3*f0/8))                            //// Octave
   {                                                            //
    f_intervall = -1*(f_diff-(f0/2));                           //
    //Serial.printf("Oktave %3d\n",f_intervall);                //
    lcd.setCursor(10,0);                                        //
    lcd.print("Octave");                                        //
   }                                                            //
   lcd.setCursor(10,1);                                         //
   lcd.print("   Hz");                                          //
   lcd.setCursor(10,1);                                         //
   lcd.print(f_intervall );                                     //
}                                                               //

Bildschirmfoto 2016-06-15 um 09.56.17.png
 
This is a code, that works.
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <LiquidCrystal.h>                                      //


AudioInputI2S            LineIn;   
AudioAnalyzeNoteFrequency notefreq1;
AudioAnalyzePeak           peak1;
AudioOutputI2S           LineOut;
AudioConnection          patchCord1(LineIn, 0, notefreq1, 0);
AudioConnection          patchCord2(LineIn, 0, LineOut, 0);
AudioConnection          patchCord3(LineIn, 0, peak1, 0);
AudioControlSGTL5000     sgtl5000_1;
LiquidCrystal             lcd(5, 4, 3, 2, 1, 0);                // lcd( )

void setup() 
{
  Serial.begin(9600);
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
  //sgtl5000_1.micGain(36);
  notefreq1.begin(0.5);
  delay(1000);
  pinMode(16, OUTPUT);
  digitalWrite(16, HIGH);
  }
float note, prob;
void loop() 
{
  if (peak1.available())                                  
  {                                                     
     float monoPeak = peak1.read();                 
   if (monoPeak > 0.005)                                   
    {                                                     
      if (notefreq1.available())                           
      {
       delay(100);                                                                       
       note = notefreq1.read();                             
       Serial.printf("Note: %3.2f\n", note);
       lcd.setCursor(5, 0);                    
       lcd.print(note);                        
       lcd.setCursor(7, 0);                    
       lcd.print("Hz   ");                
       delay(1000);                                    
     }                                        
   }                                   
  }
}
 
Okay, its a problem with the audio memory. When i set it up to 26 it works, but the LCD-Display is now shifting some letters. Is there a solution to get more memory?
 
AudioMemory(26) shouldn't consume too much. If you need more, try more than 26. Each time you increase, watch the info Arduino prints, like this:

Code:
Global variables use 9,484 bytes (14%) of dynamic memory, leaving 56,052 bytes for local variables.

AudioMemory() consumes the global variables memory. For most programs, even 4000 is plenty for "local variables".
 
Hello there! I'm so glad that there is so much buzzing around this subject with very interesting experiences!

My project is to analyze in real time (<10ms latency) a string instrument (lets start with a guitar) signal. I am working with the audio teensy system and have tried the FFT1024 that has a really fast response but hasn't a good accuracy (43Hz). I would need around 5Hz accuracy.
Then I have tried the notefreq program which is very accurate but I have too much latency with it.
So here are my questions :

1. How would it be possible to focus the FFT1024 to a short range of frequencies so to reduce the 43Hz step? For example 500Hz-5000Hz?

2. For my latency need, I understand that there is no way to analyze frequencies lower than around 400Hz but maybe analyze the harmonic which sounds tricky to me.
So would it be possible to shift the signal from 1 to 4 octaves up (like an octaver) and then to feed the FFT1024 with the new signal shifted?

I have looked over the queue program but 128 samples (the minimum) is already representing around 5ms time working before shifting and analyzing the signal.
So I may try to work with some lists. How can I fill each case of a list with each 16bit sample from the codec?

Then I may double, triple,... n (function of 1, 2,... n octaves) and reduce the time between each sample... Does anyone has an idea to do that? fig_2_7.png

Finally, how could I feed the FFT with this new signal and not the LineIN or MIC signal from the codec? With the FFT1024 from audio Library I don't see how to do this.


I think that some of my questions are redundant to some of the threads I read here but maybe there are updates ?

Thank you all!!!
 
Then I have tried the notefreq program which is very accurate but I have too much latency with it.

Look at its code within the library. As I recall, there are some parameters you can tweak to reduce the buffering, at the expense of low frequency detection.

These others ideas like resampling are unlikely to help. FFT is definitely the wrong approach if you want low latency. In general, I suspect your timing goal just isn't very realistic.
 
Status
Not open for further replies.
Back
Top