Analog To Midi with MKR 1000
Build a device that recognizes an input frequency and outputs it to MIDI as the nearest corresponding note of the chromatic scale.
With this tutorial you use the Audio Frequency Meter Library and the Arduino Midi USB library and build a device that recognizes an input frequency and outputs it to MIDI as the nearest corresponding note of the chromatic scale.
Hardware Required
Arduino MKR1000 Board
1x 10k trimmer
2x 100k resistor
2x 47k resistor
1x 100n capacitor
1x 3.5mm jack
The Circuit
  
    
    
In order to get the most dynamic range even from low level inputs, the circuit consist of a non-inverting amplifier that brings the amplitude of the signal to the full input voltage range supported by the ADC. Sampling at full resolution means a better accuracy.
The 10k trimpot allows to adjust the gain of the amplifier matching the signal level with the ADC input range. This adjustment should be made looking at the output on the Arduino Software (IDE) Serial Monitor: when the note reading is stable while playing the same note, the gain is properly set.
As an alternative, you may purchase the Electret microphone amplifier - MAX4466 with adjustable gain that was designed specifically for this purpose.
Works on: MKR1000 and Zero boards.
Schematic
  
    
    
Software Essentials
Includes:
<AudioFrequencyMeter.h>
Library that contains the methods and functions to manage analog frequencies read through the analog inputs. In this sketch it recognizes the main frequency to play through MIDI.<MIDIUSB.h>
Library that creates a MIDI device through USB Host port; the device outputs notes in MIDI format and needs a sound generator.<frequencyToNote.h>
Defines the correspondence between audio frequencies and notes of the 88 keys scale. Part of MIDIUSB<pitchToNote.h>
Defines the correspondence between notes and MIDI note values. Part of MIDIUSBFunctions In Sketch
searchForNote(float frequency) Search for the nearest frequency that is in the vector of frequencies noteFrequency[ ]
noteOn(byte channel, byte pitch, byte velocity) Sends out to MIDI the event to turn on the note of the specified pitch on the specified MIDI Channel
void noteOff(byte channel, byte pitch, byte velocity) Sends out to MIDI the event to turn off the note of the specified pitch on the specified MIDI Channel
Code
1/*2
3  Analog to Midi Converter for Arduino MKR10004
5  Demonstrates how to sample an input signal and get back its corresponding MIDI note6
7  This example code is in the public domain8
9  https://www.arduino.cc/en/Tutorial/AnalogToMidi10
11  created by Arturo Guadalupi <a.guadalupi@arduino.cc>12
13  29 Jan 201614
15*/16
17#include <AudioFrequencyMeter.h>18#include <MIDIUSB.h>19#include <frequencyToNote.h>20#include <pitchToNote.h>21
22#define DEPTH         60                      // Defines depth of the array for averaged frequencies23#define HUMAN_RATE    50                      // Defines 50ms corresponding to 20 notes/s24#define MAX_DURATION  1000                    // Defines the max play duration of the note25
26AudioFrequencyMeter meter;27
28int notesArray[DEPTH];                        // Array to store detected notes and find the "correct" note which occurred the most often29int occurrences[DEPTH];                       // Array in which the number of occurrences for each note are stored30
31bool marked[DEPTH];                           // Array to indicate which of the notes have been checked32int frequencyIndex = 0;                       // Used to navigate to where the current note must be stored33
34int previousNote;35unsigned int startTime;                       // Used to determine when the note must stop36unsigned int humanTime;                       // Used to determine when the next note can be sampled (using HUMAN_RATE timing)37
38int intensity = 64;                           // The volume of the played note is fixed at 6439
40void setup() {41
42  // put your setup code here, to run once:43
44  Serial.begin(115200);45
46  pinMode(11, OUTPUT);47
48  meter.setBandwidth(75.00, 600.00);          // Set available bandwidth between 75Hz and 600Hz49
50  meter.begin(A0, 45000);                     // Initialize A0 at sample rate of 45kHz51}52
53void loop() {54
55  float frequency = meter.getFrequency();56
57  if (frequency > 0)58
59  {60
61    int noteIndex = searchForNote(frequency); // Find the index of the corresponding frequency62
63    int note = notePitch[noteIndex];          // Use that index to find the corresponding note in the LUT64
65    notesArray[frequencyIndex++] = note;      // Store the note and continue to next value in array66
67    if (frequencyIndex > DEPTH)               // If all the notes have been stored68
69    {70
71      frequencyIndex = 0;                     // Reset the index72
73      int i, j;74
75      /*Reset all the occurrences and marked positions*/76
77      for (i = 0; i < DEPTH; i++)78
79      {80
81        occurrences[i] = 0;82
83        marked[i] = 0;84
85      }86
87      /*Count the number of occurrences*/88
89      for (i = 0; i < DEPTH; i++)90
91      {92
93        for (j = 0; j < DEPTH; j++)94
95        {96
97          // If notes are the same and the note has not been marked yet98
99          if ((!marked[j]) && (notesArray[j] == notesArray[i]))100
101          {102
103            occurrences[i]++;                 // Increment the number of occurrences104
105            marked[j] = true;                 // Signal the note as marked106
107          }108
109        }110
111      }112
113      int numberOfdifferentFrequencies = 0;   // Used to determine how many different Frequencies have been detected114
115      for (i = 0; i < DEPTH; i++)116
117      {118
119        // If the counter does not equal zero120
121        if (occurrences[i] != 0)122
123        {124
125          // Store the the various detected Frequencies126
127          notesArray[numberOfdifferentFrequencies] = notesArray[i];128
129          // And the number of occurrences for each note130
131          occurrences[numberOfdifferentFrequencies] = occurrences[i];132
133          numberOfdifferentFrequencies++;      // Increment the number of detected Frequencies134
135        }136
137      }138
139      /*Search for the maximum number of occurrences to discriminate the played note*/140
141      int maxNumberOfFrequencies = occurrences[0];142
143      int rightIndex = 0;144
145      for (i = 0; i < numberOfdifferentFrequencies; i++);146
147      {148
149        // If a new maximum exist150
151        if (occurrences[i] > maxNumberOfFrequencies)152
153        {154
155          // Update the value156
157          maxNumberOfFrequencies = occurrences[i];158
159          // Update the index160
161          rightIndex = i;162
163        }164
165      }166
167      note = notesArray[rightIndex];          // Note to be played is that with the most occurrences168
169      // If the specified time has elapsed before the next note170
171      if (millis() - humanTime > HUMAN_RATE)172
173      {174
175        humanTime = millis();                 // Update the timer176
177        startTime = millis();                 // Update the note duration178
179        noteOff(0, previousNote, intensity);  // Stop playing the previous note180
181        previousNote = note;                  // Update previous note with the new one182
183        Serial.println(note);                 // Print the note to be played184
185        noteOn(0, note, intensity);           // Play the note!186
187      }188
189    }190
191  }192
193  if (millis() - startTime > MAX_DURATION)    // If maximum time elapsed194
195    noteOff(0, previousNote, intensity);      // Turn the note off196}197
198int searchForNote(float frequency)199{200
201  float minimum = abs(frequency - noteFrequency[0]);202
203  float newMinimum;204
205  int index = 0;206
207  /*Search for the nearest frequency that is in the vector*/208
209  for (int i = 0; i < NUMBER_OF_NOTES - 1; i++)210
211  {212
213    newMinimum = abs(frequency - noteFrequency[i]);214
215    if (newMinimum < minimum)216
217    {218
219      minimum = newMinimum;220
221      index = i;222
223    }224
225  }226
227  return index;228}229
230void noteOn(byte channel, byte pitch, byte velocity) {231
232  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};233
234  MidiUSB.sendMIDI(noteOn);235}236
237void noteOff(byte channel, byte pitch, byte velocity) {238
239  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};240
241  MidiUSB.sendMIDI(noteOff);242}Suggested changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. You can read more on how to contribute in the contribution policy.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.