My question was ill worded. I actually meant to ask about Ableton Link and if that had been improved as well. The question was more if that had been updated and if there was a bit more documentation on how to implement it in a script or during usage.

1 Like

ableton link support hasn’t been improved much since we merged it, but it’s been working pretty well, are you talking about some particular improvements?

future improvements may include:

  • re-mapping the beat to the transport start time, if syncing to start/stop.
  • api for seeking along the timeline with regards to other link peers (requestBeatAtTime et al)

but they wouldn’t block you from writing scripts that you’ll be able sync with other link apps and devices. if you’re comfortable with compiling norns from git, i’d recommend starting with that. otherwise, wait until the next update, as there has been some minor api changes since version 200328.

documentation is coming!

3 Likes

Ah. Okay, so, the option of using Ableton Link will be based upon script by script usage of the new global norns clock. So, if I’m not particularly adept at coding (lord have I tried!) then it is required that I wait for a future update of both the norns and my desired scripts.

1 Like

wait for the docs, we’re working on explaining all of this

6 Likes

Will do. Got a bit overly excited.

1 Like

hey y’all – ahead of tomorrow’s release exposing the global clock, i put together a bit of a “how I migrated code I hadn’t looked in months from beatclock to global clock, survived, and thrived!”: Norns: migrating scripts from `beatclock` to the new global clock (a how-to!)

10 Likes

it’s worth mentioning that since its first release the clock module has got many important fixes by @Dewb and @ngwese, documentation by @okyeron and @dan_derks, and of course thanks to @tehn who implemented the params menu integration and did the whole release management for this update! cheers to you all, guys! :tada:

12 Likes

I’m curious if it would it be better to use the new clock system in my code where I have multiple sequences running off of a master metro at different clock divisions.

Typically I’ve been following this pattern in my main metro callback:

for i=1,#sequencers do
    sequencers[i].div_count = sequencers[i].div_count % clock_division + 1
    if sequencers[i].div_count == 1 then
      -- do sequencer stuff
    end
end

so if clock_division is 4, the sequencer will only play every 4 iterations when the modulo calculation equals 1.

My understanding is with the new system I could instead define multiple coroutines for each sequence, where each one syncs to master tempo at a different division. Is this more stable and/or performant? Are there benefits for me to refactor this to use coroutines other than it maybe looking cleaner and being more readable?

there are no performance or stability benefits. if you don’t use the coroutine features extensively and don’t need external sync sources, it’s just cleaner code.

1 Like

Is there a way to query which source the clock is using? The use case here would be to allow a user to change clock tempo with an encoder if the source is internal. I see a setter, but no getter.

2 Likes

everything’s in the params, so I think you can just call params:get("clock_source"). If it returns 1 the source is internal. You can see all the param IDs here

2 Likes

also params:string(“clock_source”)

6 Likes

ah! Thank you. I’ve somehow overlooked params:string all this time. Meanwhile I’m over here trying to keep track of all these dang indices

4 Likes

Very cool. I just updated my sequencer script. Drop-in replacement for what I was doing before.

1 Like

This is great. Excited to see Norns development is continuing in a direction that the apps I’m interested in writing will greatly benefit from.

One issue I’m running into (this is my first app so it may be the way I’ve written my sequencer): When synced to external midi and setting clock.sync within a while true do loop, there is a tiny delay on the 1st downbeat every time I start my external sequencer. If I move the engine.hz outside of the while loop then it sounds the moment I hit start on my sequencer (but only once obviously).

Here is the relevant code:

function clock.transport.start()
  clock_id = clock.run(sequencer)
end

function sequencer()
  sequencer_pos = 0
  
  while true do
    clock.sync(1/4)
    engine.hz(get_note())
  end
end

Any help would be greatly appreciated - thanks!

Completely untested random thought - try putting engine.hz inside a function that is used in the while loop?

1 Like

The behavior you are experiencing makes sense to me. According to the docs, clock.sync suspends the coroutine until the given duration has passed. Therefore, on transport start, you are immediately calling sequencer(), which will first suspend for a quarter note (first iteration of the while loop), and then call engine.hz, hence the delay. That’s my guess. There would be multiple ways to fix it, swap .sync and .hz or call .hz once before the while loop, etc.

2 Likes

Thanks for the thought @okyeron! engine.hz is actually inside of a separate function - I just simplified the code for the sake of this thread.

@Artaos I think I had actually tried both of those suggestions with no luck, but I’m not positive I had tried to call .hz once outside of the loop. The delay doesn’t seem to be a quarter note’s length (and the length seems to change on every start message). If neither of those suggestions work I’ll take a short video demonstrating the behavior. Thanks for the help!

1 Like

Swapping it does indeed have the first note land on the 1, but there is still sometimes (maybe 10% of the time) an unquantized gap between the 1st and 2nd note and then things seem to even out. Here’s a super short video: https://imgur.com/a/d4vr9Dg

I’ll experiment with the rest of the code and report back if I gain some insight in case anyone else runs into this issue.

What’s the expected type of data for clock.get_tempo()?

Looks to be a big float like 130.00013500014 when I do screen.text(clock.get_tempo()) and taking clock from Link.

Best practice here would be to use util.round (number, quant) perhaps when displaying the tempo?

Should that value be left alone as a float when setting tempo? like params:set("clock_tempo",clock.get_tempo()+delta) or better to round it first?

What level of precision would be recommended here?