Last active
September 1, 2018 14:40
-
-
Save carltesta/ac0aa240da6fbd7d3981d8cacaa770dc to your computer and use it in GitHub Desktop.
GENMDM Genesis MIDI Sequencer using Norns (10-track MIDI Sequencer)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- GENMDM | |
-- | |
-- step sequencing the genesis | |
-- | |
-- enc 1 = hp volume | |
-- enc 2 = select step | |
-- enc 3 = tune step | |
-- key 2 = random/linear seq toggle | |
-- key 3 = clear sequence | |
-- key 1 = alt | |
-- alt key 2 = set current step to 0 | |
-- alt key 3 = turn sequence off | |
-- alt enc 1 = select channel | |
-- alt enc 2 = populate sequence with random pitches | |
-- alt enc 3 = change seq length | |
-- | |
-- GENMDM interface by @little-scale | |
-- lua script by @carltesta | |
randVal = {0,0,0,0,0,0,0,0,0,0} | |
onVal = {1,1,1,1,1,1,1,1,1,1} | |
alt = false | |
chanSelect = 1 | |
local audio = require 'audio' | |
local o = midi.connect(1) | |
tracks = {one, two, three, four, five, six, seven, eight, nine, ten} | |
for i=1,10 do tracks[i] = { | |
on = true, | |
random = false, | |
length = 16, | |
sliders = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | |
edit = 0, | |
accum = 1, | |
step = 0 | |
} | |
end | |
midinotes = {"off", "a1", "a#1", "b1", "c1", "c#1", "d1", "d#1", "e1", "f1", "f#1", "g1", "g#1", "a2", "a#2", "b2", "c2", "c#2", "d2", "d#2", "e2", "f2", "f#2", "g2", "g#2", "a3", "a#3", "b3", "c3", "c#3", "d3", "d#3", "e3"} | |
tracknames = {"YM2612 FM1", "YM2612 FM2", "YM2612 FM3", "YM2612 FM4", "YM2612 FM5", "YM2612 FM6", "SN76489 PSG 1", "SN76489 PSG 2", "SN76489 PSG 3", "SN76489 Noise"} | |
basenote = {44,44,44,44,44,44,44,44,44,44} | |
local k = metro[1] | |
k.count = -1 | |
k.time = 15/72 | |
k.callback = function(stage) | |
for i=1,10 do | |
if tracks[i].on == true then | |
if tracks[i].sliders[tracks[i].step+1]==0 then | |
o.note_off(tracks[i].sliders[tracks[i].step+1]+basenote[i],0,i) | |
end | |
if tracks[i].sliders[tracks[i].step+1]~=0 then | |
o.note_on(tracks[i].sliders[tracks[i].step+1]+basenote[i],127,i) | |
end | |
if tracks[i].random == false then | |
tracks[i].step = (tracks[i].step + 1) % tracks[i].length | |
end | |
if tracks[i].random == true then | |
tracks[i].step = math.random(tracks[i].length)-1 | |
end | |
end | |
if tracks[i].on == false then | |
redraw() | |
end | |
end | |
redraw() | |
end | |
-- parameters below are specific to GENMDM but could be customised to fit any particular MIDI setup | |
function init() | |
print("GENMDM: sequencer") | |
audio.monitor_on() | |
params:add_number("tempo",20,240,72) | |
params:set_action("tempo", function(x) k.time = 15/x end) | |
params:add_separator() | |
params:add_control("LFO Enable", controlspec.new(1,2,'lin',1,1)) | |
params:set_action("LFO Enable", function(x) o.cc(74,x*64,1) end) | |
params:add_control("LFO Speed", controlspec.new(1,8,'lin',1,1)) | |
params:set_action("LFO Speed", function(x) o.cc(1,x*16,1) end) | |
params:add_separator() | |
--params:add_control("ch:1 preset",controlspec.new(0,16,'lin',1,0)) | |
--params:set_action("ch:1 preset", function(x) sendCC(1,9,x*8) end) | |
for i=1,10 do | |
params:add_number("ch:"..i.." octave",1,9,4) | |
params:set_action("ch:"..i.." octave", function(x) basenote[i] = 12*x-4 end) | |
end | |
for i=1,6 do | |
params:add_control("ch:"..i.." algorithm",controlspec.new(1,8,'lin',1,1)) | |
params:set_action("ch:"..i.." algorithm", function(x) o.cc(14,x*16,i) end) | |
params:add_control("ch:"..i.." feedback",controlspec.new(1,8,'lin',1,1)) | |
params:set_action("ch:"..i.." feedback", function(x) o.cc(15,x*16,i) end) | |
params:add_control("ch:"..i.." freq mod",controlspec.new(1,8,'lin',1,1)) | |
params:set_action("ch:"..i.." freq mod", function(x) o.cc(75,x*16,i) end) | |
params:add_control("ch:"..i.." OP1 level",controlspec.new(1,128,'lin',1,16)) | |
params:set_action("ch:"..i.." OP1 level", function(x) o.cc(16,x,i) end) | |
params:add_control("ch:"..i.." OP2 level",controlspec.new(1,128,'lin',1,32)) | |
params:set_action("ch:"..i.." OP2 level", function(x) o.cc(17,x,i) end) | |
params:add_control("ch:"..i.." OP3 level",controlspec.new(1,128,'lin',1,64)) | |
params:set_action("ch:"..i.." OP3 level", function(x) o.cc(18,x,i) end) | |
params:add_control("ch:"..i.." OP4 level",controlspec.new(1,128,'lin',1,128)) | |
params:set_action("ch:"..i.." OP4 level", function(x) o.cc(19,x,i) end) | |
params:add_control("ch:"..i.." OP1 multiple",controlspec.new(1,16,'lin',1,1)) | |
params:set_action("ch:"..i.." OP1 multiple", function(x) o.cc(20,x*8,i) end) | |
params:add_control("ch:"..i.." OP2 multiple",controlspec.new(1,16,'lin',1,1)) | |
params:set_action("ch:"..i.." OP2 multiple", function(x) o.cc(21,x*8,i) end) | |
params:add_control("ch:"..i.." OP3 multiple",controlspec.new(1,16,'lin',1,1)) | |
params:set_action("ch:"..i.." OP3 multiple", function(x) o.cc(22,x*8,i) end) | |
params:add_control("ch:"..i.." OP4 multiple",controlspec.new(1,16,'lin',1,1)) | |
params:set_action("ch:"..i.." OP4 multiple", function(x) o.cc(23,x*8,i) end) | |
params:add_control("ch:"..i.." OP1 attack",controlspec.new(1,32,'lin',1,16)) | |
params:set_action("ch:"..i.." OP1 attack", function(x) o.cc(43,x*4,i) end) | |
params:add_control("ch:"..i.." OP2 attack",controlspec.new(1,32,'lin',1,16)) | |
params:set_action("ch:"..i.." OP2 attack", function(x) o.cc(44,x*4,i) end) | |
params:add_control("ch:"..i.." OP3 attack",controlspec.new(1,32,'lin',1,16)) | |
params:set_action("ch:"..i.." OP3 attack", function(x) o.cc(45,x*4,i) end) | |
params:add_control("ch:"..i.." OP4 attack",controlspec.new(1,32,'lin',1,16)) | |
params:set_action("ch:"..i.." OP4 attack", function(x) o.cc(46,x*8,i) end) | |
params:add_control("ch:"..i.." OP1 release",controlspec.new(1,16,'lin',1,8)) | |
params:set_action("ch:"..i.." OP1 release", function(x) o.cc(59,x*8,i) end) | |
params:add_control("ch:"..i.." OP2 release",controlspec.new(1,16,'lin',1,8)) | |
params:set_action("ch:"..i.." OP2 release", function(x) o.cc(60,x*8,i) end) | |
params:add_control("ch:"..i.." OP3 release",controlspec.new(1,16,'lin',1,8)) | |
params:set_action("ch:"..i.." OP3 release", function(x) o.cc(61,x*8,i) end) | |
params:add_control("ch:"..i.." OP4 release",controlspec.new(1,16,'lin',1,8)) | |
params:set_action("ch:"..i.." OP4 release", function(x) o.cc(62,x*8,i) end) | |
params:add_separator() | |
end | |
k:start() | |
end | |
function enc(n, delta) | |
if alt==false then | |
if n == 1 then | |
mix:delta("output", delta) | |
elseif n == 2 then | |
tracks[chanSelect].accum = (tracks[chanSelect].accum + delta) % tracks[chanSelect].length | |
tracks[chanSelect].edit = tracks[chanSelect].accum | |
elseif n == 3 then | |
tracks[chanSelect].sliders[tracks[chanSelect].edit+1] = tracks[chanSelect].sliders[tracks[chanSelect].edit+1] + delta | |
if tracks[chanSelect].sliders[tracks[chanSelect].edit+1] > 32 then tracks[chanSelect].sliders[tracks[chanSelect].edit+1] = 32 end | |
if tracks[chanSelect].sliders[tracks[chanSelect].edit+1] < 0 then tracks[chanSelect].sliders[tracks[chanSelect].edit+1] = 0 end | |
end | |
elseif alt==true then | |
if n == 1 then | |
if delta > 0 then | |
if chanSelect <10 then chanSelect = (chanSelect + 1) | |
else | |
chanSelect=10 | |
end | |
end | |
if delta < 0 then | |
if chanSelect >1 then chanSelect = (chanSelect - 1) | |
else | |
chanSelect=1 | |
end | |
end | |
end | |
if n == 2 then | |
tracks[chanSelect].sliders[math.random(16)] = math.random(32) | |
end | |
if n == 3 then | |
if delta > 0 then | |
if tracks[chanSelect].length <16 then tracks[chanSelect].length = (tracks[chanSelect].length + 1) | |
else | |
tracks[chanSelect].length=16 | |
end | |
end | |
if delta < 0 then | |
if tracks[chanSelect].length >1 then tracks[chanSelect].length = (tracks[chanSelect].length - 1) | |
else | |
tracks[chanSelect].length=1 | |
end | |
end | |
end | |
redraw() | |
end | |
end | |
function key(n, z) | |
if n==1 and z==1 then | |
alt=true | |
end | |
if n==1 and z==0 then | |
alt=false | |
end | |
if n==2 and z==1 then | |
if alt == false then | |
randVal[chanSelect] = 1 - randVal[chanSelect] | |
if randVal[chanSelect] == 1 then | |
tracks[chanSelect].random = true | |
end | |
if randVal[chanSelect] == 0 then | |
tracks[chanSelect].random = false | |
end | |
end | |
if alt == true then | |
for i=1,10 do tracks[i].step = 0 end | |
end | |
end | |
if n==3 and z==1 then | |
if alt == false then | |
for i=0,15 do | |
tracks[chanSelect].sliders[i+1] = 0 | |
end | |
end | |
if alt == true then | |
onVal[chanSelect] = 1 - onVal[chanSelect] | |
if onVal[chanSelect] == 0 then | |
tracks[chanSelect].on = false | |
end | |
if onVal[chanSelect] == 1 then | |
tracks[chanSelect].on = true | |
end | |
end | |
end | |
end | |
function redraw() | |
screen.aa(1) | |
screen.line_width(1.0) | |
screen.clear() | |
screen.move(5,10) | |
screen.text("GENMDM") | |
screen.move(40,10) | |
screen.text("ch: "..tracknames[chanSelect]) | |
for i=0, tracks[chanSelect].length-1 do | |
if i == tracks[chanSelect].edit then | |
screen.level(15) | |
else | |
screen.level(2) | |
end | |
screen.move(32+i*4, 48) | |
screen.line(32+i*4, 46-tracks[chanSelect].sliders[i+1]) | |
screen.stroke() | |
end | |
screen.level(10) | |
screen.move(32+tracks[chanSelect].step*4, 50) | |
screen.line(32+tracks[chanSelect].step*4, 54) | |
screen.stroke() | |
screen.move(15,48) | |
local val = (tracks[chanSelect].sliders[tracks[chanSelect].edit+1]) | |
--print(val) | |
screen.text(midinotes[val+1]) | |
--screen.text(midinotes[tracks[chanSelect].sliders[tracks[chanSelect].edit+1]]) | |
screen.move(100,48) | |
screen.text(1+tracks[chanSelect].edit.."/"..tracks[chanSelect].length) | |
if tracks[chanSelect].random == true then | |
screen.move(100,40) | |
screen.text("rand") | |
end | |
if tracks[chanSelect].on == false then | |
screen.move(100,32) | |
screen.text("off") | |
end | |
screen.update() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment