Midi processing things

Hi all, I'm interested in creating some basic Midi sketches, I have had a look around on instructables, this forum and on little scale's excellent resource but as I am so new to Arduino and programming some of the stuff is not really that clear to me. I am also a bit dyslexic when it comes to maths and things like hexadecimal.

So far I have managed to get Midi into my Uno, I made the interface using a 6n138 opto and managed to get the LED blinking in response to Midi clock etc. I have not managed to get output based on conditions from the input though. I have just bought a sparkfun midi shield to eliminate the possibility of hardware problem. At this point I'm started to get interested in doing a few things like this:

A midi clock divider, simple just say 1/2 and 1/4 of the master clock perhaps selected by a switch
A midi filter, for example to take a midi input and strip out all other info except clock or notes etc.
Have a bunch of LEDs light up in response to different midi notes

I have a mutable instruments Midipal, which can do most this stuff for me, but I want to learn how to do these things myself, I have done some of the basic sketches in the examples, but the actual turning my ideas into sketches is where I seem clueless, programming of any sort has always been difficult for me to understand, so Arduino seems like the perfect platform to get started. I like the whole concept of sharing, hacking and modifying sketches, and of course I look foreward to one day sharing my own sketches for others to mess with.

So, with that in mind (and thanks for reading this far) does anyone have any well commented code that does any of the above? From what I can gather there would seem to be a few different ways to achieve these ideas, I'm mainly interested in simple and lean stuff that is not going to affect timing.

I understand the very basic concepts like void setup, variables, count, void loop etc but putting everything together is where I seem to be stumbling, so if anyone has any sketches to share then I'd be most greatful.

Thanks!

I have a MIDI decoder here, that should get you started (see attachment).

Demo of it in operation:

You can see it keeps up with incoming MIDI fast enough to echo it to serial. If you wanted to modify the MIDI you could make changes and output MIDI on the outgoing serial port.

There was another thread about this sort of idea recently.

MIDI_decoder.ino (13.7 KB)

Not 100% in line with what you are looking for, but in my code repository (link below) there is a library that reads MIDI files from an SD card and 'plays' them to your sketch (ie, it allows you to decide what to do with the MIDI notes). There are a number of example programs as part of the library that you may be able to use.

Thanks a lot for replying guys, I'll have a good look into both, in the meantime here is the sketch I have written, but it is not working, tempoled is simply a LED attached to pin 13 to make sure the tempo is being halved (which it seems to be) however I am getting no output from the midi out (remember I am using the sparkfun shield) I am probably overlooking something, or maybe I have approached it totally from the wrong angle, anyway have a peep.

/* my test to halve midi clock NB NOT WORKING DO NOT USE

*/

// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;


// Variables 
int clockdiv2 = 0;
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
Serial.begin(31250);
pinMode(tempoled, OUTPUT);
}


// Program
void loop() {
if(Serial.available() > 0) {
data = Serial.read();

if(data == midi_start) {
Serial.print(midi_start);

  play_flag = 1;
}

else if(data == midi_stop) {
Serial.print(midi_stop);
  play_flag = 0;
clockdiv2 = 0;
}

else if((data == midi_clock) && (play_flag == 1)) {
  
halftempo();
}
} 
}


// Functions
void halftempo() {
if(clockdiv2 == 0) {
digitalWrite(tempoled, LOW);

clockdiv2 = 1;

}

else if(clockdiv2 == 1) {
digitalWrite(tempoled, HIGH);
Serial.print(midi_clock);

clockdiv2 = 0;
}
}

