ableton live bpm read and display on teensy (clocking)

Status
Not open for further replies.

321lupo

Active member
Hey everybody,
me again with a new problem :) , I hope someone can help me. I have searched around the internet for a while,
but it still seems that Teensy, despite its amazing usb.midi library still is a bit complicated when it comes to syncing to
the clock/bpm of DAWs, in my case Ableton Live. (In the long run, would it be possible to just add that as a function to the library?)

In my case I would like to use a gestural controller to control the bpm in Ableton Live after it is switched on, however, when switching it off,
I want to to jump back to the original bpm value. Therefore it is not enough for me to simply map the bpm with a pitch control,
but I need my Teensy board to know at any give point what the current Ableton Live bpm is. I have copied/pieced together (mostly copied..) this code here, some I found on the forum:

Code:
// originally, Teensyduino MIDI Beat Clock Example 
// by Sebastian Tomczak 
// 29 August 2011 

byte counter; 
byte CLOCK = 248; 
byte START = 250; 
byte CONTINUE = 251; 
byte STOP = 252; 
int x = -1;
unsigned long millisTime=0;
unsigned long  click1Time=0;  
unsigned long  click2Time=0;  
bool clickTime;
unsigned long beatTime=0;  

void setup() {  
Serial.begin(31250); 
pinMode(13, OUTPUT); 
digitalWrite(13, HIGH); 
usbMIDI.setHandleRealTimeSystem(RealTimeSystem); 
} 

void loop() { 
  
delay(50);
usbMIDI.read(); 

millisTime = millis();  
 
click2Time-click1Time==beatTime;
Serial.print(clickTime);
Serial.print(" ");

if (clickTime==true) click1Time=millisTime;
if (clickTime==false) {
   millisTime-click1Time==beatTime;
   Serial.print(" click1Time: ");
   Serial.print(click1Time);
   Serial.print(" millis Time: ");
   Serial.println(millisTime);
}
} 

void RealTimeSystem(byte realtimebyte) { 
  
unsigned long millisTime;

if(realtimebyte == 248) { 
counter++; 

if(counter == 23) { 
digitalWrite(13, LOW); 
usbMIDI.sendNoteOff(64, 100, 1);
clickTime=false;
} 
if(counter == 24) { 
counter = 0; 
usbMIDI.sendNoteOn(61, 100, 1); 
clickTime=true;
} 
if(counter == 12) {  
} 

if(counter == 11) { 
digitalWrite(13, HIGH); 
Serial.println("HIGH");
} 
} 

if(realtimebyte == START || realtimebyte == CONTINUE) { 
counter = 0; 
digitalWrite(13, HIGH); 
Serial.println("START");
} 

if(realtimebyte == STOP) { 
digitalWrite(13, LOW); 
Serial.println("STOP");
  
} 
}

So far I can send midi notes and flash the led on/off along with the Ableton bpm. However, and I think this is simply because of my little knowledge when it comes to programming, I cannot extract the time interval from those events to then calculate a bpm. I am not sure why, but when I set click1time=millis in the lower functions, i dont get anything in the main loop... rookie mistake?
I would be very thankful if someone could give me some advice on how to extract the time difference between clicks in the main loop, it really shouldn't be so difficult, right?

Generally, would it not be very useful to add a bpm read function for the main DAWs to the teensy library, not just a clock, but a bpm serial read-out, (Ableton, Cubase, etc)? Everybody I know working with teensy as a midi controller (..three people haha..) runs into that problem at some point, and it seems like such a basic thing for anybody working with arpeggiators, controls, etc.

As usual, thank you in advance!
 
Code:
click2Time-click1Time==beatTime;
should be:
Code:
click2Time-click1Time=beatTime;

There are other instances of this in your code. The == operator is a comparison not an assignment
 
In C - click2Time-click1Time=beatTime; isn't an assignment - but a compile error.

perhaps this:
Code:
beatTime = click2Time-click1Time;
...
// and
...
beatTime = millisTime-click1Time;
 
hahaha, you and me both!
sorry, i was pretty tired when I posted (still am actually).
stupid coding mistake, for sure, the problem is however, that somehow I cannot get the serial data from those counter functions after void loop,
even just to read out the time.

