*norns walkthrough*: hacking a script to add MIDI output

continuing the discussion from Patchwork

a few weeks ago, i had the chance to meet up with @Olivier, @mattlowery, and @encephalitislethargi to see what it’d take to hack MIDI output from olivier’s fantastic Patchwork. while there were plenty of goofs + gaffs, we were able to successfully add MIDI out!

since this is often a highly requested feature for other projects, it seemed helpful to share with others who might be curious about how to extend the functions of their favorite scripts to better suit their needs. this sort of customization is exactly why norns is such a powerful platform for artists – if you have a particular use-case that a script 90% meets, you can open it up to get it past that last 10%.

this video covers:

  • how to navigate someone else’s script to figure out what does what and how
  • how to effectively use the MIDI library to help norns speak to external gear
  • how to test your changes
  • how to troubleshoot weird behavior
  • how to add parameters and put that final polish on your contributions to a community script

generally, i’m super curious what folks feel needs more alternative / additional / focused documentation around norns – there are a few a ideas bubbling in the cauldron, but it’d be preferable to root these efforts in what folks need in the moment :slight_smile:

also, if anybody is interested in doing a deep dive or capturing their practices in some way to share with others, please please lmk! it’d be great to have a visible + collective effort toward pruning the welcome mat for new folks + new expressions :revolving_hearts:

32 Likes

I was just gonna mention how nice it is to get a Vimeo alert that @dan_derks has posted a new video.

4 Likes

This is a really awesome thing you all have done with this video. Thank you.

I learn best looking over someone’s shoulder and this is absolutely the digital Covid era example of this.

Thanks for sharing your process and please, more dev videos like this would be greatly appreciated! I’ll try and think what kinds of subjects would be of the greatest value for me personally and bounce these ideas off of this thread.

1 Like

you rock dan thanks for this!

1 Like

I didn’t know that this was something that I really wanted, but now that it exists, I’m very excited about it. I can’t wait to watch it.

2 Likes

So, so great. Thanks again for setting this up, Dan :bowing_man:

1 Like

What a good lesson @dan_derks! I’ve only been coding for a couple of weeks and watching these makes it a breeze. Having this info accessible to new adopters will surely help propel this community forward.

How difficult is it to add clocking via external midi to a patch? I’m trying to apply it to AWAKE but every time I switch my clock to external everything comes to a halt.
I’ve written this baby Test Script to mess around with and try out some ideas.

Little baby script

music = require ‘musicutil’
beatclock = require ‘beatclock’
clk = beatclock.new()
clk_midi = midi.connect(1)
clk_midi.event = clk.process_midi

function go()
norns.script.load(norns.state.script)
end

step = 1

function init()
clk.on_step = function() redraw() tick() end
clk.on_select_internal = function() clk:start() end
clk.on_select_external = function() print(“external”) end
clk:add_clock_params()
clk:start()
source_get = params:get(“clock”)
clk_src = params:get(“clock_source”)

end

function tick()
step = (step % 4) + 1
end

function enc(n,d)
if n == 1 then
source_get = util.clamp(source_get + d, 1, 2)
params:set(“clock”, source_get)
redraw()
elseif n == 2 then
clk_src = util.clamp(clk_src + d, 1, 2)
params:set(“clock_source”, clk_src)
redraw()
end
end

function int_ext()
if source_get == 1 then
int_ex = “internal”
elseif source_get == 2 then
int_ex = “external”
end
return int_ex
end

function int_midi()
if clk_src == 1 then
sponge = “internal”
elseif clk_src == 2 then
sponge = “midi”
end
return sponge
end

function redraw()
screen.clear()
screen.level(1)
screen.move(0,5)
screen.text(int_ext())
screen.move(0,15)
screen.text(int_midi())
screen.move(54,22)
screen.text("step: "…step)
screen.move(54,32)
screen.text("bpm: "…params:get(“bpm”))
screen.move(54,42)
screen.text("midi_bpm: "…params:get(“clock_tempo”))
screen.update()
end

before I started writing it I could go into parameters - CLOCK set the source to midi and see the tempo change when I adjusted the clock on the midi device but, for some reason that stopped working altogether by the time I finished my script.

Here is my not very elegant hack

Baby growing up

music = require ‘musicutil’
beatclock = require ‘beatclock’
clk = beatclock.new()
clk_midi = midi.connect(1)
clk_midi.event = clk.process_midi

function go()
norns.script.load(norns.state.script)
end

step = 1

function init()
clk.on_step = function() redraw() tick() end
clk.on_select_internal = function() clk:start() end
clk.on_select_external = function() print(“external”) end
clk:add_clock_params()
clk:start()
source_get = params:get(“clock”)
clk_src = params:get(“clock_source”)
main_bpm = params:get(“bpm”)

end

function tick()
step = (step % 4) + 1
end

function enc(n,d)
if n == 1 then
source_get = util.clamp(source_get + d, 1, 2)
params:set(“clock”, source_get)
redraw()
elseif n == 2 then
clk_src = util.clamp(clk_src + d, 1, 2)
params:set(“clock_source”, clk_src)
redraw()
elseif n == 3 then
main_bpm = util.clamp(main_bpm + d, 1, 250)
params:set(“bpm”,main_bpm)
end
end

function int_ext()
if source_get == 1 then
int_ex = “internal”
elseif source_get == 2 then
int_ex = “external”
end
return int_ex
end

function int_midi()
if clk_src == 1 then
sponge = “internal”
elseif clk_src == 2 then
sponge = “midi”
params:set(“bpm”, params:get(“clock_tempo”))
end
return sponge
end

function redraw()
screen.clear()
screen.level(1)
screen.move(0,5)
screen.text(int_ext())
screen.move(0,15)
screen.text(int_midi())
screen.move(54,22)
screen.text("step: "…step)
screen.move(54,32)
screen.text("bpm: "…params:get(“bpm”))
screen.move(54,42)
screen.text("midi_bpm: "…params:get(“clock_tempo”))
screen.update()
end

The idea is to have something check if parameters - CLOCK has its source set to midi which usually doesn’t do anything except having the midi clock run in the background, then if it’s set to midi take that tempo and feed its value to the internal clock.

Now to have them reset together…