Hi,
I would like to send a MIDI note with a simple button;
then if hold on the button for more than 1000ms, a different MIDI note would be sent.
I am trying to use the library Bounce2 with the Control Surface library, without success.
See my tentative sketch:
#include <Control_Surface.h>
#include <Bounce2.h>
USBMIDI_Interface midi;
using namespace MIDI_Notes;
// WE WILL attach() THE Bounce INSTANCE TO THE FOLLOWING PIN IN setup()
#define BOUNCE_PIN 2
Bounce bounce = Bounce();
//BUTTON
NoteButton button1 = {
2,
{note(Ab, -1), CHANNEL_1}, // Note on MIDI channel
};
void setup() {
// BOUNCE SETUP
bounce.attach( BOUNCE_PIN , INPUT_PULLUP ); // USE INTERNAL PULL-UP
bounce.interval(5); //DEBOUNCE INTERVAL IN MILLISECONDS
const MIDIAddress note1 = MIDI_Notes::Ab[-1];
const MIDIAddress note2 = MIDI_Notes::A[-1];
RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE);
Control_Surface.begin();
}
void loop() {
Control_Surface.loop();
// Update the Bounce instance (YOU MUST DO THIS EVERY LOOP)
bounce.update();
// GET THE STATE WITH <Bounce.read()>
int debouncedState = bounce.read();
// <Bounce>.duration() RETURNS THE TIME IN MILLISECONDS THE CURRENT STATE HAS BEEN HELD.
// SO WE CHECK IF THE STATE IS LOW AND IF IT HAS BEEN LOW FOR MORE THAN 1 SECOND.
if ( debouncedState == LOW && bounce.currentDuration() > 1000 ) {
digitalWrite(note1, velocityHIGH);
} else {
digitalWrite(note2, velocityHIGH);
}
}
This cannot work, a MIDI address is not a digital pin, you cannot "digitalWrite" to it.
The purpose of the NoteButton class is to read the state of a switch connected to a digital pin. If that's not what you want it to do, or if you want to read the switch yourself, you cannot use NoteButton. Instead, have a look at Control Surface: Custom-MIDI-Output-Element.ino and Control Surface: MIDI Tutorial.
Thanks @PieterP, I didn't know that Control Surface supports detecting short/long presses. That's great!
I tried in vain to make the following sketch working:
#include <Control_Surface.h>
#include <Arduino_Helpers.h> // https://github.com/tttapa/Arduino-Helpers
#include <AH/Hardware/MultiPurposeButton.hpp>
// Create a Button object that reads a push button connected to pin 2:
MultiPurposeButton btn{2};
USBMIDI_Interface midi;
using namespace MIDI_Notes;
void setup() {
RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE);
Control_Surface.begin();
const MIDIAddress note0 = MIDI_Notes::A[1];
const MIDIAddress note1 = MIDI_Notes::Bb[1];
Serial.begin(115200);
btn.setLongPressDelay(1000);
btn.begin();
}
void loop() {
Control_Surface.loop();
auto longPressTime = btn.getLongPressedTime();
switch (btn.update()) {
case btn.None: break;
case btn.PressStart: midi.sendNoteOn(note0, velocityHIGH); break;
//case btn.ShortPressRelease:
// Serial << "Released after short press" << endl;
// break;
case btn.LongPress: midi.sendNoteOn(note1, velocityHIGH); break;
//case btn.LongPressRelease:
// Serial << "Released after long press (" << longPressTime << " ms)"
// << endl;
}
}
I thought to get rid of the parts where it writes through the serial, since I only need the "press" bit:
Button is pressed = send note0
Button stays pressed for 1000ms = send note1
Now, I don't know how to send a note rather than write to the serial like as explained here: https://tttapa.github.io/Control-Surface-doc/Doxygen/db/d45/3_8MultiPurposeButton_8ino-example.html
Could you help me?
Much appreciated
Thanks again for the hint @PieterP.
Following the info found on your last link (midi tutorial),
I've added to the sketch the velocity constant.
However I still get the same errors, namely note0, note1 and velocity not declared in this scope.
Below the code:
#include <Control_Surface.h>
#include <Arduino_Helpers.h> // https://github.com/tttapa/Arduino-Helpers
#include <AH/Hardware/MultiPurposeButton.hpp>
// Create a Button object that reads a push button connected to pin 2:
MultiPurposeButton btn{2};
USBMIDI_Interface midi;
using namespace MIDI_Notes;
void setup() {
RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE);
Control_Surface.begin();
const MIDIAddress note0 = MIDI_Notes::Bb[2];
const MIDIAddress note1 = MIDI_Notes::B[2];
const uint8_t velocity = 127;
Serial.begin(115200);
btn.setLongPressDelay(1000);
btn.begin();
}
void loop() {
Control_Surface.loop();
auto longPressTime = btn.getLongPressedTime();
switch (btn.update()) {
case btn.None: break;
case btn.PressStart: midi.sendNoteOn(note0, velocity); break;
case btn.LongPress: midi.sendNoteOn(note1, velocity); break;
}
}
This does not work. I'd recommend going through an introductory C++ tutorial to learn about variable scope. In short: if you declare a variable inside of a block { ... }, you cannot refer to it outside of the enclosing pair of braces.
Make these constants global or make them local to the loop function.
Hi again @PieterP and thanks for your help.
I declared the constant within the loop section and now it seems to work.
I noticed that, in order to have multiple shortpress/longpress buttons, I have to delete the auto keyword.
Would that work?
Forgive my profane approach to the programming world.
I'll definitely go through a C++ tutorial.
If you're just duplicating the code, then yes, you have to delete the auto keyword. In this context, auto declares a new variable, and you cannot have multiple variables with the same name in the same scope. If you remove the auto, you just assign a new value to an existing variable.
But the true solution here is not to duplicate any code, and use an array with some for loops instead.
Cool, thanks for answering @PieterP
Definitely going to check how arrays work.
Out of curiosity: having too many code duplicates inside the loop section, would it result in more microprocessor usage with consequent increase of power absorption and risk or errors?
Thank you!
The difference in power consumption will be negligible. However, the number of bugs in the code roughly correlates with the number of lines of source code, and duplicated/repetitive code is much harder to modify and maintain.