Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 18 of 18

Thread: How to generate USB MIDI clock with Teensy 2.0

  1. #1
    Junior Member
    Join Date
    Oct 2016
    Posts
    13

    How to generate USB MIDI clock with Teensy 2.0

    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!

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,828
    Maybe something like this?

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

  3. #3
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    Quote Originally Posted by PaulStoffregen View Post
    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?

  4. #4
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,342
    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.

  5. #5
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    So how do I vary the timing of between clocks in order to control the tempo of the external MIDI instrument?

  6. #6
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    912
    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

  7. #7
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    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?

  8. #8
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,573
    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.

  9. #9
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,342
    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_timin...pedMillis.html
    The method shown in Repeating Multiple Tasks At Regular Intervals is perhaps a bit better method.)
    Last edited by oddson; 03-27-2018 at 06:51 PM.

  10. #10
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    912
    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.

  11. #11
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    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!!

  12. #12
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    912
    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

  13. #13
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    You have a point there. I will look into blink without delay.

    Thanks!

  14. #14
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    Quote Originally Posted by mortonkopf View Post
    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);
    }
    }

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,828
    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.

  16. #16
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,342
    Quote Originally Posted by mortonkopf View Post
    oddson will hopefully correct this, but you will need to send 24 clocks per quarter note...
    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.

  17. #17
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    Quote Originally Posted by PaulStoffregen View Post
    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.

  18. #18
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    912
    @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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •