Changing variables values inside different "case"

I am trying to develop a code to communicate with musical instrument shield. This uses midi commands inside different cases. Cases are activated when the corresponding char is written over serial. I am using Firmata protocol to do this coding. and example code is given below. What i am looking for is instead of changing instrument number by making a different case and defining it, i would like to create two cases defined with instrument number (0-127). if first case is activated all the variable in other cases should be instrument+1 and for second case instrument-1. That way a person can choose different instruments just by sending one of the two char through serial.
I am not sure if this is possible but any other suggestions are welcome as well. :smiley: :smiley: :smiley:

in given code i want to change talkMIDI(0xC0,0 , 0); (specified by bold characters) to talkMIDI(0xC0,instrument , 0); and define instrument numbers (0-127). then have two more cases to select a number between 0-127 as instrument+1 and instrument-1. “instrument” being the currently specified value for instrument.

hope i could get some insight on this. Thank you for help. :slight_smile: :slight_smile: :slight_smile:

#include <Firmata.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Tied to VS1053 Reset line
byte ledPin = 13; //MIDI traffic inidicator
int instrument = 0;

byte previousPIN[TOTAL_PORTS]; // PIN means PORT for input
byte previousPORT[TOTAL_PORTS];

void outputPort(byte portNumber, byte portValue)
{
// only send the data when it changes, otherwise you get too many messages!
if (previousPIN[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue);
previousPIN[portNumber] = portValue;
}
}

void setPinModeCallback(byte pin, int mode) {
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), mode);
}
}

void digitalWriteCallback(byte port, int value)
{
byte i;
byte currentPinValue, previousPinValue;

if (port < TOTAL_PORTS && value != previousPORT[port]) {
for (i = 0; i < 8; i++) {
currentPinValue = (byte) value & (1 << i);
previousPinValue = previousPORT[port] & (1 << i);
if (currentPinValue != previousPinValue) {
digitalWrite(i + (port * 8 ), currentPinValue);
}
}
previousPORT[port] = value;
}
}

void setup()
{
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.begin(57600);
mySerial.begin(31250);

//Reset the VS1053
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);
talkMIDI(0xB0, 0x07, 120);
}

void loop()
{
byte i;

for (i = 0; i < TOTAL_PORTS; i++) {
outputPort(i, readPort(i, 0xff));
}

while (Firmata.available()) {
Firmata.processInput();
}

{
if (Serial.available()) {
//read serial as a character
char ser= Serial.read();
switch (ser) {
case’0’:
talkMIDI(0xB0, 0, 0x79);
talkMIDI(0xC0, 0, 0); //Set instrument number. 0xC0 is a 1 data byte command

noteOn(0, 60, 60);
delay(100);
noteOff(0, 60, 60);
delay(50);
break;

case’1’:
talkMIDI(0xB0, 0, 0x79);
talkMIDI(0xC0, 0, 0); //Set instrument number. 0xC0 is a 1 data byte command
noteOn(0, 70, 60);
delay(100);
noteOff(0, 70, 60);
delay(50);
break;

case’2’:
talkMIDI(0xB0, 0, 0x79); //Default bank GM1
talkMIDI(0xC0,14 , 0); //Set instrument number. 0xC0 is a 1 data byte command
noteOn(0, 60, 60);
delay(100);
noteOff(0, 60, 60);
delay(50);
break;

case’3’:
talkMIDI(0xB0, 0, 0x79); //
** talkMIDI(0xC0, 14, 0);** //Set instrument number. 0xC0 is a 1 data byte command
noteOn(0, 70, 60);
delay(100);
noteOff(0, 70, 60);
delay(50);
break;
}
}
}
}
//Send a MIDI note-on message. Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}

//Send a MIDI note-off message. Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}

//Plays a MIDI note. Doesn’t check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
digitalWrite(ledPin, HIGH);
mySerial.write(cmd);
mySerial.write(data1);

//Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
//(sort of: http://253.ccarh.org/handout/midiprotocol/)
if( (cmd & 0xF0) <= 0xB0)
mySerial.write(data2);

digitalWrite(ledPin, LOW);
}

That way a person can choose different instruments just by sending one of the two char through serial.
I am not sure if this is possible

It is.

in given code i want to change talkMIDI(0xC0,0 , 0); (specified by bold characters) to talkMIDI(0xC0,instrument , 0); and define instrument numbers (0-127). then have two more cases to select a number between 0-127 as i+1 and i-1. "i" being the currently specified value for instrument.

I'm not following this. You don't have a variable called instrument, and I have no clue what i+1 or i-1 means. If the variable i means the same as the variable instrument, just say instrument+1 and instrument-1.

Of course, you need to define what would cause instrument+1 to be used, instead of instrument or instrument-1.

thank you for your reply.
I am sorry. :cold_sweat: I am new arduino and C language. :grin:

Yes, by i+1 and i-1, I meant instrument+1 and instrument-1. but I don't know how to define instrument and cases to achieve this functionality. Any suggestion would be really apreciated... :sweat_smile: :sweat_smile:

Have you tried talkMIDI(0xC0,instrument , 0); ?
I can see nowhere in your code where you change the value of instrument from its original value of 0.
Sending that value (0) to midi will tell it to play instrument 0.
I suspect that that would be like an 'air guitar' or a 'hairbrush microphone'.

