Single midi note until change

Hello,

I’m fairly new to writing code and I’ve run into a problem to which I can’t find the answer.
For a interactive sound installation I want to play a single midi note when a person comes close to the installation and play a different note when the person is gone for more than 3 seconds. I use a sharp ir sensor on analog pin 0 to measure the distance of the listener and hairless to convert serial to midi. Ableton plays the samples.
The code I have found/edited works, but sends continuous midi notes, restarting the samples all the time. I am looking for a way to tell the arduino to play one note if the sensor data is higher than 400 and wait until the data is lower than 400 for more than 3 seconds and then play the other note etc. The code I have now is the following:

 int velocity = 100;//velocity of MIDI notes, must be between 0 and 127
 //higher velocity usually makes MIDI instruments louder
 
 int noteON = 144;//144 = 10010000 in binary, note on command
 int noteOFF = 128;//128 = 10000000 in binary, note off command

int sensorPinL = 0;  // IR SensL - A0
 
int irValL = 0;

int zValL = 0;

int irStateL = 0;      //current state
int lastIrStateL = 0;  //previous state
 
int lowThresh = 115;
int highThresh = 635;

void setup() {
  //  Set MIDI baud rate:
  Serial.begin(115200);
}

void loop() {
  zValL = irValL;
 
  irValL = analogRead(sensorPinL);

if(irValL > 400) {
  irStateL = 1;
  }
  else { 
   irStateL = 0;
}
    if (irStateL == 1) {
    MIDImessage(noteON, 50, velocity);//turn note on
  }
    if (irStateL == 0) {
    MIDImessage(noteON, 51, velocity);//turn note on
}
    
    if (irStateL - lastIrStateL > 0) {
  delay (3000);
}

irStateL = lastIrStateL;
  
}

//send MIDI message
void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}
int toMIDIRange(int x)
{
  if (x < lowThresh)
    return 0;
     
  if (x > highThresh)
    return 127;
     
  else
    return x/5;
}

I hope someone here can give me a tip where I can find an example or tutorial that can teach me how to solve this.

Jurjen

It looks like you are already almost there :wink:

You need a to write a “finite state machine”

Then determine what states you system has e.g.

  1. Wait for person to approach
  2. Person within range
  3. Person leaves range, Now delaying for 3 secs

I may have missed a state here, but hopefully you will get the idea

Use a global variable e.g.

int state=1;

to hold you state,

Then in loop() use a switch statement to execute the statements for each state

e.g. something like this

switch(state)
{
case 1:
if (dist<400)
{
state=2;
// Play a note
} 
break;

case 2:
if (dist>400)
{
state=3;
// keep playing a note??
}
break;

case 3:
delay(3000);
state=4
break;

case 4:
// play another notes??
break;


}

It looks like you are already almost there ;-)

Not to me.

OP: You need to send the MIDI message only when there has been a change. Instead, you are sending a message every time.

Copying a previous value, on every pass through loop (as you are doing) is essential to that process. But, then you have to decide if the new value is the same as the old value, and send a message only if the old and new values are different.

I found a way to make it work. Thanks for the tips. I have to change the 3 second delay for a solution which doesn’t stop the arduino from listening, but for the rest it’s ok now.

 int velocity = 100;//velocity of MIDI notes, must be between 0 and 127
 //higher velocity usually makes MIDI instruments louder
 
 int noteON = 144;//144 = 10010000 in binary, note on command
 int noteOFF = 128;//128 = 10000000 in binary, note off command

int sensorPinL = 0;  // IR SensL - A0
 
int irValL = 0;

int zValL = 0;

int irStateL = 0;      //current state
int lastIrStateL = 1;  //previous state
 
int lowThresh = 115;
int highThresh = 635;

void setup() {
  //  Set MIDI baud rate:
  Serial.begin(115200);
}

void loop() {
  zValL = irValL;
 
  irValL = analogRead(sensorPinL);

if(irValL > 400) {
  irStateL = 0;
  }
if(irValL <= 400) {
  irStateL = 1;
  }
if(irValL <= 400 && irStateL != lastIrStateL) {
   delay(3000);
   irValL = analogRead(sensorPinL);
   if(irValL > 400) {
     irStateL = 0;
   }
   if(irValL <= 400) {
     irStateL = 1;
   }
 }

if(irValL > 400 && irStateL != lastIrStateL) {
  irStateL = 0;
  MIDImessage(noteON, 50, velocity);//turn note on
 }
if(irValL <= 400 && irStateL != lastIrStateL) {
  irStateL = 1;
  MIDImessage(noteON, 51, velocity);//turn note on
 }
  
lastIrStateL = irStateL;

}

//send MIDI message
void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}
int toMIDIRange(int x)
{
  if (x < lowThresh)
    return 0;
     
  if (x > highThresh)
    return 127;
     
  else
    return x/5;
}