midilab / uClock

A tight BPM clock generator for Arduino and PlatformIO using hardware timer interruption. AVR, Teensy, STM32xx, ESP32 and RP2040 support
https://midilab.co/umodular
MIT License
164 stars 22 forks source link

Sync with external PPQN_48 will give double BPM on uClock.setOnSync24 with setPPQN(uClock.PPQN_48) #37

Closed underwoodblog closed 7 months ago

underwoodblog commented 7 months ago

As the title says, I have an external PPQN_48 signal that I try to convert to midi clock. It seems the uClock.setOnSync24 is called on every tick and not in sync to PPQN_48. Do I get the documentation wrong? With external signal set to 24 ppq bpm is in sync, with 48ppq I get double bpm. Here my code:

In setup:

  uClock.init();                              // init uClock first
  uClock.setPPQN(uClock.PPQN_48);             // internat ppq setting
  uClock.setMode(uClock.EXTERNAL_CLOCK);      // sync to external clock source
  uClock.setOnSync24(onSync24Callback);       // calback on 24ppq for midi out
  uClock.start();                             // uClock start

callback ans sync function via IRQ

void ppqInterrupt() { // IRSR to sync uclock to FALLING edge on input pin
  uClock.clockMe();   // sync
}                     // end

void onSync24Callback(uint32_t tick) { // midi clock out on ppqn24
  mySerial.write(MIDI_CLOCK);          // MIDI clock byte definitions
  digitalWrite(13, HIGH);              // LED on
}                                      // end
midilab commented 7 months ago

Hi @underwoodblog ,

The uClock.setPPQN() is only used for internal ticking system setup, and that will reflects only on callback set at uClock.setOnPPQN() ( the main ticking callback, is separated from Sync callback signals ).

The onSync24Callback is always pulsing at 24ppqn no matter what internal ticking you choose.

I realize i didn't documented that but the external sync is waiting a 24ppqn on uClock.clockMe(), its on TODO list to extend the PPQN setup for external clock too, so you can use it with other external clocks like 48PPQN, but for now we only accept 24ppqn as clock source and onSync24Callback will always ticking at 24PPQN(where most MIDI devices rely on).

One thing that you could do is to count 2 PPQN48 pulses to then call one uClock.clockMe() as a way around until we have the extended setup for external PPQN sync on uClock.clockMe().

For that matter you can keep internal 96PPQN(no need to setup uClock.setPPQN(uClock.PPQN_48)), and just count 2 pulses on ppqInterrupt() to triger a 24PPQN clock. That way your midi setup will be good to go on onSync24Callback()

something like this should solve(not tested! just a idea):

uint8_t clockDiv48Trig = 0;
void ppqInterrupt() {
  if (clockDiv48Trig == 0 || clockDiv48Trig % 2 == 0) {
    uClock.clockMe();
  }
  ++clockDiv48Trig;
}