2 function button midi sending

Hi,

looking for help in the following sketch. spent nearly a full day trying to figure out how to send midi commands with a 2 function switch. i have it sending a midi message on one click then another independent midi message on a double click, it turn on the effect with the two midi messages but wont turn the effect off. The leds are working of booleans so i was wondering to turn off the effect by sending a midi message would you need to use a boolean to do this as well.
intrested in seeing how this works. have tryed puting sendControlChange(90, 0);where the button is LoW.

any help would be greatfull

/* 4-Way Button:  Click, Double-Click, Press+Hold, and Press+Long-Hold Test Sketch

By Jeff Saltzman
Oct. 13, 2009

To keep a physical interface as simple as possible, this sketch demonstrates generating four output events from a single push-button.
1) Click:  rapid press and release
2) Double-Click:  two clicks in quick succession
3) Press and Hold:  holding the button down
4) Long Press and Hold:  holding the button for a long time
*/

#define buttonPin 5        // analog input pin to use as a digital input
#define ledPin1 3          // digital output pin for LED 1
#define ledPin2 13          // digital output pin for LED 2
#define ledPin3 0          // digital output pin for LED 3
#define ledPin4 13          // digital output pin for LED 4

// LED variables
boolean ledVal1 = false;    // state of LED 1
boolean ledVal2 = false;    // state of LED 2
boolean ledVal3 = false;    // state of LED 3
boolean ledVal4 = false;    // state of LED 4

//=================================================

void setup() {
   // Set button input pin
   pinMode(buttonPin, INPUT);
   digitalWrite(buttonPin, HIGH );
   // Set LED output pins
   pinMode(ledPin1, OUTPUT);
   digitalWrite(ledPin1, ledVal1);
   pinMode(ledPin2, OUTPUT);
   digitalWrite(ledPin2, ledVal2);
   pinMode(ledPin3, OUTPUT);   
   digitalWrite(ledPin3, ledVal3);
   pinMode(ledPin4, OUTPUT);   
   digitalWrite(ledPin4, ledVal4);
   sendControlChange(82, 0);
   sendControlChange(89, 0);
   Serial.begin(31250);
}

void loop() {
   // Get button event and act accordingly
   int b = checkButton();
   if (b == 1) clickEvent();
   if (b == 2) doubleClickEvent();
   if (b == 3) holdEvent();
   if (b == 4) longHoldEvent();
}

//=================================================
// Events to trigger

void clickEvent() {
   ledVal1 = !ledVal1;
   digitalWrite(ledPin1, ledVal1);
   sendControlChange(90, 127);
   Serial.println("buton");
}
void doubleClickEvent() {
   ledVal2 = !ledVal2;
   digitalWrite(ledPin2, ledVal2);
   sendControlChange(82, 127);
}
void holdEvent() {
   ledVal3 = !ledVal3;
   digitalWrite(ledPin3, ledVal3);
}
void longHoldEvent() {
   ledVal4 = !ledVal4;
   digitalWrite(ledPin4, ledVal4);
}
//=================================================
//  MULTI-CLICK:  One Button, Multiple Events

// Button timing variables
int debounce = 20;          // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250;            // max ms between clicks for a double click event
int holdTime = 1000;        // ms hold period: how long to wait for press+hold event
int longHoldTime = 3000;    // ms long hold period: how long to wait for press+hold event

// Button variables
boolean buttonVal = HIGH;   // value read from button
boolean buttonLast = HIGH;  // buffered value of the button's previous state
boolean DCwaiting = false;  // whether we're waiting for a double click (down)
boolean DConUp = false;     // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true;    // whether it's OK to do a single click
long downTime = -1;         // time the button was pressed down
long upTime = -1;           // time the button was released
boolean ignoreUp = false;   // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false;        // when held, whether to wait for the up event
boolean holdEventPast = false;    // whether or not the hold event happened already
boolean longHoldEventPast = false;// whether or not the long hold event happened already

