Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync to external Eurorack trigger #40

Open
carlosedp opened this issue Jul 22, 2024 · 15 comments
Open

Sync to external Eurorack trigger #40

carlosedp opened this issue Jul 22, 2024 · 15 comments

Comments

@carlosedp
Copy link

Hi, I'm writing an Eurorack module for clock generation and division and wonder if I can sync my module that uses uClock to an external trigger coming from another Eurorack module.

The input trigger is usually a square wave from another oscillator or LFO (not MIDI).

Can I use the uClock.clockMe() for this? Any tips?

Thanks!

@midilab
Copy link
Owner

midilab commented Jul 23, 2024

Hi @carlosedp,

Yes it is possible to sync to external clock. one of the uclock main features is the phase lock mechanism to keep a good and solid internal clock based on external one.

uClock.clockMe() should be called at each low or high state of you square wave depending of the rise/fall style of your clock signal.

Rigth now the expected clock is 24PPQN, we have a TODO list to include the option to change expected external clock too.

But for now if you have any external clock different from 24PPQN you need to handle it on your code. For example: if you have a 48PPQN input clock, you should trigger uclock.clockMe() each second tick.

A code example

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

and a thread about the subject:
#37

If you external clock is 24PPQN than you only need to call uClock.clockMe() each external signal rise or fall.

@carlosedp
Copy link
Author

Got it but I think in my case it's kinda the opposite... I need to generate a 24PPQN from a single pulse (can I call it 1 PPQN?)... right?
Is this viable or precise?

@midilab
Copy link
Owner

midilab commented Jul 23, 2024

i dont think it exist such of 1PPQN resolution. Most eurorack modules are based on 48PPQN or 24PPQN, if it is a simple LFO that you have, there is no resolution at all, it is only a signal that you will try to sync to.

My suggestion is that you try it first uClock.clockMe() at each signal input LOW or HIGH(choose one of those only), and check it how it behaves, for clock generation. After that, just adjust the clock output to sane levels based on your LFO input(example: maybe the middle of your LFO time knob should be something like 140BPM output? then try to find how many signals to count before trigger uclock.clockMe())

Since a LFO is not PPQN sync based, you will need to find the ideal sync count that fits you purpose. To find the ideal clock count, try different values of CLOCK_COUNTER incrementing from 2 to 20 or more.... until you find the ideal value.

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

Mabe you can start with the example:
https://github.com/midilab/uClock/blob/main/examples/GenericMasterOrExternalSync/GenericMasterOrExternalSync.ino

your clock output will be done inside onSync24Callback function based on bellow example(wich outputs at 24PPQN resolution)

The example is doing clockMe() inside loop() function, but ideally you should use interruption linked to your clock input PIN instead of doing inside loop().

@houtson
Copy link

houtson commented Sep 22, 2024

I think the OP is looking for a 'tap tempo' style of input, with a trigger per step/quarter note.

@houtson
Copy link

houtson commented Sep 22, 2024

But for now if you have any external clock different from 24PPQN you need to handle it on your code. For example: if you have a 48PPQN input clock, you should trigger uclock.clockMe() each second tick.

Thanks for the 48PPQN example, I'll use that for syncing with old Korg DINSYNC synths.

Cheers Paul

@carlosedp
Copy link
Author

That's exactly what @houtson mentioned... suppose I want to sync my module that uses uClock with MI Marbles T2 output for example... it would output 120BPM in the middle position... if I connect it to my module's INPUT that triggers the clockMe function, it wouldn't work since it expects 24PPQN which would be 24x Marbles output.

Is there any way to make the clockMe set the input PPQN for the sync signal?

@midilab
Copy link
Owner

midilab commented Nov 17, 2024

The library needs a new feature to set the resolution of clock sync input signal other than 24ppqn, its on the TODO list.

If the resolution is higher you can div your clock like 48ppqn with div = 2. but in your case where the resolution is lowerw than the uClock base resolution nothing can be done with uClock.clockMe() to solve it on current version.

@doctea starts some code on tap tempo feature wich can leads to another way of doing what you need.

But the ideal feature would be to set PPQN input resolution, just as we have on current version of uClock a set PPQN for output. Also some setMultiplier and setDivider functions would be nice to add on input and output of uClock signal.

@IC-Alchemy
Copy link

IC-Alchemy commented Dec 10, 2024

@carlosedp

Marbles is a confusing example so my answer below assumes you are asking about generating a MIDI clock from a typical eurorack module.
image

I need to generate a 24PPQN from a single pulse (can I call it 1 PPQN?)... right?

24 PPQN describes timing resolution used for MIDI clock.

I think of PPQN like Frames Per Second (FPS)

FPS is the number of individual images (frames) displayed each second.
PPQN is the number of pulses used to represent one beat (specifically, a quarter note) in music

Higher PPQN means the musical timing is divided into more parts, allowing for finer placement of notes and rhythms.

For example Ableton uses 960PPQN which is a high enough resolution where you can come close to any swing imaginable.