hi Henry.
Thanks for replying.
I know I would have to use talkMIDI(0xC0,instrument , 0);, But I don't know how to define instrument to change values. since they are all inside cases. I am not sure how it works. Any example or relevant topic would be really helpful, since I can't find anything similar.

I don't know how to define instrument to change values. since they are all inside cases.

If you declare instrument as a global variable then you can assign, change or use it's value anywhere in the program.

here is the modification I made. I am not sure if it is working fine. because sometimes it skips one instrument and chooses the next one.(e.g 0+1=1 but it chooses no.2). there’s a way to fix this? and do I also have to specify the the numbers of instruments are between 0-127? any suggestions?

thanks again

#include <Firmata.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Tied to VS1053 Reset line
byte ledPin = 13; //MIDI traffic inidicator
int  instrument = 0;


byte previousPIN[TOTAL_PORTS];  // PIN means PORT for input
byte previousPORT[TOTAL_PORTS];

void outputPort(byte portNumber, byte portValue)
{
 // only send the data when it changes, otherwise you get too many messages!
 if (previousPIN[portNumber] != portValue) {
   Firmata.sendDigitalPort(portNumber, portValue);
   previousPIN[portNumber] = portValue;
 }
}

void setPinModeCallback(byte pin, int mode) {
 if (IS_PIN_DIGITAL(pin)) {
   pinMode(PIN_TO_DIGITAL(pin), mode);
 }
}

void digitalWriteCallback(byte port, int value)
{
 byte i;
 byte currentPinValue, previousPinValue;

 if (port < TOTAL_PORTS && value != previousPORT[port]) {
   for (i = 0; i < 8; i++) {
     currentPinValue = (byte) value & (1 << i);
     previousPinValue = previousPORT[port] & (1 << i);
     if (currentPinValue != previousPinValue) {
       digitalWrite(i + (port * 8), currentPinValue);
     }
   }
   previousPORT[port] = value;
 }
}

void setup()
{
 Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
 Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
 Firmata.attach(SET_PIN_MODE, setPinModeCallback);
 Firmata.begin(57600);
   mySerial.begin(31250);

 //Reset the VS1053
 pinMode(resetMIDI, OUTPUT);
 digitalWrite(resetMIDI, LOW);
 delay(100);
 digitalWrite(resetMIDI, HIGH);
 delay(100);
 talkMIDI(0xB0, 0x07, 120);
}

void loop()
{
 byte i;

 for (i = 0; i < TOTAL_PORTS; i++) {
   outputPort(i, readPort(i, 0xff));
 }

 while (Firmata.available()) {
   Firmata.processInput();
 }

{
 if (Serial.available()) {
   //read serial as a character
   char ser= Serial.read();
   switch (ser) {
     case'0':
     talkMIDI(0xB0, 0, 0x79); //Default bank GM1
   talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command
     //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
     noteOn(0, 60, 60);
     delay(100);
     noteOff(0, 60, 60);
     delay(50);
    break; 
     case'1':
     talkMIDI(0xB0, 0, 0x79); //Default bank GM1
   talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command
     //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
     noteOn(0, 70, 60);
     delay(100);
     noteOff(0, 70, 60);
     delay(50);
    break; 
     case'2':
     talkMIDI(0xB0, 0, 0x79); //Default bank GM1
   talkMIDI(0xC0,instrument , 0); //Set instrument number. 0xC0 is a 1 data byte command
     //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
     noteOn(0, 65, 60);
     delay(100);
     noteOff(0, 65, 60);
     delay(50);
    break;
     case'3':
     talkMIDI(0xB0, 0, 0x79); //Default bank GM1
   talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command
     //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
     noteOn(0, 71, 60);
     delay(100);
     noteOff(0, 71, 60);
     delay(50);
    break; 
  case'4':
     instrument= instrument+1;
     break;
     case'5':
     instrument=instrument-1;
     break;
   }
 }

Your code would be much easier to read and copy to an editor (and would not have a smiley in it) of you used code tags. Select the code and use the code icon (</>) above the edit window.

sometimes it skips one instrument and chooses the next one.(e.g 0+1=1 but it chooses no.2)

Try printing a message and the value of ser so that you know exactly what is being received.

do I also have to specify the the numbers of instruments are between 0-127? any suggestions?

I am not familiar with the MIDI interface but it is trivial to keep the value of instrument within the range 0-127. After you increment or decrement its value check the result and if it is out of the required range change it’s value so that it is back in the range.

i have figured out that part. i just have one more question. how many cases can i create?
i know i can use 0-9 a to z and A to Z. is there a way that arduino can use more than one character in cases? if yes. could someone please provide me a refreence?
thank you

can use more than one character in cases?

The case must be an integer or be able to be resolved to an integer so, no, you cannot use more than one character.

You could take a multi character string (lowercase s) and create an integer by manipulating the ASCII value of each character or more simply just use an if expression and the strcmp() function to test the string.

Kumar102:
i have figured out that part. i just have one more question. how many cases can i create?
i know i can use 0-9 a to z and A to Z. is there a way that arduino can use more than one character in cases? if yes. could someone please provide me a refreence?
thank you

You can have up to 1024 different cases in each switch statement. You can number them from 0 to 1023 or from 30,000 to 31,023 or anywhere in between. The number has to be unique for each case, but they don't have to be contiguous. So you must be able to have up to 5 numeric characters to define a case.