int checkButton() {   
   int event = 0;
   buttonVal = digitalRead(buttonPin);
   // Button pressed down
   if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce)
  
   {
   
 // i have tryed putting    sendControlChange(82, 0);
  // sendControlChange(90, 0);

       downTime = millis();
       ignoreUp = false;
       waitForUp = false;
       singleOK = true;
       holdEventPast = false;
       
       
       longHoldEventPast = false;
       if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true)  DConUp = true;
       else  DConUp = false;
       DCwaiting = false;
   
   }
   // Button released
   else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce)
 
   {       
       if (not ignoreUp)
       Serial.println("butoff");
       {
           upTime = millis();
           if (DConUp == false) DCwaiting = true;
           else
           {
               event = 2;
               DConUp = false;
               DCwaiting = false;
               singleOK = false;
               
           }
       }
   }
   // Test for normal click event: DCgap expired
   if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
   {
       event = 1;
       DCwaiting = false;
   }
   // Test for hold
   if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
       // Trigger "normal" hold
       if (not holdEventPast)
       {
           event = 3;
           waitForUp = true;
           ignoreUp = true;
           DConUp = false;
           DCwaiting = false;
           //downTime = millis();
           holdEventPast = true;
       }
       // Trigger "long" hold
       if ((millis() - downTime) >= longHoldTime)
       {
           if (not longHoldEventPast)
           {
               event = 4;
               longHoldEventPast = true;
           }
       }
   }
   buttonLast = buttonVal;
   return event;
}
void sendControlChange(byte Ctrl, byte Value){
  Serial.write(0xB0); 
  Serial.write(Ctrl);
  Serial.write(Value);
}
digitalWrite(ledPin4, ledVal4);

use HIGH or LOW, not a boolean, as per the function definition, like this

digitalWrite(ledPin4, ledVal4 ? HIGH : LOW);

and see if that makes a difference

Thanks for the reply Marco
but that didn't work.

From your setup function:-

   sendControlChange(82, 0);
   sendControlChange(89, 0);
   Serial.begin(31250);

You are sending two controlChange messages before you have set the baud rate.

Thanks Mike,

I removed the CC messages from the void set up and tried putting them where the button is low, the effect comes on but wont go off till the double click is selected.

and tried putting them where the button is low

Where is this then?
When you make changes you should repost the code.

What do you expect to happen?
It seems to me that you only ever send 127 to CC 90 on a single click. Do you want it to toggle? If so you need to remember the last value you sent to it and send the inverse on the next click.

Hi Mike

What do you expect to happen?

I am trying to send 127 to CC 90 to toggle on and off ( CC 90 0) on a normal click
and 127 to CC 82 toggle on and off ( 0 to CC 82)on a double click.

I am only sending out 127 to CC 90 on a single click and 127 to CC 82 on a double click
and i cant work out how to send 0 to CC 90 and 0 to CC 82.

/* 4-Way Button:  Click, Double-Click, Press+Hold, and Press+Long-Hold Test Sketch

By Jeff Saltzman
Oct. 13, 2009

To keep a physical interface as simple as possible, this sketch demonstrates generating four output events from a single push-button.
1) Click:  rapid press and release
2) Double-Click:  two clicks in quick succession
3) Press and Hold:  holding the button down
4) Long Press and Hold:  holding the button for a long time
*/

#define buttonPin 5        // analog input pin to use as a digital input
#define ledPin1 3          // digital output pin for LED 1
#define ledPin2 13          // digital output pin for LED 2
#define ledPin3 0          // digital output pin for LED 3
#define ledPin4 13          // digital output pin for LED 4

// LED variables
boolean ledVal1 = false;    // state of LED 1
boolean ledVal2 = false;    // state of LED 2
boolean ledVal3 = false;    // state of LED 3
boolean ledVal4 = false;    // state of LED 4

//=================================================

void setup() {
   // Set button input pin
   pinMode(buttonPin, INPUT);
   digitalWrite(buttonPin, HIGH );
   // Set LED output pins
   pinMode(ledPin1, OUTPUT);
   digitalWrite(ledPin1, ledVal1);
   pinMode(ledPin2, OUTPUT);
   digitalWrite(ledPin2, ledVal2);
   pinMode(ledPin3, OUTPUT);   
   digitalWrite(ledPin3, ledVal3);
   pinMode(ledPin4, OUTPUT);   
   digitalWrite(ledPin4, ledVal4);
   
   Serial.begin(31250);
}

void loop() {
   // Get button event and act accordingly
   int b = checkButton();
   if (b == 1) clickEvent();
   if (b == 2) doubleClickEvent();
   if (b == 3) holdEvent();
   if (b == 4) longHoldEvent();
}

//=================================================
// Events to trigger

void clickEvent() {
   ledVal1 = !ledVal1;
   digitalWrite(ledPin1, ledVal1);
   sendControlChange(90, 127);
   Serial.println("buton");
   
}
void doubleClickEvent() {
   ledVal2 = !ledVal2;
   digitalWrite(ledPin2, ledVal2);
   sendControlChange(82, 127);
}
void holdEvent() {
   ledVal3 = !ledVal3;
   digitalWrite(ledPin3, ledVal3);
}
void longHoldEvent() {
   ledVal4 = !ledVal4;
   digitalWrite(ledPin4, ledVal4);
}
//=================================================
//  MULTI-CLICK:  One Button, Multiple Events