so for this:
Code:
// originally, Teensyduino MIDI Beat Clock Example 
// by Sebastian Tomczak 
// 29 August 2011 

byte counter; 
byte CLOCK = 248; 
byte START = 250; 
byte CONTINUE = 251; 
byte STOP = 252; 
int x = -1;
unsigned long millisTime=0;
unsigned long  click1Time=0;  
unsigned long  click2Time=0;  
bool clickTime;
unsigned long beatTime=0;  

void setup() {  
Serial.begin(31250); 
pinMode(13, OUTPUT); 
digitalWrite(13, HIGH); 
usbMIDI.setHandleRealTimeSystem(RealTimeSystem); 
} 

void loop() { 
  
delay(50);
usbMIDI.read(); 

millisTime = millis();  

if (clickTime==true) click1Time=millisTime;
if (clickTime==false) {
   click2Time=millisTime;
   beatTime=click2Time-click1Time;
   Serial.print(" click1Time: ");
   Serial.print(click1Time);
   Serial.print(" click2Time: ");
   Serial.print(click2Time);
   Serial.print(" beatTime: ");
   Serial.print(beatTime);
   Serial.print(" millis Time: ");
   Serial.println(millisTime);
}
} 

void RealTimeSystem(byte realtimebyte) { 
  
unsigned long millisTime;

if(realtimebyte == 248) { 
counter++; 

if(counter == 23) { 
digitalWrite(13, LOW); 
usbMIDI.sendNoteOff(64, 100, 1);
clickTime=false;

/*click2Time=millisTime;
   beatTime=click2Time-click1Time;
   Serial.print(" click1Time: ");
   Serial.print(click1Time);
   Serial.print(" click2Time: ");
   Serial.print(click2Time);
   Serial.print(" beatTime: ");
   Serial.print(beatTime);
   Serial.print(" millis Time: ");
   Serial.println(millisTime); */
} 
if(counter == 24) { 
counter = 0; 
} 
if(counter == 12) {  
} 

if(counter == 11) { 
usbMIDI.sendNoteOn(61, 100, 1); 
digitalWrite(13, HIGH); 
Serial.println("HIGH");
clickTime=true;
//click1Time=millisTime;
} 
} 

if(realtimebyte == START || realtimebyte == CONTINUE) { 
counter = 0; 
digitalWrite(13, HIGH); 
Serial.println("START");
} 

if(realtimebyte == STOP) { 
digitalWrite(13, LOW); 
Serial.println("STOP");
  
} 
}

the serial give me this:
Code:
 click1Time: 0 click2Time: 7359 beatTime: 7359 millis Time: 7359
 click1Time: 0 click2Time: 7409 beatTime: 7409 millis Time: 7409
 click1Time: 0 click2Time: 7459 beatTime: 7459 millis Time: 7459
 click1Time: 0 click2Time: 7509 beatTime: 7509 millis Time: 7509
 click1Time: 0 click2Time: 7559 beatTime: 7559 millis Time: 7559
 click1Time: 0 click2Time: 7609 beatTime: 7609 millis Time: 7609
 click1Time: 0 click2Time: 7659 beatTime: 7659 millis Time: 7659
 click1Time: 0 click2Time: 7709 beatTime: 7709 millis Time: 7709
 click1Time: 0 click2Time: 7759 beatTime: 7759 millis Time: 7759
 click1Time: 0 click2Time: 7809 beatTime: 7809 millis Time: 7809
 click1Time: 0 click2Time: 7859 beatTime: 7859 millis Time: 7859
 click1Time: 0 click2Time: 7909 beatTime: 7909 millis Time: 7909
 click1Time: 0 click2Time: 7959 beatTime: 7959 millis Time: 7959
 click1Time: 0 click2Time: 8009 beatTime: 8009 millis Time: 8009
 click1Time: 0 click2Time: 8059 beatTime: 8059 millis Time: 8059
 click1Time: 0 click2Time: 8109 beatTime: 8109 millis Time: 8109
 click1Time: 0 click2Time: 8159 beatTime: 8159 millis Time: 8159
 click1Time: 0 click2Time: 8209 beatTime: 8209 millis Time: 8209
 click1Time: 0 click2Time: 8259 beatTime: 8259 millis Time: 8259
 click1Time: 0 click2Time: 8309 beatTime: 8309 millis Time: 8309
 click1Time: 0 click2Time: 8359 beatTime: 8359 millis Time: 8359
 click1Time: 0 click2Time: 8409 beatTime: 8409 millis Time: 8409
 click1Time: 0 click2Time: 8459 beatTime: 8459 millis Time: 8459
 click1Time: 0 click2Time: 8509 beatTime: 8509 millis Time: 8509
 click1Time: 0 click2Time: 8559 beatTime: 8559 millis Time: 8559
 click1Time: 0 click2Time: 8609 beatTime: 8609 millis Time: 8609


