Go Down

Topic: Incoming analog signal to MIDI Out (Read 1 time) previous topic - next topic

Hi guys

I know there are a lot of methods of having an incoming analog signal (let's say from a guitar) and convert to MIDI. Particularly I am more interested in how Stephen Hobley did on his project, as shown here:

http://www.stephenhobley.com/blog/2011/01/24/pitch-and-volume-tracking-midi-interface-for-the-theremin/

I would ask Hobley himself, but he has not responded to my email for weeks so I figured I will ask you guys in deciphering his code.

The Volume data is pretty straightforward, but the pitch detection is what baffles me. Here's the audio component of his project:
http://www.stephenhobley.com/blog/wp-content/uploads/2011/01/schematic_4_web.gif
[the threshold comparator is what I'm focused on now]

According to his code, he takes the pitch preview of the theremin [which is analog) and convert it to square waves and feed it into an interrupt pin in the Atmega328p

Code: [Select]
void setup ()
...
...
attachInterrupt(0, sample_freq, RISING);
.....



At this point, it makes sense and I've tried it on the breadboard to confirm it (using a function generator feeding as the  pitch-preview)

Next, after having enough number of samples it will start matching the MIDI note number:

Code: [Select]
void loop ()
 
  // We have captured enough samples, time to process...
  if (sample_counter == NO_OF_SAMPLES)
  {
    ProcessSamples();

    // Start sampling again
    sample_counter = 0;
  }
}


Code: [Select]
void sample_freq() // Interrupt handler function
{
  if (sample_counter == NO_OF_SAMPLES) //NO_OF_SAMPLES = 5
    return;
   
  if ((sample_counter > 0) && (micros() < samples[sample_counter-1]))
  {
    sample_counter = 0; // Reset and
    return;             // do nothing if we have overflowed.
  }
 
  samples[sample_counter] = micros();
  sample_counter++;
}



Hobley's methods is what throws me off here...

When the function ProcessSample calls out, he takes those 5 samples and take the average of it (?) as shown here:

Code: [Select]
unsigned long ProcessSamples()
{
    accumulator =  (samples[1] - samples[0]);
    accumulator += (samples[2] - samples[1]);
    accumulator += (samples[3] - samples[2]);
    accumulator += (samples[4] - samples[3]);
   
    accumulator = accumulator / 4;

   
Then he compares (from what I'm assuming a huge array of period numbers, which I still dont know how he got those numbers) to correspond the right note:

Code: [Select]
   for (int i = 0; i <69; i++)
    {
      if (accumulator > lower_bound_period[i])
      {
.............................


where

Code: [Select]
uint16_t lower_bound_period[]  = {
/*22282,*/ 21052, 19869, 18748, 17696, 16706, 15768, 14880, 14046, 13259,
12515, 11814, 11152, 10525, 9931,  9374,  8849,  8351,  7882,  7442,
7024,  6631,  6260,  5908,  5577,  5264,  4968,  4689,  4426,  4177,
3943,  3722,  3513,  3316,  3130,  2955,  2789,  2632,  2485,  2346,
2214,  2090,  1972,  1862,  1757,  1658,  1565,  1478,  1395,  1317,
1244,  1174,  1107,  1045,  987,   932,   880,   830,   784,   740,
699,   659,   622,   588,   555,   524,   495,   467,   441,   421 
};


Can anyone help me understand what exactly is he doing here? Is there an actual name for this A/D method?

Magician

It looks like he is using Look Up Table (LUT) to get a note number from measured frequency.
Data is slightly off, compare to :http://en.wikipedia.org/wiki/Piano_key_frequencies
Other-way, he would have to get 12-th root, which is quite slow on arduino.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy