norns: clock

hope all’s well :slight_smile:

1-300bpm is the supported range — lmk if there was a cc2 issue tho in the thread and i’ll take a peek!

1 Like

Are there any big things to avoid when working with clock coroutines? I am trying to use clock.sync to synchronize 2 pattern_time patterns. Everything works fine if I’m only using one of the patterns in clock-synced mode, i.e. only one clock coroutine running at a time, but as soon as I try to use both synced to the clock (2 clock coroutines running at once) I get some very strange behavior.

I do have both patterns stored in a table, and the coroutines both access the table to modify(record/start/etc) a pattern at index n, but both should be accessing different indices and different patterns.

maybe share the code? sorry i don’t quite get it.

… actually that’s ok, it’s enough i think. i’ll try and reproduce or make a working example.

Here’s the code: orison/orison.lua at 51f95423debb6d1222dc895bd95e9b15646b5793 · evannjohnson/orison · GitHub

It’s quite messy, and I’ll try to make a distilled version to illustrate what I’m talking about. There’s a table called “patterns”, indices 1 and 2 store tables with a pattern and a couple state variables, such that you can access pattern n with “patterns[n].pattern”.

All the clock synced stuff happens in record_start_sync(), record_stop_sync(), start_sync(), stop_sync(), and reset_sync(). All but reset_sync are started in g.key. Reset_sync is started by a special event I put near the end of the patterns, it is started at the top of pattern_note().

The gist of the script is that columns 2-16 is a grid of notes you can play, column 1 is control functions, (1,3) controls pattern 1, (1,4) controls pattern 2. Holding (1,7) while pressing a pattern button clears that pattern starts recording unsynced, pressing the pattern button again stops recording and then controls stopping/starting. Holding (1,6) while pressing a pattern button does the same, but synced to the clock. You can toggle the grid flashing to the clock by pressing key2 on norns while holding (1,7).

Feel free to wait for me to give you a distilled example, my code is pretty rough.

… here’s an example of two parallel clock-driven sequences. one is a steady 16th note and the other steps between a few different sync divisions in sequence.

… does that help at all?


as far as race conditions…

well, our lua VM is single threaded, the question is can we guarantee an order of execution for clock routines that are sync’d to the same beat. that’s a good question; i’ll take a quick look and see if there is an obvious answer.

for now best, to assume that you can’t and try and avoid the possibility of race conditions. (i mean once you get into any sort of complex rhythmic relationship you probably want to assume this anyway.)

so, on the other side of it i will make a brief attempt to grok your script’s management of runtime state. we’ll see.

going on your general description - it seems fine for multiple clock threads to mutate different fields in a table. it might be a generally bad idea to have both threads adding or removing elements in the same table, but even then it depends on the method - there are ways to make it safe.

4 Likes

Thanks for your help - I guess I should finally start making some diagrams so that I can fully grok the script’s management of runtime state…

This is the kind of stuff that was in the last CS course I took, and failed. Time to dig back into it I guess :sweat_smile:

1 Like

ah well, i didn’t mean anything complicated and probably phrased that badly.

so far i haven’t spotted anything obviously scary. ah, well ok, i am skeptical of / would investigate if/how pattern_reset_sync(n) and one or more pattern_*_start_sync(n) are interacting when they run simultaneously with the same n. that seems like it coud easily become hard to predict.

but, i guess you said it’s working with only one pattern… so, sorry - nothing obvious (assuming the ns really are distinct and really are getting passed on to the clock update functions correctly.)

like ok, here’s my dummy check: add print statements (print n in each coro, print the returned id of each coro) to make triple sure that the ns are distinct. (who knows, we could have some bug in the way the clock wrappers handle varargs or something.)

1 Like

I’ve added the print statements: orison/orison.lua at b56b0ddd0708860a1dbcd41a5e1735064ff13d25 · evannjohnson/orison · GitHub

There’s some kind of mixup happening with the patterns, but I’m pretty sure n is being properly passed to all functions. Here’s a sample of the output:

encountered syncer event for pattern 1
pattern reset sync1
742
encountered syncer event for pattern 1
pattern reset sync1
743
pattern_time: not playing
pattern rec start sync2
pattern_time: not playing
744
encountered syncer event for pattern 1
pattern reset sync1
745
pattern rec start
pat2.rec
0
encountered syncer event for pattern 1
pattern reset sync1
746
encountered syncer event for pattern 1
pattern reset sync1
747
encountered syncer event for pattern 1
pattern reset sync1
748
encountered syncer event for pattern 1
pattern reset sync1
749
encountered syncer event for pattern 1
pattern reset sync1
750
pat1.rec
1

Pattern 1 was playing synced, you can see the syncer event being processed. Then I attempt to start recording pattern 2 synced, and it does print pattern rec start sync2, so it’s getting the correct n. You can then see further down that pattern_time has printed pattern rec start, on beat. But, pat2.rec = 0 and pat1.rec = 1, so something has gone wrong here, despite pattern_record_start_sync correctly being passed 2. I can’t figure out why.
̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶ ̶
I got it working. First tried moving all variables out of the table to eliminate weirdness from 2 coroutines accessing the table at the same time. That didn’t work, the pattern_sync functions would still cause weirdness when being run at the same time. So I made separate sync functions for the patterns, to try and divorce the flow of execution (am I using that term right?) for the coroutines as much as possible. And now it seems to be working as intended.