so even though counter 11 does stop the led from glowing, and it also sends a midi on note message sucessfully,
it doesnt send serial, nor does it set clickTime to true (which should then send a rising click1Time value in the main loop.
do you understand what I mean?

going to get coffee now.

ps: the bracket in parts are just alternative versions, which also dont function, i just wanted to check if the problem was that the serial sends didnt work and maybe work around that by using a bool change and get the respective millis times in the main loop instead.
im probably just misusing/not understanding the counter functions imo..
 
Last edited:
You might be interested to know I'm developing a mackie huipro compatible transport framework. It's working well, bpm calculation is something I'll need to include ultimately.

When the time is right I intend to submit a pull request to add it to the teensy usbMidi library; this will make my code lighter in the sketch. It might be a while though - and all I need for my current project is BPM flashing.

Don't hold your breath - it won't help your challenge here.

Edit:"framework" might be a little strong. It's a collection of note defines and accompanying procedures and functions to make it easy to achieve, along with examples, and setup instructions.
 
Last edited:
hey again,

@pensive: sounds great! you probably already have the code, but if not the code above does give you the clicks. :)

so, i havent made any progress so far.. i really just need to be able to get a millis measurement from the if(counter etc..) function into the main loop,
the main void loop doesnt register measurement in those functions, so i cannot subtract the two events from each other to calculate the bpm according to the time events.
ideally i would prefer to read the bpm directly from abletong, but even measuring it from the clock events would be very helpful.. does anybody have any ideas?
did i explain the problem clearly?
thanks!
 
I think I've recovered from my embarrassment now :L

How about trying this in your main loop?
Code:
if(clickTime){Serial.println("HIGH");}

It's crude I know, but I'm not familiar with the MIDI library. This could actually be a bug
 
Last edited:
nope :( not working, but thanks anyways!

don't be too hard on yourself, a few years ago i tried to install a printer driver for my parents which didnt seem work and it took me about half an hour to realize
they hadnt plugged it in..
i wonder whats up with those counter functions though, cause i can send a midi note from the, and switch the led on, but i cannot send a serial, and i cannot register an event in them and use it in the main loop, weird no?
 
Most of my hard to solve issues aren't actually hard, I've just overlooked something I considered too simple :L

Ooop.

bool clickTime;
Should probably be
volatile bool clickTime;

It's certainly weird though yes.
 
nope... still nothing. looks like the bools arent changing in the functions click2 keeps counting, and click1 stays at 0
 
321lupo, perhaps something like the below would work. I used part of this code for ableton to send to multiple serial via Teensy. I have modified it to either send the value 248 to serial monitor if ableton is sending, or send a simple beat if no serial input. You can use this bp function as a basis for sending any value. You can change the value in the function by external inputs. I checked it on ableton just now and it either prints the ableton value, or sends a value to serial if not receiving. Not extensive testing though. As the code stands below, it won't do what you want completely, but it is a start to wards at least having the two work together.

Code:
byte counter; 
byte CLOCK = 248; 
byte START = 250; 
byte CONTINUE = 251; 
byte STOP = 252; 

long previousMillis = 0; 
long interval = 500;
int ledState = LOW;  

void setup() { 
Serial.begin(31250); 
pinMode(13, OUTPUT); 
digitalWrite(13, HIGH); 
usbMIDI.setHandleRealTimeSystem(RealTimeSystem); 
} 
int BPM;

void loop() {
usbMIDI.read(); 
if (usbMIDI.read()>1) {RealTimeSystem(BPM);}

else { 
myBPM();
}
}

void RealTimeSystem(byte realtimebyte) { 
//---------------if receiving from ableton-----------//
if(realtimebyte == 248) { 
  //Serial.write(248); //this for sending a clock byte
  Serial.println(248, DEC); // this is for reading in serial monitor debug
counter++; 
if(counter == 24) { 
counter = 0; 
digitalWrite(13, HIGH);}
 
if(counter == 12) { 
digitalWrite(13, LOW);} 
}
 
else if(realtimebyte == START || realtimebyte == CONTINUE) { 
counter = 0; 
digitalWrite(13, HIGH);}
 
else if(realtimebyte == STOP) { 
digitalWrite(13, LOW); }
}

void myBPM(){
    unsigned long currentMillis = millis();
    
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;  
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW; 
      digitalWrite(13, ledState);
Serial.write( 248);
}
}
 