Ok, bit of progress, realised I was wrongly using serial.print rather than serial.write (d'oh!) So seems to be (kind of) working now, here is the updated code

*/

/* my test to halve midi clock 2nd attempt

// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;


// Variables 
int clockdiv2 = 0;
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
Serial.begin(31250);
pinMode(tempoled, OUTPUT);
}


// Program
void loop() {
if(Serial.available() > 0) {
data = Serial.read();

if(data == midi_start) {
Serial.write(midi_start);

  play_flag = 1;
}

else if(data == midi_stop) {
Serial.write(midi_stop);
  play_flag = 0;
clockdiv2 = 0;
}

else if((data == midi_clock) && (play_flag == 1)) {
  
halftempo();
}
} 
}


// Functions
void halftempo() {
if(clockdiv2 == 0) {
digitalWrite(tempoled, LOW);

clockdiv2 = 1;

}

else if(clockdiv2 == 1) {
digitalWrite(tempoled, HIGH);
Serial.write(midi_clock);

clockdiv2 = 0;
}
}

Well, does it work? Try using the IDE's auto-format feature.

I uploaded it to my Uno and it sort of works, the tempo clock of the slave device is half that of the master, but then I am getting some oddness, such as the start/stop not always working, and the LED pin running all the time, I thought that the LED should not be lit when the master clock was stopped.

Hey Nick, do you think you could try it with your setup and let me know if it works?

Can you upload code that compiles please?

Oops, sorry about that, try this (living up to my handle here!)

// my test to halve midi clock 2nd attempt

// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;


// Variables 
int clockdiv2 = 0;
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
Serial.begin(31250);
pinMode(tempoled, OUTPUT);
}


// Program
void loop() {
if(Serial.available() > 0) {
data = Serial.read();

if(data == midi_start) {
Serial.write(midi_start);

  play_flag = 1;
}

else if(data == midi_stop) {
Serial.write(midi_stop);
  play_flag = 0;
clockdiv2 = 0;
}

else if((data == midi_clock) && (play_flag == 1)) {
  
halftempo();
}
} 
}


// Functions
void halftempo() {
if(clockdiv2 == 0) {
digitalWrite(tempoled, LOW);

clockdiv2 = 1;

}

else if(clockdiv2 == 1) {
digitalWrite(tempoled, HIGH);
Serial.write(midi_clock);

clockdiv2 = 0;
}
}

The Auto-Format feature works quite well you know.

I can't see where you are passing on anything but midi_start, midi_stop and midi_clock.

Your led may be on because when it stopped it was HIGH, but no one told him to go off...

else if(data == midi_stop) {
Serial.write(midi_stop);
  play_flag = 0;
clockdiv2 = 0;
}

if clockdiv2 equals 0 the led should be off, but that is inside halftempo();. You're making play_flag = 0 and clockdiv 2 = 0 at the same time, so if play_flag == 0 this won't happen

else if((data == midi_clock) && (play_flag == 1)) {
  
halftempo();
}

and the led variable on the halftempo() function will be refreshed, but the function won't be executed at all.
You can just add digitalWrite(tempoled, LOW); to the stop statement

else if(data == midi_stop) {
Serial.write(midi_stop);
  play_flag = 0;
clockdiv2 = 0;
digitalWrite(tempoled, LOW); 
}

How are you sending midi clock to the arduino? Remember some programs may send continue instead of start

@ Nick - I think I just pasted it in from the IDE wrongly,as it was compiling ok on my computer :blush:

@Capicoso - Thanks, at present I am just using an old Roland PMA-5 to send the midi, good catch on the continue, it might explain some of the weirdness?

I'm wondering if using the midi library might be worth a try, I had a quick look at it but lots of the (non midi) terminology is unfamiliar to me (I'm really not a computer guy, if that wasn't already blatantly clear!) so not sure ATM.

Also I am aware that this attempt will only allow halving of the tempo, what would be the best approach for other tempo divisions, such as for example having digital pins going high on musical divisions of a bar, so for example to get 16th notes I assume it would be a case of figuring out how to divide the 24ppqn midi clock down to 4ppqn (divide by 6). But maybe getting a bit ahead of myself here....

OldDumbButKeen:
@ Nick - I think I just pasted it in from the IDE wrongly,as it was compiling ok on my computer :blush:

@Capicoso - Thanks, at present I am just using an old Roland PMA-5 to send the midi, good catch on the continue, it might explain some of the weirdness?

I'm wondering if using the midi library might be worth a try, I had a quick look at it but lots of the (non midi) terminology is unfamiliar to me (I'm really not a computer guy, if that wasn't already blatantly clear!) so not sure ATM.

Also I am aware that this attempt will only allow halving of the tempo, what would be the best approach for other tempo divisions, such as for example having digital pins going high on musical divisions of a bar, so for example to get 16th notes I assume it would be a case of figuring out how to divide the 24ppqn midi clock down to 4ppqn (divide by 6). But maybe getting a bit ahead of myself here....

I send MIDI clock with my computer, using Renoise, and i press play with right click it sends start, but with left cilck it sends continue if i remember correctly... That littlescale code makes use of the continue message, but you deleted it, you should add it and see if the weirdness stops... Do you know the difference between continue and start messages?
I don't think you need the MIDI library, i have a huge code for a sequencer i'm designing, and i'm using something like that littlescale code and it works fine, it's something simple...

For the subdivision part...
I did something like that, my sequencer receives midi clock, and it has 3 clock outputs at the same time, one at 1/4, another one at 1/8 and other 1/16.
Your function is called everytime a MIDI clock pulse is received. So if you want your led to go on and off at 1/4 intervals, you have to count to 24 inside the function.
So, you can say if the counter is at 0 make the led go on, then it'll be on as long as you want, if you want to make it short, make another statement if the counter is at 3, power off the led. Then another one at counter 24, to reset it to 0. Or you could use modulo % so you don't have to reset it to 0.

Thanks for the pointers, I'll keep at it, but when you say stuff like:

" Or you could use modulo % so you don't have to reset it to 0." I have no idea what that means :blush:

Any chance you could post an example as code? (don't worry if you don't have the time)

And big thanks for you guys patience, I'm kind of trying to get little building blocks of the concepts working, then hopefully adding the other things once I understand how each section works.

OldDumbButKeen:
Thanks for the pointers, I'll keep at it, but when you say stuff like:

" Or you could use modulo % so you don't have to reset it to 0." I have no idea what that means :blush:

Well it may be my fault because I don't speak english so well...
Check reference to see how it works, and here you have an example
http://arduino.cc/en/Tutorial/ButtonStateChange
It has a variable that increments everytime the button is pressed, in your case, this happen everytime a MIDI clock pulse is received. And

if (buttonPushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  }

if you want something to happen every 4 pulses, the above code works without resetting the variable to 0. Because if it's 4, the remainder will be 0, if it's 8 the remainder will be 0, 16 % 4 = 0, 20, 24, etc.

OldDumbButKeen:
Thanks a lot for replying guys, I'll have a good look into both, in the meantime here is the sketch I have written, but it is not working, tempoled is simply a LED attached to pin 13 to make sure the tempo is being halved (which it seems to be) ...

One problem I see here is that if you halve the tempo, surely that means you take in (say) 16 notes and output 8 in the same time? Now very very quickly you are going to run out of a "holding place" to hold the extra notes.

Imagine a room which holds 50 people, and people are entering at the rate of 10 a minute, and leaving at the rate of 5 a minute. The room will fill up quickly, won't it?

You know what Nick, you might very well have solved a weird issue I was having - when the sketch was running, (I stupidly did not keep track well enough of changes I made, classic newb mistake I guess) the tempo function was doing exactly what I wanted, but then after around 2 bars or so the slave device was stopping. I thought that since it is just clock then no space was needed- is that not right? Certainly your observation seems to be in line with what was happening.

Maybe my best bet is to throw out the whole sketch and try something else? At this point all I want to be able to achieve is have the arduino recieve midi clock (done, working) and send out midi clock at half the tempo, so for example if the master clock is 120bpm, then the tempo from the midi out would be 60bpm. Then eventually I'd like to be able to add some digital pins doing other divisions of the clock, so for example have a LED flashing at the tempo (4 beats like on a drum machine etc) then a 16th note output for triggering old pre midi gear etc. (5v pulse say 20ms)

What do you guys think is the best way to achieve it? How would you do it? I'm not looking for you to write the sketch for me but I'd be interested in some other ideas. Thanks :slight_smile:

OldDumbButKeen:
Then eventually I'd like to be able to add some digital pins doing other divisions of the clock, so for example have a LED flashing at the tempo (4 beats like on a drum machine etc) then a 16th note output for triggering old pre midi gear etc. (5v pulse say 20ms)

What do you guys think is the best way to achieve it? How would you do it? I'm not looking for you to write the sketch for me but I'd be interested in some other ideas. Thanks :slight_smile:

I gave you a hint for that in the last post. Just make a digital pin high every x midi clock pulses and low after x+3 or so.

What I don't understand even with Nick's observation is that weird behaviour you're having with the midi clock. I don't see what is wrong with that:
1 1
2
3 2
4
5 3
6
7 4
8
the 2nd row is the tempo at half the speed
i don't see the problem... what am i missing?
oh and this:

void halftempo() {
if(clockdiv2 == 0) {
digitalWrite(tempoled, LOW);

clockdiv2 = 1;

}

else if(clockdiv2 == 1) {
digitalWrite(tempoled, HIGH);
Serial.write(midi_clock);

clockdiv2 = 0;
}
}

I think you should send the first midi clock pulse when the first midi clock pulse arrived to your arduino. Now you're sending the out after the first pulse...
if you try something like this?:

int counter = 0;
void halftempo() {
if (counter % 2 == 0) {
Serial.write(248);
}

counter++;
}

Not really tested. I just tried it with the serial monitor:

void setup(){
  Serial.begin(9600);
}


int counter = 0;
void loop(){

  if(counter % 2 == 0) {
    Serial.print(counter);
    Serial.print("clockOut");
  }

  Serial.print(counter);
  Serial.println(" ----- clockIn");
  
  delay(100);
  
  counter++;
}

@OP: Can you post your current code please? When I last saw it you were not passing on all messages.

It seems to me that you need to do more than halve the MIDI clock rate. The actual messages have to go out at half the rate as well.

OK, here is the current version, it is not working at all now, also the LED starts flashing as soon as the sketch starts, changing the tempo or pressing start/stop has no affect on the LED or the slave device. I have no idea why it isn't working.

/* my test to halve midi clock

*/

// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;


// Variables 
int clockdiv2 = 0;
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
Serial.begin(31250);
pinMode(tempoled, OUTPUT);
}


// Program
void loop() {
if(Serial.available() > 0) {
data = Serial.read();

if(data == midi_start) { // if midi in start
Serial.write(midi_start); // send midi out start

  play_flag = 1;
}

if(data == midi_continue) { // if midi in continue
Serial.write(midi_continue); // send midi out continue

  play_flag = 1;
}

else if(data == midi_stop) { // if midi in stop
Serial.write(midi_stop); // send midi out stop
  play_flag = 0;
clockdiv2 = 0;
}

else if((data == midi_clock) && (play_flag == 1)) {
  
halftempo();
}
} 
}


// Functions
void halftempo() {
if(clockdiv2 == 0) {
digitalWrite(tempoled, LOW);

clockdiv2 = 1;

}

else if(clockdiv2 == 1) {
digitalWrite(tempoled, HIGH);
Serial.write(midi_clock); // send midi clock to out

clockdiv2 = 0;
}
}

@Capicoso Sorry I did not intend to seem ungrateful, what I meant was that I did not understand how to do what you suggested earlier.