It feels pretty clumsy, but it’ll have to do until I better understand coroutines.

Here’s the working code: orison/orison.lua at d995ec527f93c55ec94ca1c71571a7f9adcbc642 · evannjohnson/orison · GitHub

apologies if there’s a better place to find this, but: has anyone had luck sending clock from norns to Logic Pro X? The following steps aren’t working for me:

  1. Set norns clock to source: internal, whatever tempo. Set norns clock midi out to e.g. port 1
  2. Open up Logic Pro X, and in File > Project Settings > Synchronization, try Sync Mode: MTC. Also go to “MIDI” and turn on “Listen to MIDI Machine Control (MMC) Input”, just for kicks.

Logic does not seem to receive norns’ tempo or transport messages with these settings

hihi!

i think Logic doesn’t receive sync from anything unless it’s MTC (MIDI Time Code), which norns doesn’t currently transmit. seems like for regular MIDI clock devices, Logic needs to be the ‘central transmitting device’: Sync multiple MIDI devices to Logic Pro - Apple Support :confused:

edit: maybe there’s a way to send pulses to Logic’s Tempo Interpreter?
seems like the ‘tap tempo’ command is just a keyboard shortcut. weiiiird.

2 Likes

I’m very new to norns and trying to get an overview of the current sync options. Is the idea of having a global synced transport still alive – or a long term plan? Until then: are there any sequencer apps with synced start/stop when setting the global clock to Ableton Link?

1 Like

norns supports transport sync on the API level, but doesn’t enforce scripts to support it, given that different scripts can have very different ways of following time and user input.

for instance, some scripts will trigger sample playback when a button on the grid is pressed, so there will be no notion of “transport start” in such script completely.

i am not using any scripts synced to transport myself, but i am sure some of them do it.

3 Likes

I’d bet most norns sequencers do. I know Cyrene: a drum sequencer based on Mutable Instruments Grids does

I’m a bit confused about how the tempo set in the the Parameter > Clock menu can be applied to an actual clock.

This is my basic setup:

function init()

    -- Master sequencer step clock
    master_clock_id = clock.run(master_clock)

end -- End init

function master_clock()
  while true do
    clock.sync(1/4)
    pattern_generator.do_master_step()
    --print(clock.get_beat_sec())
    print(clock.get_tempo(master_clock))
  end
end

However, when I change the tempo in the menu, it still reports 90.0 bpm, and the rate at which my step function gets called doesn’t seem to vary.

I notice some other scripts use the Norns Clock system, but, have their own tempo display in the UI, and changes here don’t seem to be reflected in the Menu, either.

I’d ideally like to have the tempo set only in the Menu.

I have Clock Source set to “internal”, incidentally.

there’s an unrelated mistake in this line:

print(clock.get_tempo(master_clock))

since get_tempo doesn’t require any arguments, there’s no need to pass the parent function or anything to it.

otherwise, the snippet works fine for me. is the clock source set to internal?

1 Like

Thanks for getting back to me, @artfwo.

That’s strange. It was definitely not working for me. I wonder if it’s a Fates thing. I’m developing on a Fates, with the latest available Norns.

I’m pretty sure it was. The clock was running, and there wasn’t any other source for it, I don’t think.

I will investigate further when I’m back home.

it shouldn’t be - as this part of the software is not any different on the Fates hardware.

1 Like

I’m still not getting this to work, unfortunately. Is there something else I need to do, to get the tempo of the master clock to respond to the setting in the Clock menu?

Changes to the tempo in the menu seem to have literally no effect either on the reported tempo nor the rate at which the master_clock() function gets executed.

I notice clock settings aren’t getting saved into a preset for the script. I don’t know if those is expected behaviour or is related to the clock issue.

hi hi! hope all’s well :slight_smile:

super strange to see this persist – here’s a quick + dirty ‘it works’ script based on your code above:

function init()
  master_clock_id = clock.run(master_clock)
end

function master_clock()
  while true do
    clock.sync(1/4)
    pattern_generator.do_master_step()
  end
end

pattern_generator = {}

function pattern_generator.do_master_step()
  print(clock.get_tempo())
end

with clock set to internal, i see changes to the tempo parameter (either in menu or by live-executing params:set("clock_tempo",90) etc) print to the maiden repl. whenever you’re able, can you please confirm you aren’t seeing the same with the above code?

Hi @dan_derks thanks for getting back to me.

I can confirm that the code snippet above doesn’t work for me, in the sense that the tempo printed to Maiden remains 120.0, and the master_clock() function continues to be executed at the same rate, irrespective of the value that I set in the Clock menu.

Interestingly, running params:set("clock_tempo",90) does result in the value in the Clock menu changing - it’s just the actual rate master_clock() runs does not change.

UPDATE:

Aha! I reset my Fates using the Reset item in the System menu, and now it appears to be working as it should!

1 Like