Last edited:
hey mortonkopf, thanks, for the post!
i tried the code, but to be honest im not understanding it completely and i am not sure how it helps me recover the bpm since i dont really see the difference to the version i used before, at least in terms of my problem.
the serial gives me a "248" message in time with the ableton clock, but thats what i already had before too.

however, what i need is to print and save the exact ableton bpm value in the serial (as in ableton is running on 140 bpm, i want my serial to say we have 140 bpm, if i change it to 130bpm, i want my serial to say, oh, its 130bpm). so my idea is since i cannot seem to get the value of ableton directly, i could calculate it according to the clock, measure two time events according to the arduino clock, subtract them from each other, put that in an equation, and then calculate the exact bpm. i guess this is unusual since most people just want to sync their arpeggiators or drum machines with ableton, so they only need a click that follows the ableton bpm, but again, thats just a click, not the actual bpm. what i build is a gestural midi controller, so basically, when i move my arm or do a type of matrix move the bpm slows down (im using ableton loopers so there is an additional slow down sound-gets-lower vinyl effect so it detunes the loops down). now, when im done doing this and i deactivate the bpm manipulation i want ableton to jump back to the exact same bpm level before i activated the gestural ctrl change (so the loopers are back on the same exact speed and in tune with my external instruments otherwise the whole song is fucked up..). i tried to do this with sending ctrl-z redo message, which kind of works but of course easily messes things up if i do anything else meanwhile, like change other ctrl values. easiest thing would be if i could exactly control the ableton bpm. that doesnt seem to be possible (maybe with maxmsp but id like to keep it simple), so my thought was to calculate the exact bpm value according to the clock, save it, apply the ctrl change and once i deactivate the controller have it reset the bpm to the value before it started changing it, the loops go back into tune and i continue the song.

now this is my problem: i get the clicks, i get the sync and the clock works fine, but whenever i try to measure millis time points in those "counter"functions and use them in the main loops, i get nothing back from the variables. i would just like to have a simple: if (click of clock happens) set click1 to, if it clicks again, set click2, subtract from each other, whats the bpm right now, save that, etc. so, i dont understand, when i change bools in the lower functions, why dont they change when i check them back in the main loop as in the code i tried above? probably its just because of my very limited understanding of c++...

(maybe the solution is already in your code, and im just not getting it, in that case im sorry :) )
 
Last edited:
ah. The code I posted was only to show the switch between ableton generated (Teensy receiving) and Teensy sending (the if / else part), showing in a rudimentary way how both can be active. I will have a think about the measurement of bpm.
 
Yeah, well i will definitely save your code it for possible future use (if that is ok), but for now i just need to be able to measure the time interval between two successive clicks. I really dont get why i am having such a hard time doing that..
 