@carlosedp
Copy link
Author

Yea, I know... :) When I mean 1PPQN I mean imagine syncing the library to an LFO with a square wave outputting pulses every second (60BPM) ... the idea is that while pretty unstable, this pulse train would drive the clock at 60BPM too.

I think Pamela's workout has a setting where you can set the input PPQN for the output clock where the default is 24PPQN but it can go as low as 1PPQN.

Check this part of the video: https://youtu.be/mkoVfQq7m8Y?t=285

@IC-Alchemy
Copy link

IC-Alchemy commented Dec 14, 2024

I've made tons of devices that move forward one step on each rising edge trigger.
This can be done with out any clock at all, and without keeping track of time.

if (risingEdge)
    step++; 

For this to be synced with uClock,
so that you could output a midi clock that is synced with your LFO for example,
you'd have to decide what note value you want to assign to each step.

This won't work if you think of an LFO as being 1PPQN

The standard sequencer defaults to 16th notes, like on a TB303.

Each 16th note consists of 6PPQN, assuming your clock is MIDI at 24PPQN

If you don't plan on outputting multiple synd'd signals there are a ton of advantages of not using any clock at all and just moving forward one step like you mention.

I call this "time agnostic" but I think I just made that up.

A time agnostic sequencer automatically locks perfectly to what ever you send it, including swing, tempo changes, randomness etc...

@midilab
Copy link
Owner

midilab commented Feb 16, 2025

Hi @carlosedp, @houtson, @IC-Alchemy, and @doctea,

I've added an experimental feature that allows setting the input sync clock for different PPQN resolutions. This is currently untested, so I'm reaching out to gather feedback from you all.

The feature is implemented using setClockPPQN(PPQNResolution resolution) method.

uClock.setClockPPQN(uClock.PPQN_4);

This sets the resolution to 4 PPQN (Pulses Per Quarter Note), meaning each pulse corresponds to one step. For reference, here are the available PPQN resolutions in an extended list:

enum PPQNResolution {
    PPQN_4 = 4,
    PPQN_8 = 8,
    PPQN_12 = 12,
    PPQN_24 = 24,
    PPQN_48 = 48,
    PPQN_96 = 96,
    PPQN_384 = 384,
    PPQN_480 = 480,
    PPQN_960 = 960
};

So why 4PPQN?
Most analog sequencers send out a pulse every 16th note which equals 4PPQN. So probrably is what you'll need for eurorack modules @carlosedp

Please note that while this code compiles and the logic appears sound on paper, it hasn't been thoroughly tested yet. I'm especially interested in hearing from anyone who has tried using this feature or encountered any issues with it.

This way we can have higher resolution clock running internally(good for groove/shuffle stuff) and and keep on sync with external lower resolution clocks.

There is a nice read about some different machines and their clock setups:
https://djjondent.blogspot.com/2020/06/modular-clocks-analog-midi.html

If it happens that your sequencer is 2ppqn or 1ppqn i will need to rethink about the code on develop branch... since for now only 4ppqn minimun supported. Anyway, i will try to review and implement 1ppqn and 2ppqn too asap.

Some know machines that operates with sync at 1ppqn and 2ppqn according to the link reference: DOEPFER DARK TIME, Korg SQ-10, Euro - Zularic Repetitor, (Noise Engineering), Erica Pico Seq & Pico trigger , Delptronics Triggerman, Disting Mk3 & 4, Modcan Touch Sequencer (ext sync), KORG (SQ-1), Volcas, Teenage Engineering Pocket Operators (POs sync on audio pulses, essentially a click track).

Thank you in advance for your feedback and insights.

Best regards,

@carlosedp
Copy link
Author

That's awesome! I'm currently on vacation and will return next week, then I will take a look and play with it!
Thanks! Seems promising!

@carlosedp
Copy link
Author

TE OP-Z also works at 2PPQN and for example if there's a need to sync to a square LFO or Marbles T2 output, 1PPQN would be needed...

@IC-Alchemy
Copy link

Awesome I'm gonna try it later today most likely.
The type of sequencers that increment one step for each trigger don't even think about PPQN, it is fairly easy to design a sequencer that simple steps forward on each trigger. No need to even consider time at all, so I call them "time agnostic" but I think "analog clock input" would be the language that the most people understand.

I'm gonna try and use the analog clock input (4PPQN) along with a faster clock + swing at the same time.

@midilab
Copy link
Owner

midilab commented Mar 25, 2025

I have time to test and fix a little error on clock input new schema. now should be working as expected.

i also have added Sync callbacks set other than 24PPQN: 1PPQN, 2PPQN, 4PPQN, 8PPQN, 12PPQN and 48PPQN and can be set via setOnSyncXX() function, that way will be easier to setup more complex clocking outputs(one or more clock outputs at a time) to control your setup with multiple clock time signatures when uClock is the master clock.

still no clock input sync for 1PPQN and 2PPQN... i will investigate the implementation of it soon...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants