So I'm trying to make a music lock of sorts where the right sequence of keys on a keyboard unlocks a solenoid. It would be great if someone could point from where code wise I can start from.
I've used this to light up led13 when note 60 is on, How do I expand from that to a sequence?
byte commandByte;
byte noteByte;
byte velocityByte;
byte noteOn = 144;
//light up led at pin 13 when receiving noteON message with note = 60
void setup(){
Serial.begin(31250);
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
}
void checkMIDI(){
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
if (commandByte == noteOn){//if note on message
//check if note == 60 and velocity > 0
if (noteByte == 60 && velocityByte > 0){
digitalWrite(13,HIGH);//turn on led
}
}
}
}
while (Serial.available() > 2);//when at least three bytes available
}
void loop(){
checkMIDI();
delay(10);
digitalWrite(13,LOW);//turn led off
}
if (Serial.available()){
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
If there is one byte available, it is NOT OK to read all three of them.
A do/while loop is almost certainly the wrong statement to be using. It will perform the body of the statement at least once, and then check whether to do it again.
Use Google to look for examples where someone uses a keypad to enter a password. For example: Arduino Playground - KeypadPassword Then remove the keypad stuff and put in MIDI stuff.
I have a hard time making this, my knowledge is really limited but I gotta make it work fast.
Is this more suitable ?
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
// -----------------------------------------------------------------------------
// This function will be automatically called when a NoteOn is received.
// It must be a void-returning function with the correct parameters,
// see documentation here:
// http://arduinomidilib.fortyseveneffects.com/a00022.html
void handleNoteOn(byte channel, byte pitch, byte velocity)
{
// Do whatever you want when a note is pressed.
// Try to keep your callbacks short (no delays ect)
// otherwise it would slow down the loop() and have a bad impact
// on real-time performance.
}
void handleNoteOff(byte channel, byte pitch, byte velocity)
{
// Do something when the note is released.
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
}
// -----------------------------------------------------------------------------
void setup()
{
// Connect the handleNoteOn function to the library,
// so it is called upon reception of a NoteOn.
MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function
// Do the same for NoteOffs
MIDI.setHandleNoteOff(handleNoteOff);
// Initiate MIDI communications, listen to all channels
MIDI.begin(MIDI_CHANNEL_OMNI);
}
void loop()
{
// Call MIDI.read the fastest you can for real-time performance.
MIDI.read();
// There is no need to check if there are messages incoming
// if they are bound to a Callback function.
// The attached method will be called automatically
// when the corresponding message has been received.
}
johnwasser:
Use Google to look for examples where someone uses a keypad to enter a password. For example: Arduino Playground - HomePage Then remove the keypad stuff and put in MIDI stuff.
Not really sure exactly which part ties to the keypad and which is password related.
Would it be possible to have multiple key presses to activate the lock? Would that be easier to make instead of a sequence of key presses? Any help would be appreciated.
is this working for you? can you check if when you press a key handleNoteOn is called and when you release the key handleNoteOff is called too?
if not - review your wiring and get that part to work.
Once this is working then you have the structure to capture notes events. that's where you can do you magic cooking to identify if the last x keys pressed are the ones from your secret password tone..
Thanks for replying. Yes that was a copy from the web I asked if it was the right place to start from. I do not know how to expand from it. The example in my first post is working, from this one i can see different signs on serial monitor when I press and release the keys, so I think the wiring is correct.
Also I tested the input with this code as well.
#include <MIDI.h> // Add Midi Library
#define LED 13 // Arduino Board LED is on Pin 13
//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
pinMode (LED, OUTPUT); // Set Arduino board pin 13 to output
MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library.
// OMNI sets it to listen to all channels.. MIDI.begin(2) would set it
// to respond to notes on channel 2 only.
MIDI.setHandleNoteOn(MyHandleNoteOn); // This is important!! This command
// tells the Midi Library which function you want to call when a NOTE ON command
// is received. In this case it's "MyHandleNoteOn".
MIDI.setHandleNoteOff(MyHandleNoteOff); // This command tells the Midi Library
// to call "MyHandleNoteOff" when a NOTE OFF command is received.
}
void loop() { // Main loop
MIDI.read(); // Continuously check if Midi data has been received.
}
// MyHandleNoteON is the function that will be called by the Midi Library
// when a MIDI NOTE ON message is received.
// It will be passed bytes for Channel, Pitch, and Velocity
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,HIGH); //Turn LED on
}
// MyHandleNoteOFF is the function that will be called by the Midi Library
// when a MIDI NOTE OFF message is received.
// * A NOTE ON message with Velocity = 0 will be treated as a NOTE OFF message *
// It will be passed bytes for Channel, Pitch, and Velocity
void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,LOW); //Turn LED off
}
I think you will be interested in the pitch value. it's a byte ranging from 0 to 127 and you can deal with it just like if was a character as part of your password.
I think you will be interested in the pitch value. it's a byte ranging from 0 to 127 and you can deal with it just like if was a character as part of your password.
That's exactly how it works now. I understand the parameters and that pitch is the important one, I just don't know how to combine password and midi together. I would like this to work but would it make this project easier if instead of a password pressing down specific keys at the same time would be easier to do?
Why don't you create a global variable array that holds bytes which will be your password - Lets say 5 keys between 0 and 127 (let s call this one password[])
Have another array of the same size to hold the user entry - lets call it userEntry[] and initialize every item to 255.
Then every time you get a new key entered, shift down the previous entries and save the newly entered key at the last position.
You compare the 2 arrays, if they match bingo you won (reset everything) if not wrong entry. (That approach does not have a reset, it will succeed when you type the right 5 keys in the right sequence)
Let's see how this work:
Say your password is 88 90 92 94 96
userEntry Is 255 255 255 255 255
you type key 75 - the userEntry becomes 255 255 255 255 75 - compare false
you type key 88 - the userEntry becomes 255 255 255 75 88 - compare false
you type key 90 - the userEntry becomes 255 255 75 88 90 - compare false
you type key 92 - the userEntry becomes 255 75 88 90 92 - compare false
you type key 94 - the userEntry becomes 75 88 90 92 94 - compare false
you type key 96 - the userEntry becomes 88 90 92 94 96 - compare true
You win - trigger your solenoid, do what's needed and Reset userEntry to 255 255 255 255 255 to be ready for next time.
J-M-L's post came up when I was entering this code, it's close to what was described.
If your original code is working then you can add to it the ability to store the correct password and the keys pressed. Instead of comparing just one key you compare what is entered with the full password.
You need to determine how long the password is and whether you compare key presses as they are entered or wait until you get the proper number for a complete password. The code below uses a four note password and waits until there are four notes to compare.
byte commandByte;
byte noteByte;
byte velocityByte;
byte noteOn = 144;
const int passwordLength = 4; // # of keypresses in password
byte password[passwordLength] = {60, 62, 60, 61}; // correct password
byte keysPressed[passwordLength]; // store pressed keys
byte keyCount = 0; // keep track of # of keys presses
//light up led at pin 13 when receiving noteON message with note = 60
void setup() {
Serial.begin(31250);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
}
// return true if correct password entered
//
boolean checkPassword()
{
boolean retVal = true;
// look at keys pressed
for (int i = 0; i < passwordLength; i++)
{
// if not a match
if ( password[i] != keysPressed[i] )
{
// signal bad password
retVal = false;
// stop looking
break;
} // if
} // for
return (retVal);
}
void checkMIDI() {
if (Serial.available() > 2) {
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
//if (commandByte == noteOn){//if note on message
//check if note == 60 and velocity > 0
//if (noteByte == 60 && velocityByte > 0){
// if a note has been played
if ( (commandByte == noteOn) && (velocityByte > 0) )
{
// store key
keysPressed[keyCount++] = noteByte;
// if we've gotten a full password
if ( keyCount == passwordLength )
{
// check what was entered
if ( checkPassword() )
{
digitalWrite(13, HIGH); //turn on led
delay(10);
digitalWrite(13, LOW); //turn led off
} // if
// reset count
keyCount = 0;
} // if
} // if
}
}
void loop() {
checkMIDI();
}
EDIT: Corrected Serial.read() in first version and added MIDI library version for future thread readers.
Using MIDI library:
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
const int passwordLength = 4; // # of keypresses in password
byte password[passwordLength] = {60, 62, 60, 61}; // correct password
byte keysPressed[passwordLength]; // store pressed keys
byte keyCount = 0; // keep track of # of keys presses
void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
// set note on handler and start MIDI library
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.begin(MIDI_CHANNEL_OMNI);
}
// return true if correct password entered
//
boolean checkPassword()
{
boolean retVal = true;
// look at keys pressed
for (int i = 0; i < passwordLength; i++)
{
// if not a match
if ( password[i] != keysPressed[i] )
{
// signal bad password
retVal = false;
// stop looking
break;
} // if
} // for
return (retVal);
}
// called by MIDI library when a noteOn is recieved
void handleNoteOn(byte channel, byte pitch, byte velocity) {
// if a note has been played
if ( velocity > 0 )
{
// store key
keysPressed[keyCount++] = pitch;
// if we've gotten a full password
if ( keyCount == passwordLength )
{
// check what was entered
if ( checkPassword() )
{
digitalWrite(13, HIGH); //turn on led
delay(10);
digitalWrite(13, LOW); //turn led off
} // if
// reset count
keyCount = 0;
} // if
} // if
}
void loop() {
MIDI.read(); // check for a MIDI note
}
Thanks for the reply. Even though the code I posted in the first post definitely worked a couple of days ago, it didn't work this morning and I don't know why. So when i press key 60 led doesn't blink, i tried your code and it didn't work either, probable because its based on mine. Also can I make serial monitor to show notes properly, its just random signs now.
Chole:
Also I wasn't able to make serial monitor to show notes properly.
You can't use Serial for both MIDI and Serial Monitor. If you use an Arduino Leonardo you can use Serial (USB) for Serial Monitor and Serial1 (async serial) for MIDI. Similarly the MEGA has spare hardware serial ports.
get the simple wiring with the LEDS working. you should see the built in LED (pin 13) turn on and off each time you press and then release a key. if it does not, then you have a wiring issue. fix that first. when it works look at what is suggested above and code it. Do your part of the work please.
#include <MIDI.h> // Add Midi Library
#define LED 13 // Arduino Board LED is on Pin 13
//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,HIGH); //Turn LED on
}
void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,LOW); //Turn LED off
}
void setup() {
pinMode (LED, OUTPUT); // Set Arduino board pin 13 to output
MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library.
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleNoteOff(MyHandleNoteOff);
}
void loop() { // Main loop
MIDI.read(); // Continuously check if Midi data has been received.
}
get the simple wiring with the LEDS working. you should see the built in LED (pin 13) turn on and off each time you press and then release a key. if it does not, then you have a wiring issue. fix that first. when it works look at what is suggested above and code it. Do your part of the work please.
#include <MIDI.h> // Add Midi Library
#define LED 13 // Arduino Board LED is on Pin 13
//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,HIGH); //Turn LED on
}
void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,LOW); //Turn LED off
}
void setup() {
pinMode (LED, OUTPUT); // Set Arduino board pin 13 to output
MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library.
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleNoteOff(MyHandleNoteOff);
}
void loop() { // Main loop
MIDI.read(); // Continuously check if Midi data has been received.
}
That code works fine. Pin 13 turns on and off with each press and then release of a key. I will try to figure out how to do this with 2 arrays.
It strikes me that your do-while conditions do not make sense.
do {
if (Serial.available()) {
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
.
.
.
}
} while (Serial.available() > 2);//when at least three bytes available
If there are any bytes available you try to read 3 bytes, so if there is a single byte ready you get out of sync. Try removing the do-while and checking for three bytes before reading any.
if (Serial.available() > 2) {
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
.
.
.
}
you are technically correct - he should wait for data to arrive
he moved away from that approach though if you read below in the thread, you'll see he is now trying to use handler which takes the guesswork out of the way as you are called with all the info when a key is pressed or released.
makes what he wants to do much easier
@ JML
You explanation of the proposed code is really clear and understandable. I'm afraid that I'm just over my head with this with my 2 month experience with arduinos and coding in general. What I in the end end up doing is google and trying to piece things together. How do I single out pitch and store it in the array? I'm sorry if this is gibberish, tryed to expand on that code that worked.
#include <MIDI.h> // Add Midi Library
#define LED 13 // Arduino Board LED is on Pin 13
//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_DEFAULT_INSTANCE();
const int passwordLength = 5; // # of keypresses in password
int password[passwordLength] = {60, 62, 64, 65, 67}; // correct password
int userEntry[passwordLength] = { 255, 255, 255, 255, 255, };
void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,HIGH); //Turn LED on
}
void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
digitalWrite(LED,LOW); //Turn LED off
}
void setup() {
pinMode (LED, OUTPUT); // Set Arduino board pin 13 to output
MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library.
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleNoteOff(MyHandleNoteOff);
}
boolean checkArrays(int password[],int userEntry[], long numItems) {
boolean same = true;
long i = 0;
while(i<numItems && same) {
same = password[i] == userEntry[i];
i++;
}
return same;
}
void loop() { // Main loop
MIDI.read(); // Continuously check if Midi data has been received.
}
Please write a program - don't google it - that prints the index in the array, and each element in password array and corresponding userEntry element - one by one - to the serial and print "==" if they are the same or "<>" if they are different in between the values.
The output with the values above in your code should look like