just a thought, cant test at the moment, but what about replacing if(realtimebyte == 248) { Serial.println(248, DEC); etc... in my code above, with something like:

if (realtimebyte == 248) {
firstmillis = previousmillis;
secondmillis = millis();
bpm = 60000 /(secondmillis – firstmillis);
previousmillis = secondmillis;
Serial.println(bpm, DEC);
...then the rest of the task....

of course, you need to add in "long firstmillis, secondmillis, previousmillis; int bpm;" earlier in the sketch. It would also need some averaging or smoothing
 
Hi

I'm assuming ableton can send clock on 'channel X', and receive and sync to clock 'simultaneously' on a different channel...if not I suppose there is a way to switch from ableton being the master to slave and back again ....

So what I think you want is a snapshot of ableton's clock in bpm (60 / (24 x 1clockpulseinseconds)) or even just store the 1clockpulseinseconds and store the clock just before you start to transmit teensy clock. At some future time when you have finished sending teensy clock (manipulated by your controller) , you send the stored clock, then start looking at ableton's clock, waiting to store and switch to teensy clock/controller.

So, you need to monitor the ableton clock, timing its pulses (or even you could just enter abletons bpms via serial monitor to teensy if it is not changing), and at a transition point (which could be a digital footswitch, or the start/finish of a data stream or maybe starting with a special gesture, and finishing with a special gesture) you stop with looking at the ableton clock and start sending your own clock via teensy. This requires an interface with your controller ... I'm not quite sure what that would look like.... (waves hands frantically) ...the interface takes your gesture data and converts it into 1clockpulseinseconds for teensy to send via the '248 serial command' (although I wonder if, at this stage it would be better to use a midi parameter control, like pitch shift, as you suggest ...)

Control is handed back to the 'ableton clock monitor' at the end of the 'controller interface / 248 serial command' block.

Am I on the right track??
 
hey, haha, i think so. maybe check "mi.mu gloves" to get a better idea, im doing something very similar. the point of my whole setup is that i can use ableton without having to be on the laptop or look at the monitor just by using my controllers, so there is no typing involved and i want to keep it that way. i dont think a master slave switch has to be done either since i control ableton's bpm simply by a mapped midi ctrl value, that is given by the accelerometer (0-127 to 76.50-140.00 bpm in ableton, so basically i can change the ableton bpm in 0.5bpm increments. i could send a pitch shifter message instead, but 0-127 is enough detail for me for now).

so, technically i dont really need any synching or clocking or any master-slave stuff, since my devices simply send midi notes. if i use any arpeggiators, they are vsts and receive their clocking directly from ableton anyways. i just thought that since i cannot read-out the bpm level directly (at least i think i cant) i could send a clocking from ableton and use the sync function on the teensy to calculate the bpm from the intervals, which seem to be reliable enough to do that. i dont have a lot of tempo changes so i would just use an average. once i want to change the speed of the song, i activate my glove or chest controller (imagine ironman without his suit, but the chest light is a drumpad with an accelerometer in it). the controller starts sending the bpm change ctrl value, ableton speeds up or slows down according to how i move, then i deactivate the midi send and want it to send the respective ctrl value which makes ableton jump back to the original bpm it had before i made the change. so, i think you got it pretty right, except that i do not use the teensy 248 command to send anything, that is done by the midi parameter control already anyways. all i need is to measure the time interval between those damn clicks and convert them into a bpm, save that, convert that into the right ctrl val and send it back to ableton once im done waving my hand frantically ahahaha :p

im sorry, i know a video would be much easier. i basically made a gestural midi interface like "onyx ashanti" or "imogen heap mi.mu", but do not use software on the laptop to interpret the controllers and convert to midi, but the teensys do that and send midi messages themselves. all good? i need a drink! :)

(again, ideally there would be no work around, but just a straight bpm read, but i read somewhere that ableton has made it difficult to read out all parameters easily. thats just hearsay of course.)
 
Last edited:
So all you need to do is read the ableton clock time just before you become iron man, and retransmit it via cc when you stop becoming ironman .. .... so ... when you get the ableton clock you use that as the base for you controller ... and the cc values just increment and decrement 120 + 1, 121 +1, or does it work 120 + 1, 120 + 2 ??? ... doesn't really matter I suppose ... when you finish, you send the old bpm back to ableton.

How about something like this...its going to be inaccurate because of latency (for example there is a serial.Print in there) and there is no averaging ... also it reads, effectively, every second pulse ...none of this is probably an issue for you, and removing serial.Print is going to help no end ...its off the top of my head, and using timers is a new thing for me, so the logic may well be faulty (almost certainly!!!) Just a sketch of an idea ... I'll test it on my setup later .... I'm pretty sure I have a sequencer that will send midiclock ...never used it myself.

Code:
bool clock = false;
bool prevlook = false;
bool controlleractive = false;
bool bpmsent = true;
int storedbpm = 0;
long int total = 0;
int count =0;

void RealTimeSystem(byte realtimebyte) {
  if (realtimebyte == 248 )
  {
    if (clock) {
      clock = false;
    }
    else {
      clock = true;
    }
  }
} // create a clock variable that swaps from high to low when a clock message is received

void ControllerActive (byte channel, byte note, byte velocity) {
  if (note == 64 )
  {
    if (controlleractive) {
      controlleractive = false;
    }
    else {
      controlleractive = true;
    }
  }
} /* if note 64 is sent, controller mode is activated, if 64 is sent again, controller mode is deactivated ... I guess its not coming on USB but I've written it that way!!*/

void setup() {
  Serial.begin(31250);
  usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
  usbMIDI.setHandleNoteOn(ControllerActive);
}

elapsedMillis bliptimer; //start a timer

void loop() {

  usbMIDI.read();

  if (!controlleractive) {
    //controlleractive is false, controller is inactive, so monitor the clock

    if (bpmsent == false) {
      /*transmit storedbpm to ableton*/ bpmsent = true;
    }
    // this is triggered after the controlleractive goes inactive .. It resets ableton to the storedbpm

    if (clock && (!prevlook)) {
      bliptimer = 0;
      prevlook = true;
    }
    //set timer to zero when positive high clock is first received (! no previous positive clock)

    if ((!clock) && prevlook) {
      total += bliptimer;
      count ++;
      prevlook = false;
    }
    // if clock goes low, and was previously high, store and print the bpm
     if (count == 240) {
      count = 0; storedbpm = 600000 / total; total = 0;
      Serial.println (storedbpm);
    }
  }
  else  {
    // controller active is true ..no more clock watching ... time to send CC data to ableton

    if (bpmsent == true) {
      bpmsent = false; //reset flag so that when it goes inactive the previously stored bpm is transmitted (above)
    }

    /* CC controller routine  ...use storedbpm to send CCinfo to ableton (and preserve bpm)  .... active until controlleractive is falsified through noteon 64 event, then previously stored bpm is transmitted (above)*/
  }
}
 
Last edited:
So I tested the code above in #20 and it works after a fashion ... The serial monitor output tracks the bpm, but unless it is a really low bpm (like 50 or less) its quite inaccurate ...

I suppose I am 'serialprinting' the bpm each blip, so at high bpm, there is a lot of serial print action .... I tried adding up every 24 blips and then printing, but that didn't really help accuracy at high bpms ...so I suspect the base problem is the accuracy of my sequencer's clock at high bpm ... I'm pretty sure that the teensy can clock at midi serial speeds....

I will muck around some more .... give it a try at low bpm and tell me how you go...

Edit: I wonder if in addition to the near certainty that my sequencer clok is inaccurate whether there are usb / serial interrupt type issues at high bpm (but I worked it out to be around 50hz clock for 120bpm 24 blips in .5 of a second!!).... could serialprint be a queering factor along with usb type things which I don't have a clue about at that speed???.... will look at it further.
 
Last edited:
Another 10 minutes... another post ... So I have updated the code in #20... I shifted the serial print, and 'analysed' the clock (and printed/stored) over a much longer period ... 20 beats instead of 1/24 of a beat ... and I'm getting a pretty accurate serialprint of the sequencer's bpm ... (that is, accurate for my sequencer, setup and midiclock generally) ... about +- 2% at higher bpms... As good as others have reported on my platform.

....

Yay! Photies ... one at 120bpm, the other at the correct speed for rock and roll ... 180bpm
120bpm.jpg180bpm.jpg
 
Last edited:
great. I have also got bpm printing to serial, but using a very simple mills loop. The code below also allows for teensy automatically sending beat to ableton if nothing being received from ableton. The serial monitor bpm read out is spot on the value if a small averaging is added. Take your pick:

Code:
byte counter; 
byte CLOCK = 248; 
byte START = 250; 
byte CONTINUE = 251; 
byte STOP = 252; 

long previousMillis = 0; 
long interval = 500;
int ledState = LOW;  

void setup() { 
Serial.begin(31250); 
pinMode(13, OUTPUT); 
digitalWrite(13, HIGH); 
usbMIDI.setHandleRealTimeSystem(RealTimeSystem); 
} 
int BPM;
unsigned long firstmillis, secondmillis, previousmillis, diff; 
int bpm;
unsigned long timing = 60000;

void loop() {
usbMIDI.read(); 
if (usbMIDI.read()>1) {RealTimeSystem(BPM);}

else { 
myBPM();
}
}

void RealTimeSystem(byte realtimebyte) { 
//---------------if receiving from ableton-----------//
if(realtimebyte == 248) { 
                firstmillis = previousmillis;
                secondmillis = millis();
                diff = (secondmillis-firstmillis);
                bpm = ((timing / diff)/24);
                previousmillis = secondmillis;
                Serial.println(bpm, DEC);
  
counter++; 
if(counter == 24) { 
counter = 0; 
digitalWrite(13, HIGH);}
 
if(counter == 12) { 
digitalWrite(13, LOW);} 
}
 
else if(realtimebyte == START || realtimebyte == CONTINUE) { 
counter = 0; 
digitalWrite(13, HIGH);}
 
else if(realtimebyte == STOP) { 
digitalWrite(13, LOW); }
}

void myBPM(){
    unsigned long currentMillis = millis();
    
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;  
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW; 
      digitalWrite(13, ledState);
Serial.write(248 );
}
}
 
