Norns: scripting

Sorry I never answered this, but just look at he websock wrapped code, it is a few lines using nanomsg

There’s no protocol to speak of since the two processes (matron, sclang) have each their own repl already. ASCII utf8

There are a couple special commands for maiden, not needed to get started

hoping to get some help for @capsella with my less concepts script on 1.0 (I’m assuming the fix would also help with 2.0).

apparently, my external midi clocking code isn’t working as intended.

following study 4, I’ve implemented the following at the top of the script:

local beatclock = require ‘beatclock’
local clk = beatclock.new()
clk_midi = midi.connect()
clk_midi.event = clk.process_midi

then this in my init():

m = midi.connect()
clk.on_step = function() iterate() end <~~~~ iterate triggers all the action in the script
clk.on_select_internal = function() clk:start() end
clk.on_select_external = function() print(“external”) end
clk:add_clock_params()
clk:stop() <~~~~ I don’t want the clock to start when loaded + it’s the only difference

I then have some hardware interaction, key 1 to start and stop internal clock:

if n == 1 and z == 1 then
automatic = automatic + 1
if automatic % 2 == 1 then
clk:start()
elseif automatic % 2 == 0 then
clk:stop()
end
end

per the study, clk.on_step = function() iterate() end should trigger regardless of clock source (internal or external), but @capsella is reporting that the script only responds to internal clocking. any ideas?

edit, OH WAIT: is clk:start() a global command that affects both internal and external clocking? e.g.: clk:stop() means ALL clock signals will not trigger clk.on_step?? I was naively assuming that those commands were only applicable to internal clocking – can anyone confirm?

Yeah, looking at the code for BeatClock it seems like it is stopping and starting both internal and external.

It’s trying to hide from you the fact that stop and start use completely different methods under the hood. But they both clk:tick() periodically when you run clk:start()

It seems like it would be pretty doable to make a version of beatclock that breaks those out with a clk:start_internal() and clk:start_external(), you’d mostly have to shuffle some existing code around in that class.

1 Like

vindication, thank you so much @mimetaur, knowing this is hugely helpful – I’ll do some fiddling and testing to change how I’m handling those events in my script :slight_smile:

2 Likes

@Dan_Derks there are some new midi things in 2.0 (helpers for clock/start/stop/continue) which will probably with help your situation.

check out these midi-demo scripts
https://github.com/okyeron/midi-demo which I did as examples for working with external clock from my TR-09

3 Likes

@ppqq prompted a little investigation into meta-parameters (and i think i recall seeing @carvingcode exploring this earlier?)

basic goal: have a parameter which is the assignment for another parameter.

ie: a parameter which maps the destination of an encoder turn.

here’s some existing code from earthsea, sound params (without set_action for each)

params:add_control("shape", "shape", controlspec.new(0,1,"lin",0,0,""))
params:add_control("timbre", "timbre", controlspec.new(0,1,"lin",0,0.5,""))
params:add_control("noise", "noise", controlspec.new(0,1,"lin",0,0,""))
params:add_control("cut", "cut", controlspec.new(0,32,"lin",0,8,""))

add a meta param:

params:add_option("enc2","enc 2 mapping", {"shape","timbre","noise","cut"})

then let’s implement the mapping:

function enc(n,delta)
  if n==2 then
    params:delta(params:string("enc2"),delta*4)
  end
end

calling params:string returns the string name from the OPTION, which sets the destination of the delta change. i multiply by 4 to increase sensitivity.

so now encoder turns can be redirected very easily in PLAY mode.

and you could of course have a key action rotate/change the OPTION as well

12 Likes

Interesting possibilities, @tehn. A couple of these, placed on a UI Page and we’re close to having capabilities similar to boxes like Octatrack which can modulate multiple params from a single knob. Used with Passersby or MollyThePoly… nice!

3 Likes

I spent a few hours trying to understand how the Arc works by stepping through the code from the angl script. I understood everything except for what I see as a crucial piece of functionality.

How do the values in the table named positions get set? The code says that it is assigned to the value of pos which is an argument to a callback function for a poll named phase_1. Looking at the console, I can see 7 polls named phase_n. What do these polls do and how do they get their input values?

The only suspicion I have is the new softcut engine is being used and it exports a bunch of phase values between 0 and 1 for the buffer read location.

line 82 sets up the polls on init
local phase_poll = poll.set('phase_' .. v, function(pos) positions[v] = pos end)

then I look up study 5 about polls:
https://monome.org/docs/norns/study-5/

Aha - In the Glut engine, the phase and levels polls are created.

Engine_Glut.sc line 212

			this.addPoll(("phase_" ++ (i+1)).asSymbol, {
				var val = phases[i].getSynchronous;
				val
			});

			this.addPoll(("level_" ++ (i+1)).asSymbol, {
				var val = levels[i].getSynchronous;
				val
			});
		});

but… if VOICES is 4 why are there 7 phase polls created? Or is 7 the default in the engine, and angl is just setting 4 of those?

Seems like the polls get updated by the callback function every time iteration?

EDIT - Aha the engine defines 7 voices classvar nvoices = 7;

3 Likes

Thanks. This makes sense. I had a long discussion with a friend about how this implementation of an oscillating circle is based on the length of the sample. I forgot about the SC layer exporting polls from engines.

1 Like

So are you running the REPL at the command line on the Norns, and typing “norns.script.load()…” to reload? Right now I’m doing this mix of VS code, rsync, and hitting the play button in Maiden that gets pretty old.

I’d love to automate reloading the script on the Norns side and keep the console/REPL up for errors

1 Like

Yeah - that’s what I was doing for a bit. I keep going back and forth on using my text editor and maiden.

Considerably quicker than reopening the script and ‘playing’ it. :+1:

Not sure if it’s the right place to ask, but there is a way to control internal tempo via cc? It might seem stupid, I know :slight_smile:

Maybe with crow I will be able to change tempo via cv from the modular? That would be awesome, but I’d like to do it also in stand-alone mode via a fader on my nanokontrol. No, uh?

1 Like

I think you can expose tempo controls to params menu, and map it to cc from there

A lot of apps have tempo in the params menu, but AFAIK it’s NEVER cc-controllable, so I thought it was not possible. If it is please tell me how to mod the scripts and I’d be grateful! :pray:

2 Likes

you can certainly write your own midi cc map to tempo. see the norns study on midi as a start.

I am intending to expand the parameters cc system to cover Number types in addition to Control types, so soon no extra scripting will be needed

3 Likes

If I wanted to write a supercollider engine for midi processing (because SC has some cool midi tricks up its sleeve) and then use it along with an existing synth engine (such as molly_the_poly) can I do that? Multiple interacting engines from one lua script?

1 Like

What kind of MIDI tricks are you after? Just wondering if it might make sense to build out more libs on the Lua side for this…

2 Likes

well, i’m aware of your musicutils.lua lib, and it’s really nice. But I’m thinking about scala support, chord inversion, voice leading…

Maybe it makes sense for lua, but doesn’t this stuff already exist for supercollider?

1 Like