i’m working on a thing that continuously spits out midi CCs, presently sending CCs 1-4 100x a second. it seems to work ok with my op-1 so far but it seems like a lot and i don’t have any other midi speaking gear to test on it.

is there a need to rate limit midi messages and if so, what is it?

I’m working with a system lib that is called with require and I’m kinda confused.

I’ve added a number of print statements to the lib as debug, but they never show up in REPL.

I’ve started/stopped norns to get things to reload, but no dice.

Is there some magic sauce I need to get a system lib to print debug?

EDIT - perhaps I’m just doing something stupid as I have this working ā€œsometimesā€ now. : -\

Maybe the same caching issue as above? You could try include of require instead to sidestep it. Or even copy it into your script’s lib folder and include it?

Turns out the chunk of code I was trying to debug wasn’t actually executing. :doh!:

(had been running ./stop.sh and ./start.sh to avoid caching issues)

1 Like

working on a new script

https://vimeo.com/333030294

based on the roland tb-303 sequencer via ā€œAnalysis of the µPD650C-133 CPU timingā€
pretty specific use case (requires norns, a grid, malekko sync, and xox heart + pacemaker) but i will try to open source it this year.

5 Likes

blown away by all the amazing contributions, and grateful for those of you who know how to code :slight_smile: I recently came across this old post in dust-scripting about a markov melody generator for norns…My knowledge of music theory is about as piss poor as my knowledge of scripting, so, I’m just bumping this to see if any of you talented folks might be interested enough to take a crack at it at some point (I messaged the original poster and he is unfortuantely too busy with other stuff at this time). Thanks in advance.

on the off chance that you’re just trying to get it running, i think all you have to do is change line 6 of the script from this:

counter = metro.alloc(count, 0.15, -1)

to this

counter = metro.init(count, 0.15, -1)
4 Likes

cheers. doesnt mean much to me know, but maybe someday :slight_smile:

i’m working on a script to bring arc controled LFOs to midi devices. here’s the whole thing on github

two bottlenecks are keeping it from moving past ā€œnovelty funā€ to ā€œactually funā€:

—preserving phase on speed change. instead of what you would expect to hear when changing lfo speed, it resets the waveform and gargles the ccs. i think because i calculate phase from current time minus start time? but i can’t work out how to fix it. setting speed to only update at 1/0/-1 is too sluggish.

—more LFO shapes, ideally control over curves of the shapes as well. this is killing me, i have been trying to make a saw wave LFO for three days. the best reference i’ve found so far is this book:

i am looking at the chapter on ā€œclassical waveformsā€ but i am just not comprehending how to translate the math into the code (which probably means i don’t understand the math…)

here is what i think the relevant code is:

function init()
  startTime = util.time()
  lfo_metro = metro.init()
  lfo_metro.time = .01
  lfo_metro.count = -100
  lfo_metro.event = function()
    currentTime = util.time()
    for i = 1,4 do 
      lfo[i].bpm = lfo[i].freq * 60
      lfo[i].amp = params:get("lfo_" .. i .. "_amp")
      lfo[i].offset= params:get("lfo_" .. i .. "_offset")
    
      --get phase of LFO
      if params:get("lfo_" .. i .. "_type") == 1 then --sin
        lfo[i].phase = math.sin((currentTime - startTime) * lfo[i].freq * tau)
      elseif params:get("lfo_" .. i .. "_type") == 2 then --square  
        if math.sin((currentTime - startTime) * lfo[i].freq* tau) > 0 then lfo[i].phase = 1
        else lfo[i].phase = -1 end
      end

      -- clamp ccs
      if math.ceil(lfo[i].offset + 64 * lfo[i].phase * lfo[i].amp) < 0 then lfo[i].cc = 0
      elseif math.ceil(lfo[i].offset + 64 * lfo[i].phase * lfo[i].amp) > 127 then lfo[i].cc = 127
      -- set cc
      else lfo[i].cc= math.ceil(lfo[i].offset + 64 * lfo[i].phase * lfo[i].amp) end
    
      --for arc redraw
      lfo[i].counter = (lfo[i].counter + (1*lfo[i].freq))%100
      lfo[i].ar = lfo[i].counter*.64

      send_cc(i,lfo[i].cc)
      lfo[i].lastphase = lfo[i].phase
    end
  end
end

if anyone has suggestions on how to implement more waveforms in lua or what to read to comprehend how to implement waveforms in code i would be so grateful! if nothing else i did get a couple of new ideas to try while writing this up.

1 Like

this is a bit of a shot in the dark, but i’m going to recommend looking at @markeats passersby and mollythepoly libs for lua implemented LFOs

2 Likes

molly the poly’s lfo is in supercollider, unless i really misread the code. need to check passerby though. maybe i saw something in his ui library about this too. thanks for the tip!

LFOs in supercollider can certainly be cleaner, faster, and more efficient.

in lua it’s ok as long as your ā€˜LF’ is pretty low - like only update every 5-10ms or something.

(will try and make a demo for you if i have time, what you have looks a little complicated to me at first glance. that chapter in miller’s book is not really about LFOs, but about bandlimiting for, um, HFOs.)


(tangent)

the bottleneck is not the actual speed of lua or the metros, rather its not wanting to swamp the networking with OSC packets.

for softcut / crone parameters (e.g. levels) i’d like to at least switch over from OSC to a lighter IPC layer, soon (like 2.2 goal)

4 Likes

I’ve been making LFO’s in SC and then exposing them to Lua via Polls, which is sort of the other way round from LFOs in Lua.

It performs pretty well and I got to avoid trying to figure out how to build waveforms in Lua(!) but a pure Lua solution is appealing - especially one that people could just drop in maiden and add modulation.

(My experiments with fast metros have shown a tendency to choke up my Norns UI though.)

2 Likes

thank you everyone! @zebra would love to see an example if you find a minute! no worries if you don’t get a chance though, big ask i know.

my script is (right now) literally just for controlling midi ccs, so it didn’t even occur to me to try to drag in supercollider. it feels a bit non-nornsy to use supercollider only for processing midi events, but obviously the available objects make that an appealing route. as @mimetaur mentioned though a drag and drop lua solution seems super helpful.

re:performance, i was worried about it(think i actually posted earlier here questioning the limit for sending cc messages), but my metro updating 4 lfos every 10ms is totally stable for my op-1 and norns hardware—even at the completely unnecessary 40fps display refresh rate. the only issue is my extremely poor grasp of math.

one caveat to that, putting something that doesn’t work correctly inside that metro does induce a lot of ui chugging and crashes maiden if you have it up. definitely make use of the metro.count timeout when you’re auditioning changes in there.

sorry i missed that you wanted to control midi with this. for that case, agree that lua side is best

Has anyone got any experience of updating metro tick speed without stopping and then starting it again? I’d like to smoothly update a BPM but can only get the update to happen if I stop then restart the metro.

One solution could be to run the metro at a very fast base speed, but maintain your ā€œrealā€ tempo in a separate variable.

Then you could only execute the code in the metro’s callback function every X (your speed divided by base speed - I think?) times.

3 Likes

ā€œthat looks too complicatedā€ is i think actually all i needed to know, started over and am on much more solid ground, don’t think i need an example anymore. thank you!

edit: @P1505, @mimetaur’s idea is actually in my script above right now. can smoothly update the bpm, but need to change it slightly to round off the decimals. haven’t tried keeping time long term but 10ms seems good enough for most tempos in my 5-10 minute tests

1 Like

have you checked out the beatclock lib?

1 Like

I haven’t but will. Does it solve this issue? I’d love to know how so I’ll go digging.