// Button timing variables
int debounce = 20;          // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250;            // max ms between clicks for a double click event
int holdTime = 1000;        // ms hold period: how long to wait for press+hold event
int longHoldTime = 3000;    // ms long hold period: how long to wait for press+hold event

// Button variables
boolean buttonVal = HIGH;   // value read from button
boolean buttonLast = HIGH;  // buffered value of the button's previous state
boolean DCwaiting = false;  // whether we're waiting for a double click (down)
boolean DConUp = false;     // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true;    // whether it's OK to do a single click
long downTime = -1;         // time the button was pressed down
long upTime = -1;           // time the button was released
boolean ignoreUp = false;   // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false;        // when held, whether to wait for the up event
boolean holdEventPast = false;    // whether or not the hold event happened already
boolean longHoldEventPast = false;// whether or not the long hold event happened already

int checkButton() {   
   int event = 0;
   buttonVal = digitalRead(buttonPin);
   // Button pressed down
   if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce)
 
   {
   
 // i have tryed putting    sendControlChange(82, 0);
  // sendControlChange(90, 0);

       downTime = millis();
       ignoreUp = false;
       waitForUp = false;
       singleOK = true;
       holdEventPast = false;
       
       
       longHoldEventPast = false;
       if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true)  DConUp = true;
       else  DConUp = false;
       DCwaiting = false;
   
   }
   // Button released
   else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce)
 
   {       
       if (not ignoreUp)
       Serial.println("butoff");
     
       {
           upTime = millis();
           if (DConUp == false) DCwaiting = true;
           else
           {
               event = 2;
               DConUp = false;
               DCwaiting = false;
               singleOK = false;
               
           }
       }
   }
   // Test for normal click event: DCgap expired
   if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
   {
       event = 1;
       DCwaiting = false;
   }
   // Test for hold
   if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
       // Trigger "normal" hold
       if (not holdEventPast)
       {
           event = 3;
           waitForUp = true;
           ignoreUp = true;
           DConUp = false;
           DCwaiting = false;
           //downTime = millis();
           holdEventPast = true;
       }
       // Trigger "long" hold
       if ((millis() - downTime) >= longHoldTime)
       {
           if (not longHoldEventPast)
           {
               event = 4;
               longHoldEventPast = true;
           }
       }
   }
   buttonLast = buttonVal;
   return event;
}
void sendControlChange(byte Ctrl, byte Value){
  Serial.write(0xB0);
  Serial.write(Ctrl);
  Serial.write(Value);
}

As Mike has said you need to remember the last value you sent so you can send the opposite. You already track on/off for the LEDs using the ledVal variables, so if ledVal turns true you send the on signal, when ledVal turns false you send the off signal.

Hi marco,

So am i right in saying the only place where the led variables are false are in the void set up.

No. They are false everywhere you set them false. This code

ledVal1 = !ledVal1;

set the value to ledVal to not the current value of ledVal. This inverts ledVal from true to false and false to true. That's how the LEDs go on and off, and the LEDs are supposed to show the message you have sent, right?

So you need to add the code

if(ledVall) {
// send cc message with 127
}
else {
// send cc message with 0
}

Cheers lads,

Thanks for that i did try putting an if and else statement in originally and for some reason it wouldn,t compile but after the help from you guys its all working.

Thanks Again

Greg

Hello Hi and another Happy New Year in the round …

I’m Robert from Germany and am a complete newcomer to Arduino & Co.

To be honest, I am also not a programmer and only became aware of Arduino because I am a guitarist and have seen that I can convert a foot controller with an Arduino.

THE FOLLOWING:

  • I have a housing with 12x foot switches
  • Each of these switches should send a simple Midi CC command to control the “BIAS FX” software
  • I watched some videos and tutorials and finally came across Merwin’s “MIDI_Guitar” project
  • I then ordered an Adafruit Bluefruit LE and wired everything as he did it.
  • I also installed the Sketsch and I managed to connect to my iPad via Bluetooth
  • JAAA, I even have a great MIDI keyboard on the floor now :slight_smile: :smiley:

Because then I found that BIAS FX didn’t want to send “notes”, but CC’s (ControlChanges)
I tried everything “me” possible but unfortunately my knowledge is far from sufficient.
I do not need a “bank” or “octave” switchover, just 12 fixed CC’s that are sent to the iPad via the 12 buttons …

for example like this:
Key 1 sends CC30 with a value of 127
Key 2 sends CC31 with a value of 127
etc etc

Please excuse me if a beginner should be able to do that, but I’m finished with my Latin and would be very grateful for a solution …

Best wishes

this is the code from merwin:

