How to generate USB MIDI clock with Teensy 2.0

Status
Not open for further replies.

laserr

Member
I am a Teensy newbie.

I know how to send note/on/off, continuous controllers via USB MIDI in my MIDI controller projects.

Can someone show me in a simple sketch how to generate MIDI Clock using usbMIDI.sendRealTime(usbMIDI.Clock);

I cannot find any examples that send MIDI clock over USB. I don't need to sync with a DAW, I want to control the tempo of a Kontakt 5 instrument in standalone mode. No DAW is involved.

I know how to read a potentiometer to generate a variable. How to insert the variable into "clock".

Thanks!
 
Maybe something like this?

Code:
void setup() {
}
void loop()  {
  usbMIDI.sendRealTime(usbMIDI.Clock);
  usbMIDI.send_now();
  delay(125);
}
 
Maybe something like this?

Code:
void setup() {
}
void loop()  {
  usbMIDI.sendRealTime(usbMIDI.Clock);
  usbMIDI.send_now();
  delay(125);
}

Paul,

The above does not show me how generate the variable "Clock".

For example generating a MIDI CC (continuous controller) like Modulation is easy.
I read a pot:
int mod = map(analogRead(7), 0, 1023, 0, 117);
Then insert the variable "mod"
usbMIDI.sendControlChange(1, mod, 1); The first 1 is the CC type "1" modulation, mod is amount of modulation, and the last 1 is the MIDI channel. It is very intuitive.

How do do a similar thing for clock?
 
MIDI Real Time Clock is a 1 byte event message without a parameter. It's more like a click-track than a clock.

Effectively usbMIDI.clock IS the parameter since it's value (defined as 0xF8) IS the realtime message.
 
So how do I vary the timing of between clocks in order to control the tempo of the external MIDI instrument?
 
sound like you want to send out a bpm clock. you can set a timer to count and if it reaches the number of micro or milliseconds you have set, it will send a clock message. you set a time interval that you can vary with a dial or pot, read that value, this becomes your midi clock interval (adjust it to scale), then you set a current time, see if that plus the interval is what you want, if it is send the clock message and reset the current time

something like:


if ((currentTime - pastTime) > midiclockIntervall) {
usbMIDI.sendRealTime(CLOCK); }

where:
const byte CLOCK = 0xF8; //=midi beat clock message

you could also make this up into an interval timer
 
I am newbie and have never used a timer controlled by a pot. I know how to read a pot and set a variable, but that is about the extent of my knowledge.

Can I trouble you for a code example?
 
Explanations and code examples can be found on the corresponding PJRC reference website: https://www.pjrc.com/teensy/td_libs_TimerOne.html

Symbolic code would be in setup() initialize timer with a default value, attach an interrupt function. In the loop() read the pot, calculate the desired time interval from that and use setPeriod(myInterval) to apply it. Finally write the previously attached interrupt function which will just send out the clock tick over USB.
 
So you want a pot to set a variable which affects the timing of MIDI clock messages?

Do you have a BPM range in mind? Say 120 at mid-point and 60-180 as the range.

So if the variable (midiclockIntervall) is going to end up with the milliseconds between clocks we will need to map the output range from 1000 at 0 to 333 at 1023 (for 10-bit DAC).

Then in Morton's example I think you just need to write the current 'pastTime' after every clock so it will be false again until another interval is passed.

Because of the possibility the currentTime minus the last clock maybe greater than the interval we don't want to reset pastTime to the current time but rather one interval more than its previous value so that any late clocks won't cause the tempo to drift over time.

if ((currentTime - pastTime) > midiclockIntervall) {
usbMIDI.sendRealTime(CLOCK);​
pastTime = pastTime + midiclockIntervall;​
}

Where currentTime is an elapsedMillis timer left running and pastTime is just a variable.

(edit - Th. posted while I fiddled... I've not used the timer library before so I'm not sure if there is any advantage to it. The ellapsedMillis function is documented here: https://www.pjrc.com/teensy/td_timing_elaspedMillis.html
The method shown in Repeating Multiple Tasks At Regular Intervals is perhaps a bit better method.)
 
Last edited:
oddson will hopefully correct this, but you will need to send 24 clocks per quarter note and a quarter note is 60bpm. At 120 BPM this means 2880 Midi Clock Pulses per minute. The reason I mention this is so that you can get an idea of scaling your potentiometer output into the right range.
 
My application does not require precise BPM. I am controlling a Kontakt 5 Didgeridoo instrument that has rhythmic variations based on the tempo. So I may just use a 3 position (2 bit logic) input switch to select SLOW, MEDIUM, FAST.
So prove to myself that the MIDI clock works, I put together this extremely simple sketch using delay and it works.

void setup() {
// put your setup code here, to run once:

}

void loop() {
// put your main code here, to run repeatedly:


usbMIDI.sendRealTime(usbMIDI.Clock);
delay(20);//about 125 BPM
}

I can see that Kontakt is displaying 125 +/- 5%, which is good enough for me.

I guess I should learn how to use the timer interval method. But if this works along with the rest of the MIDI controller sketch I am happy.

Thanks to all for your help!!
 
if it works for your purposes, great. A word of caution though, introducing delay() into the loop may create issues with timing when you combine this with future midi ideas as your sketch develops. see discussion on blink without delay ; https://www.arduino.cc/en/tutorial/BlinkWithoutDelay

This sketch using millis seems to work. I use a pot to adjust timer from 83 to 147 bpm. What do you think?

/*
Repeating Timer
Code Alternative to ElapsedMillis

(c)2015 Forward Computing and Control Pty. Ltd.
This code may be freely used for both private and commerical use.
Provide this copyright is maintained.
*/

unsigned long timer; // the timer
int tim;

void setup() {

timer = millis(); // start timer
}

void loop() {
int tim = map(analogRead(0), 0, 1023, 30, 18);//adjusts tempo from 83 to 147BPM
unsigned long INTERVAL = tim; // the repeat interval
if ((millis()-timer) > INTERVAL) {
// timed out
timer += INTERVAL;// reset timer by moving it along to the next interval
usbMIDI.sendRealTime(usbMIDI.Clock);
}
}
 
You might consider using micros() instead of millis() and map the result from 30000 to 18000. That will give you finer control.

Mapping from 30 to 18 gives you only 13 coarse steps. If you're happy with with that precision, then maybe this is overkill. But it's pretty easy since all you have to do is change the function name and add 3 zeros to the numbers to give yourself much higher precision.
 
oddson will hopefully correct this, but you will need to send 24 clocks per quarter note...

:eek: er... right. don't know why I quoted quarter note values I just was reading them from a chart and forgot what I was doing.

Still not sure of the math but I think Paul is correct re: micros since I get 20.8 microseconds between clocks to get 48 clocks per second for 120 bpm.
 
You might consider using micros() instead of millis() and map the result from 30000 to 18000. That will give you finer control.

Mapping from 30 to 18 gives you only 13 coarse steps. If you're happy with with that precision, then maybe this is overkill. But it's pretty easy since all you have to do is change the function name and add 3 zeros to the numbers to give yourself much higher precision.

I changed millis to micros and it works fine. I noticed that as with millis the Kontakt tempo readout is always fluctuating (for example 122.8 thru 122.9). It doesn't matter to me but I wonder if the value can be sent quantized to the nearest whole number like 123 instead of 122.8 thru 122.9.
 
@Paul, perhaps add the final working variable midi tempo sender sketch to the examples list in teensyduino? It does seem to be one of the things that many people want to include in homebrew usbmidi devices.
 
Status
Not open for further replies.
Back
Top