In search of a better mousetrap, and thinking about mortonkopf's nice clean code, I thought, since we are looking at a span, not each individual clock tick ... "count then time, not time then count" ...

The following code is totally accurate on my setup, up to 180bpm! There is a place in it for your CC timechange to ableton (I assume u are using teensy as your usb midi interface), and the code has a place in it for storing abletons bpm, switching to controller, then ...when switching back ...sending the stored 'pre-controller' bpm back to ableton

The code looks at a span of 10 beats ... maybe less could be used, so the program responds better to bpm changes ... it takes 5 or so seconds for the bpm change to register correctly... I tried 1 beat and the accuracy was pretty bad...almost as bad as looking at individual clock ticks

enjoy

Code:
bool controlleractive = false;
bool bpmsent = true;
int storedbpm = 0;
int count = 0;

void RealTimeSystem(byte realtimebyte) {
  if (realtimebyte == 248 )
  {
    count++;
  }
}

void ControllerActive (byte channel, byte note, byte velocity) {
  if (note == 64 )
  {
    if (controlleractive) {
      controlleractive = false;
    }
    else {
      controlleractive = true;
    }
  }
} /* if note 64 is sent, controller mode is activated, if 64 is sent again, controller mode is deactivated ... I guess its not coming on USB but I've written it that way!!*/

