Hey folks,
I am currently struggling with my code and specifically how to add a sort of delay to it. What I have been trying to do is stop the arduino from sending notes out that are shorter than around 20-30ms, I tried to add an interval that would count the time between the note being played and when the note turned off and then saying if the note length/interval was less than 50ms it wouldn't send to MIDI. I don't know if something like this is possible but it wasn't working so any help would be greatly appreciated.
#include <Filters.h>
//clipping indicator variables
boolean clipping = 0;
//data storage variables
byte newData = 0;
byte prevData = 0;
unsigned int time = 0; //keeps time and sends vales to store in timer[] occasionally
int timer[10]; //sstorage for timing of events
int slope[10]; //storage fro slope of events
unsigned int totalTimer; //used to calculate period
unsigned int period; //storage for period of wave
byte index = 0; //current storage index
float frequency; //storage for frequency calculations
int maxSlope = 0; //used to calculate max slope as trigger point
int newSlope; //storage for incoming slope data
//variables for decided whether you have a match
byte noMatch = 0; //counts how many non-matches you've received to reset variables if it's been too long
byte slopeTol = 3; //slope tolerance- adjust this if you need (original value =3)
int timerTol = 10; //timer tolerance- adjust this if you need (original value =10)
//for MIDI instructions
constexpr int noteON = 144; //144 = 10010000 in binary, note on command
constexpr int noteOFF = 128; //128 = 10000000 in binary, note off command
int velocity = 100;
//Full spectrum of notes
unsigned int MIDI_FREQUENCY[]{
// C C-sharp D D-sharp E F F-sharp G G-sharp A A-sharp B
8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 15, // Octave -1
16, 17, 18, 19, 21, 22, 23, 25, 26, 28, 29, 31, // Octave 0
33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, // Octave 1
65, 69, 73, 78, 82, 87, 93, 98, 104, 110, 117, 123, // Octave 2
131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, // Octave 3
262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, // Octave 4
523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, // Octave 5
1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, // Octave 6
2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, // Octave 7
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902, // Octave 8
8372, 8870, 9397, 9956, 10548, 11175, 11840, 12544 // Octave 9 (partial)
};
const uint8_t MIDI_NOTE_C0 = 52;
const uint8_t MIDI_NOTE_C9 = 81;
static byte LastNote = 0;
//DSP filter code
float lowFrequency = 165; // test signal frequency (Hz)
float highFrequency = 880;
float testAmplitude = 100; // test signal amplitude
float testOffset = 100;
float windowLength = 20.0 / lowFrequency; // how long to average the signal, for statistist
float testSignalSigma = testAmplitude / sqrt(2.0); // the RMS amplitude of the test signal
float testSignal3dbSigma = testSignalSigma / sqrt(2.0); // the RMS amplitude of the test signal, down -3db
float printPeriod = 5.0;
// return the current time
float filtertime() {
return float(micros()) * 1e-6;
}
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT); //led indicator pin
pinMode(12, OUTPUT); //output pin
cli(); //diable interrupts
//set up continuous sampling of analog pin 0 at 38.5kHz
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX |= (1 << REFS0); //set reference voltage
ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
ADCSRA |= (1 << ADATE); //enabble auto trigger
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADSC); //start ADC measurements
sei(); //enable interrupts
}
ISR(ADC_vect) { //when new ADC value ready
PORTB &= B11101111; //set pin 12 low
prevData = newData; //store previous value
newData = ADCH; //get value from A0
if (prevData < 127 && newData >= 127) { //if increasing and crossing midpoint
newSlope = newData - prevData; //calculate slope
if (abs(newSlope - maxSlope) < slopeTol) { //if slopes are ==
//record new data and reset time
slope[index] = newSlope;
timer[index] = time;
time = 0;
if (index == 0) { //new max slope just reset
PORTB |= B00010000; //set pin 12 high
noMatch = 0;
index++; //increment index
} else if (abs(timer[0] - timer[index]) < timerTol && abs(slope[0] - newSlope) < slopeTol) { //if timer duration and slopes match
//sum timer values
totalTimer = 0;
for (byte i = 0; i < index; i++) {
totalTimer += timer[i];
}
period = totalTimer; //set period
//reset new zero index values to compare with
timer[0] = timer[index];
slope[0] = slope[index];
index = 1; //set index to 1
PORTB |= B00010000; //set pin 12 high
noMatch = 0;
} else { //crossing midpoint but not match
index++; //increment index
if (index > 9) {
reset();
}
}
} else if (newSlope > maxSlope) { //if new slope is much larger than max slope
maxSlope = newSlope;
time = 0; //reset clock
noMatch = 0;
index = 0; //reset index
} else { //slope not steep enough
noMatch++; //increment no match counter
if (noMatch > 9) {
reset();
}
}
}
if (newData == 0x00 || newData == 0xFF) { //if clipping
PORTB |= B00100000; //set pin 13 high- turn on clipping indicator led
clipping = 1; //currently clipping
}
time++; //increment timer at rate of 38.5kHz
}
void reset() { //clea out some variables
index = 0; //reset index
noMatch = 0; //reset match couner
maxSlope = 0; //reset slope
}
void checkClipping() { //manage clipping indicator LED
if (clipping) { //if currently clipping
PORTB &= B11011111; //turn off clipping indicator led
clipping = 0;
}
}
void testOnePoleFilters() {
// filters are test with a sine wave input, keep track of those values here for a sanity check
RunningStatistics inputStats; // create statistics to look at the raw test signal
inputStats.setWindowSecs(windowLength);
FilterOnePole filterOneLowpass(LOWPASS, lowFrequency); // create a one pole (RC) lowpass filter
RunningStatistics filterOneLowpassStats; // create running statistics to smooth these values
filterOneLowpassStats.setWindowSecs(windowLength);
FilterOnePole filterOneHighpass(HIGHPASS, highFrequency); // create a one pole (RC) highpass filter
RunningStatistics filterOneHighpassStats; // create running statistics to smooth these values
filterOneHighpassStats.setWindowSecs(windowLength);
float startTime = filtertime();
float nextPrintTime = filtertime();
while (true) {
// update all real time classes
float inputValue = testAmplitude + testAmplitude * sin(TWO_PI * lowFrequency * filtertime());
// update the test value statistics
inputStats.input(inputValue);
// update the one pole lowpass filter, and statistics
filterOneLowpass.input(inputValue);
filterOneLowpassStats.input(filterOneLowpass.output());
// update the one pole highpass filter, and statistics
filterOneHighpass.input(inputValue);
filterOneHighpassStats.input(filterOneHighpass.output());
}
}
void loop() {
checkClipping();
frequency = 38462 / float(period); //calculate frequency timer rate/period
for (byte note = MIDI_NOTE_C0; note < MIDI_NOTE_C9; note++) {
if (frequency < (MIDI_FREQUENCY[note] + MIDI_FREQUENCY[note + 1]) / 2) {
// Matching note!
if (note != LastNote)
{
{
// The note has changed so turn off the previous note
MIDImessage(noteOFF, LastNote, velocity);
MIDImessage(noteON, note, velocity);
}
}
LastNote = note;
break; // No need to look for more matches.
}
}
}
//send MIDI message
void MIDImessage(byte command, byte MIDInote, byte MIDIvelocity) {
Serial.write(command); //send note on or note off command
Serial.write(MIDInote); //send pitch data
Serial.write(MIDIvelocity); //send velocity data
}