/*
Video for this project here:https://youtu.be/QPgYpVHFSQY

Thank you for checking out my video and my code!

For more videos and information check out
https://www.youtube.com/merwinmusic
http://www.lukemerwin.com/

*/

#include <Arduino.h>
#include <SPI.h>

#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VARIANT_ARDUINO_ZERO_)
  #include <SoftwareSerial.h>
#endif

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"
#include "Adafruit_BLEMIDI.h"

#include "BluefruitConfig.h"

#define FACTORYRESET_ENABLE         0
#define MINIMUM_FIRMWARE_VERSION    "0.7.0"


Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

Adafruit_BLEMIDI midi(ble);

bool isConnected = false;


// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

// callback
void connected(void)
{
  isConnected = true;

  Serial.println(F(" CONNECTED!"));
  delay(1000);

}

void disconnected(void)
{
  Serial.println("disconnected");
  isConnected = false;
}

void BleMidiRX(uint16_t timestamp, uint8_t status, uint8_t byte1, uint8_t byte2)
{
  Serial.print("[MIDI ");
  Serial.print(timestamp);
  Serial.print(" ] ");

  Serial.print(status, HEX); Serial.print(" ");
  Serial.print(byte1 , HEX); Serial.print(" ");
  Serial.print(byte2 , HEX); Serial.print(" ");

  Serial.println();
}

                                

const int ButtonPins[12] = {2, 3, 5, 6, 9, 10, 11, 12, 13, 18, 19, 20};

int LastButtonState[12] = {0};
int currentMillis = 0;
int LastButtonChangeTime[12] = {currentMillis};

int NoteNumber[12] = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};


int buttonPushCounter = 0;



void setup(void)
{
  
                                        
  
 

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit MIDI Example"));
  Serial.println(F("---------------------------------------"));

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ) {
      error(F("Couldn't factory reset"));
    }
  }

  //ble.sendCommandCheckOK(F("AT+uartflow=off"));
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  /* Set BLE callbacks */
  ble.setConnectCallback(connected);
  ble.setDisconnectCallback(disconnected);

  // Set MIDI RX callback
  midi.setRxCallback(BleMidiRX);

  Serial.println(F("Enable MIDI: "));
  if ( ! midi.begin(true) )
  {
    error(F("Could not enable MIDI"));
  }

  ble.verbose(false);
  Serial.print(F("Waiting for a connection..."));

for(int i=0; i < 15; i++)
  pinMode(ButtonPins[i],INPUT_PULLUP);

}

void loop() {
  //-------------------------------------------------------------------------------------//
  // interval for each scanning ~ 500ms (non blocking)
  ble.update(250);

  // bail if not connected
  if (! isConnected)
    return;

int octave = (buttonPushCounter * 12);

//-----------------------------------------------------------------------------------//
   {
  unsigned long currentMillis = millis();
  for (int i=0; i<15; i++) {
    boolean state = !digitalRead(ButtonPins[13]);  // 'true'==pressed, 'false'==released
    // Check for state change and do debounce
    if (state != LastButtonState[13] && currentMillis-LastButtonChangeTime[13] > 50) {
      LastButtonState[13] = state;
      LastButtonChangeTime[13] = currentMillis;
      if (state){
        buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
      }
    }
  }
   }
//-----------------------------------------------------------------------------------//
   {
  unsigned long currentMillis = millis();
  for (int i=0; i<15; i++) {
    boolean state = !digitalRead(ButtonPins[14]);  // 'true'==pressed, 'false'==released
    // Check for state change and do debounce
    if (state != LastButtonState[14] && currentMillis-LastButtonChangeTime[14] > 50) {
      LastButtonState[14] = state;
      LastButtonChangeTime[14] = currentMillis;
      if (state){
        buttonPushCounter--;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
      }
    }
  }
   }
{
  if (buttonPushCounter < -1){
    buttonPushCounter = -1;
  }
  if (buttonPushCounter > 6){
    buttonPushCounter = 6;
  }
}
  
//-----------------------------------------------------------------------------------//
   {
  unsigned long currentMillis = millis();
  for (int i=0; i<13; i++) {
    boolean state = !digitalRead(ButtonPins[i]);  // 'true'==pressed, 'false'==released
    // Check for state change and do debounce
    if (state != LastButtonState[i] && currentMillis-LastButtonChangeTime[i] > 50) {
      LastButtonState[i] = state;
      LastButtonChangeTime[i] = currentMillis;
      if (state)
        midi.send(0x90, octave + NoteNumber[i], 0x64);  // Pressed
      else
        midi.send(0x80, octave + NoteNumber[i], 0x64);  // Released
      }
    }
  }
//-----------------------------------------------------------------------------------//

}