void setup() {
  Serial.begin(31250);
  usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
  usbMIDI.setHandleNoteOn(ControllerActive);
}

elapsedMillis bliptimer; //start a timer

void loop() {

  usbMIDI.read();

  if (!controlleractive) {
    //monitor clock count not controller
    if (bpmsent == false) {
      /*code to transmit storedbpm to ableton*/ bpmsent = true;
    }
    if (count == 239) {
      count = 0; storedbpm = 600000 / (bliptimer); bliptimer = 0;
      Serial.println (storedbpm);
    }
  }
  else  {
    // monitor controller, not clock count
    if (bpmsent == true) {
      bpmsent = false; //reset flag so that when it goes inactive the previously stored bpm is transmitted (above)
    }
    /* CC controller routine  ...use storedbpm to send CCinfo to ableton (and preserve bpm)  .... active until controlleractive is falsified through noteon 64 event, then previously stored bpm is transmitted (above)*/
  }
}
 
Hey i was looking at the ableton manual and i see that it can send parameter feedback for mapped parameters, meaning if you can map bpm, you should be able to get direct bpm feedback ...i don't know if you can map bpm, though ... maybe worth looking at?

Edit: it looks like you can map bpm in ableton, so all you need to do is turn on parameter feedback, read it, and store abletons bpm before you go into 'suit mode', and send it when you come out of suit mode ... you don't need to use the clock to extract the bpm, by the looks ...
 
Last edited:
Status
Not open for further replies.
Back
Top