Hello friends,
I am attempting to create a code for teensy whereby in simple terms, takes an input fundamental frequency from an audio source and outputs the note to usb midi monophonically.
I have an issue where it correctly detects the fundamental, but if the same note is sustained in the microphone, the teensy outputs midi on and midi off messages for the same midi value rapidly.
My goal is to have the teensy send midi on and stay on as long as the input frequency is sustained. The teensy should only send a midi off for that note if the amplitude of the input falls below a particular threshold or there is a change in detected frequency.
Please see the below code for reference, and I appreciate any input that can be provided to simplify or alter the code to accomplish the goal.
Thanks
#include <Audio.h>
#include <MIDI.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Wire.h>
const int channel = 0;
const int myInput = AUDIO_INPUT_MIC;
AudioInputI2S audioInput;
AudioAnalyzeNoteFrequency notefreq1; // YIN algorithm object
AudioConnection patchCord1(audioInput, 0, notefreq1, 0);
AudioAnalyzeRMS rms1;
AudioConnection patchCord2(audioInput, 0, rms1, 0);
AudioControlSGTL5000 audioShield;
const int numNotes = 127; // Number of standard musical notes
float musicalNotes[numNotes];
int currentNote = -1;
bool noteSent = false;
void setup() {
AudioMemory(30);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.2);
notefreq1.begin(0.1); // Initialize the YIN algorithm with a threshold
Serial.begin(9600);
calculateMusicalNotes();
}
void loop() {
float micInputLevel = rms1.read();
if (micInputLevel > 0.05) {
// Determine MIDI velocity based on the RMS value
int midiVelocity = int(map(micInputLevel, 0.0, 1.0, 0, 127));
if (notefreq1.available()) {
// Check the microphone input level (RMS value)
float Frequency = notefreq1.read();
int closestNoteIndex = findClosestNoteIndex(Frequency);
int newMidiNote = hzToMidiNote(musicalNotes[closestNoteIndex]);
if (newMidiNote != currentNote && noteSent) {
sendMIDINoteOff(currentNote);
noteSent = false;
// Go back to the beginning of the loop
return;
}
else if (noteSent) {
return; // Go back to the beginning of the loop
}
sendMIDINoteOn(newMidiNote, midiVelocity);
currentNote = newMidiNote;
noteSent = true;
}
}
else {
if (currentNote != -1) {
// Mic input threshold not met, send MIDI note off and reset
sendMIDINoteOff(currentNote);
currentNote = -1;
noteSent = false;
}
}
}
int findClosestNoteIndex(float detectedFrequency) {
int closestNoteIndex = 0;
float minDistance = abs(detectedFrequency - musicalNotes[0]);
for (int i = 1; i < numNotes; i++) {
float distance = abs(detectedFrequency - musicalNotes);
if (distance < minDistance) {
minDistance = distance;
closestNoteIndex = i;
}
}
return closestNoteIndex;
}
void calculateMusicalNotes() {
float ratio = pow(2.0, 1.0 / 12.0); // 12th root of 2
float currentFrequency = 116.54; // Adjust this to match your range
for (int i = 0; i < numNotes; i++) {
musicalNotes = currentFrequency;
currentFrequency *= ratio;
}
}
int hzToMidiNote(float frequency) {
if (frequency <= 0.0) {
return 0; // Return 0 for an invalid frequency
}
float note = 12.0 * log2(frequency / 440.0) + 69.0;
return int(note + 0.5);
}
void sendMIDINoteOn(int note, int velocity) {
if (note >= 0 && note <= 127) {
usbMIDI.sendNoteOn(note, velocity, channel);
}
}
void sendMIDINoteOff(int note) {
if (note >= 0 && note <= 127) {
usbMIDI.sendNoteOff(note, 0, channel);
}
}
I am attempting to create a code for teensy whereby in simple terms, takes an input fundamental frequency from an audio source and outputs the note to usb midi monophonically.
I have an issue where it correctly detects the fundamental, but if the same note is sustained in the microphone, the teensy outputs midi on and midi off messages for the same midi value rapidly.
My goal is to have the teensy send midi on and stay on as long as the input frequency is sustained. The teensy should only send a midi off for that note if the amplitude of the input falls below a particular threshold or there is a change in detected frequency.
Please see the below code for reference, and I appreciate any input that can be provided to simplify or alter the code to accomplish the goal.
Thanks
#include <Audio.h>
#include <MIDI.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Wire.h>
const int channel = 0;
const int myInput = AUDIO_INPUT_MIC;
AudioInputI2S audioInput;
AudioAnalyzeNoteFrequency notefreq1; // YIN algorithm object
AudioConnection patchCord1(audioInput, 0, notefreq1, 0);
AudioAnalyzeRMS rms1;
AudioConnection patchCord2(audioInput, 0, rms1, 0);
AudioControlSGTL5000 audioShield;
const int numNotes = 127; // Number of standard musical notes
float musicalNotes[numNotes];
int currentNote = -1;
bool noteSent = false;
void setup() {
AudioMemory(30);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.2);
notefreq1.begin(0.1); // Initialize the YIN algorithm with a threshold
Serial.begin(9600);
calculateMusicalNotes();
}
void loop() {
float micInputLevel = rms1.read();
if (micInputLevel > 0.05) {
// Determine MIDI velocity based on the RMS value
int midiVelocity = int(map(micInputLevel, 0.0, 1.0, 0, 127));
if (notefreq1.available()) {
// Check the microphone input level (RMS value)
float Frequency = notefreq1.read();
int closestNoteIndex = findClosestNoteIndex(Frequency);
int newMidiNote = hzToMidiNote(musicalNotes[closestNoteIndex]);
if (newMidiNote != currentNote && noteSent) {
sendMIDINoteOff(currentNote);
noteSent = false;
// Go back to the beginning of the loop
return;
}
else if (noteSent) {
return; // Go back to the beginning of the loop
}
sendMIDINoteOn(newMidiNote, midiVelocity);
currentNote = newMidiNote;
noteSent = true;
}
}
else {
if (currentNote != -1) {
// Mic input threshold not met, send MIDI note off and reset
sendMIDINoteOff(currentNote);
currentNote = -1;
noteSent = false;
}
}
}
int findClosestNoteIndex(float detectedFrequency) {
int closestNoteIndex = 0;
float minDistance = abs(detectedFrequency - musicalNotes[0]);
for (int i = 1; i < numNotes; i++) {
float distance = abs(detectedFrequency - musicalNotes);
if (distance < minDistance) {
minDistance = distance;
closestNoteIndex = i;
}
}
return closestNoteIndex;
}
void calculateMusicalNotes() {
float ratio = pow(2.0, 1.0 / 12.0); // 12th root of 2
float currentFrequency = 116.54; // Adjust this to match your range
for (int i = 0; i < numNotes; i++) {
musicalNotes = currentFrequency;
currentFrequency *= ratio;
}
}
int hzToMidiNote(float frequency) {
if (frequency <= 0.0) {
return 0; // Return 0 for an invalid frequency
}
float note = 12.0 * log2(frequency / 440.0) + 69.0;
return int(note + 0.5);
}
void sendMIDINoteOn(int note, int velocity) {
if (note >= 0 && note <= 127) {
usbMIDI.sendNoteOn(note, velocity, channel);
}
}
void sendMIDINoteOff(int note) {
if (note >= 0 && note <= 127) {
usbMIDI.sendNoteOff(note, 0, channel);
}
}