Here’s another fun Spacetime edit. I added in a gate row. Encoder 1 navigates between the command row and the gate row. One fun thing is that the gate row always runs sequentially while the command row does its own thing.
Lua is a lot of fun (aside from the 1 indexing blergh). This only took about 20 minutes to get the second row added in. When I find time, I’d like to break the metro commands out of the command row and into a dedicated clock div row. I would like to also add in the ability to change each row’s length. It would be Kria’s weird cousin.
Maybe MIDI Out once I get comfortable…
-- spacetime deluxe
-- with rings
-- from norns study 3
--
-- ENC 1 - change row
-- ENC 2 - select edit position
-- ENC 3 - edit current step
-- KEY 2 - return current row to default
-- KEY 3 - randomize current row
--
-- spacetime is a weird function sequencer.
-- it plays a note on each step
-- each step is a symbol for the action.
-- + = increase note
-- - = decrease note
-- < = go to bottom note
-- > = go to top note
-- * = random note
-- M = fast metro
-- m = slow metro
-- # = jump random position
--
-- top row: functions
-- bottom row: gates
-- augment/change this script
-- with new functions!
-- this mod adds burn's
-- excellent KarplusRings
-- engine
engine.name = "KarplusRings"
local cs = require 'controlspec'
numRows = 2
activeRow = 1
note = 40
position = 1
step = {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1}
STEPS = 16
edit = 1
gatePosition = 1
gate = {2,1,2,2, 2,1,2,1, 2,2,1,2, 2,1,2,1}
gateLabel = {"_", "X"}
function inc() note = util.clamp(note + 5, 40, 120) end
function dec() note = util.clamp(note - 5, 40, 120) end
function bottom() note = 40 end
function top() note = 120 end
function rand() note = math.random(80) + 40 end
function metrofast() counter.time = 0.125 end
function metroslow() counter.time = 0.25 end
function positionrand() position = math.random(STEPS) end
act = {inc, dec, bottom, top, rand, metrofast, metroslow, positionrand}
COMMANDS = 8
label = {"+", "-", "<", ">", "*", "M", "m", "#"}
function init()
cs.AMP = cs.new(0,1,'lin',0,0.75,'')
params:add_control("amp",cs.AMP)
params:set_action("amp",
function(x) engine.amp(x) end)
engine.amp(0.75)
cs.DECAY = cs.new(0.1,15,'lin',0,3.6,'s')
params:add_control("damping",cs.DECAY)
params:set_action("damping",
function(x) engine.decay(x) end)
cs.COEF = cs.new(0,1,'lin',0,0.11,'')
params:add_control("brightness",cs.COEF)
params:set_action("brightness",
function(x) engine.coef(x) end)
cs.LPF_FREQ = cs.new(100,10000,'lin',0,3600,'')
params:add_control("lpf_freq",cs.LPF_FREQ)
params:set_action("lpf_freq",
function(x) engine.lpf_freq(x) end)
engine.lpf_freq(3600.0)
cs.LPF_GAIN = cs.new(0,3.2,'lin',0,0.5,'')
params:add_control("lpf_gain",cs.LPF_GAIN)
params:set_action("lpf_gain",
function(x) engine.lpf_gain(x) end)
cs.BPF_FREQ = cs.new(100,10000,'lin',0,1200,'')
params:add_control("bpf_freq",cs.BPF_FREQ)
params:set_action("bpf_freq",
function(x) engine.bpf_freq(x) end)
engine.bpf_freq(1200.0)
cs.BPF_RES = cs.new(0,4,'lin',0,0.5,'')
params:add_control("bpf_res",cs.BPF_RES)
params:set_action("bpf_res",
function(x) engine.bpf_res(x) end)
counter = metro.alloc(count, 0.125, -1)
counter:start()
end
function count()
position = (position % STEPS) + 1
gatePosition = (gatePosition % STEPS) + 1
act[step[position]]()
if gate[gatePosition] == 2 then
engine.hz(midi_to_hz(note))
end
redraw()
end
function redraw()
screen.clear()
for i = 1,16 do
screen.level((i == edit and activeRow == 1) and 15 or 2)
screen.move(i*8-8,10)
screen.text(label[step[i]])
screen.level((i == edit and activeRow == 2) and 15 or 2)
screen.move(i*8-8, 30)
screen.text(gateLabel[gate[i]])
if i == position then
screen.move(i*8-8, 15)
screen.line_rel(6,0)
screen.stroke()
end
if i == gatePosition then
screen.move(i*8-8, 35)
screen.line_rel(6,0)
screen.stroke()
end
end
screen.update()
end
function enc(n,d)
if n == 1 then
activeRow = util.clamp(activeRow + d, 1, numRows)
elseif n == 2 then
edit = util.clamp(edit + d, 1, STEPS)
elseif n ==3 then
if activeRow == 1 then
step[edit] = util.clamp(step[edit]+d, 1, COMMANDS)
elseif activeRow == 2 then
gate[edit] = util.clamp(gate[edit]+d, 1, 2)
end
end
redraw()
end
function key(n,z)
if n == 2 and z == 1 then
init_steps()
end
if n == 3 and z == 1 then
randomize_steps()
end
end
function midi_to_hz(note)
return (440/32) * (2 ^ ((note - 9) / 12))
end
function randomize_steps()
for i= 1,16 do
if activeRow == 1 then step[i] = math.random(COMMANDS) end
if activeRow == 2 then gate[i] = math.random(2) end
end
end
function init_steps()
for i= 1,16 do
if activeRow == 1 then step[i] = 1 end
if activeRow == 2 then gate[i] = 1 end
end
end