Last active
September 16, 2018 17:41
-
-
Save okyeron/cd3d30223669c46270199db6b3c14aac to your computer and use it in GitHub Desktop.
rebound by nf adding basic grid support (for 256)
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
-- g-bound: a kinetic sequencer w/ grid | |
-- | |
-- key1: shift^ | |
-- key2: add/^remove orb | |
-- key3: select next orb | |
-- enc1: change orb note | |
-- enc2: rotate orb^s | |
-- enc3: accelerate orb^s | |
-- written by nf in august 2018 | |
-- params and scales taken from tehn/awake, thanks | |
local cs = require 'controlspec' | |
engine.name = "PolyPerc" | |
local gr = grid.connect() -- get grid port 1 (defined in menu) | |
local balls = {} | |
local cur_ball = 0 | |
local scale_degrees = {2,1,2,2,2,1,2} | |
local notes = {} | |
local freqs = {} | |
local BeatClock = require 'beatclock' | |
local clk = BeatClock.new() | |
local clk_midi = midi.connect() | |
clk_midi.event = clk.process_midi | |
local freq_queue = {} | |
local shift = false | |
function init() | |
screen.aa(1) | |
gr.all(0) | |
local u = metro.alloc() | |
u.time = 1/60 | |
u.count = -1 | |
u.callback = update | |
u:start() | |
--clk.send = true | |
clk.on_step = play_notes | |
clk.on_select_internal = function() clk:start() end | |
clk:add_clock_params() | |
params:set("clock out", 2 ) | |
clk_midi.send{250} -- send midi start | |
params:add_separator() | |
params:add_number("scale mode",1,7,3) | |
params:set_action("scale mode", function(n) | |
build_scale() | |
end) | |
params:add_number("trans",-12,24,0) | |
params:set_action("trans", function(n) | |
build_scale() | |
end) | |
params:add_separator() | |
cs.AMP = cs.new(0,1,'lin',0,0.5,'') | |
params:add_control("amp",cs.AMP) | |
params:set_action("amp", | |
function(x) engine.amp(x) end) | |
cs.PW = cs.new(0,100,'lin',0,80,'%') | |
params:add_control("pw",cs.PW) | |
params:set_action("pw", | |
function(x) engine.pw(x/100) end) | |
cs.REL = cs.new(0.1,3.2,'lin',0,0.2,'s') | |
params:add_control("release",cs.REL) | |
params:set_action("release", | |
function(x) engine.release(x) end) | |
cs.CUT = cs.new(50,5000,'exp',0,555,'hz') | |
params:add_control("cutoff",cs.CUT) | |
params:set_action("cutoff", | |
function(x) engine.cutoff(x) end) | |
cs.GAIN = cs.new(0,4,'lin',0,1,'') | |
params:add_control("gain",cs.GAIN) | |
params:set_action("gain", | |
function(x) engine.gain(x) end) | |
params:bang() | |
end | |
function build_scale() | |
local scale = params:get("scale mode") | |
local trans = params:get("trans") | |
local n = 0 | |
for i=1,32 do | |
notes[i] = n | |
n = n + scale_degrees[(scale + i)%#scale_degrees + 1] | |
end | |
for i=1,#notes do | |
freqs[i] = 55*2^((notes[i]+trans)/12) | |
end | |
end | |
function redraw() | |
screen.clear() | |
if shift then | |
screen.level(5) | |
screen.line_width(1) | |
screen.rect(1,1,126,62) | |
screen.stroke() | |
end | |
for i=1,#balls do | |
drawball(balls[i], i == cur_ball) | |
end | |
screen.update() | |
end | |
function redrawgrid() | |
gr.refresh() | |
end | |
function update() | |
gr.all(0) | |
for i=1,#balls do | |
updateball(balls[i]) | |
end | |
redraw() | |
redrawgrid() | |
end | |
function reset_all() | |
balls = {} | |
-- send midi stop | |
clk_midi.send{252} | |
update() | |
end | |
function enc(n, d) | |
if n == 1 and not shift and cur_ball > 0 then | |
-- note | |
balls[cur_ball].n = math.min(math.max(balls[cur_ball].n+d, 1), #notes) | |
elseif n == 2 then | |
-- rotate | |
for i=1,#balls do | |
if shift or i == cur_ball then | |
balls[i].a = balls[i].a - d/10 | |
end | |
end | |
elseif n == 3 then | |
-- accelerate | |
for i=1,#balls do | |
if shift or i == cur_ball then | |
balls[i].v = balls[i].v + d/10 | |
end | |
end | |
end | |
end | |
function key(n, z) | |
if n == 1 then | |
-- shift | |
shift = z == 1 | |
elseif n == 2 and z == 1 then | |
if shift then | |
-- remove ball | |
table.remove(balls, cur_ball) | |
if cur_ball > #balls then | |
cur_ball = #balls | |
end | |
else | |
-- add ball | |
table.insert(balls, newball(64,32)) | |
cur_ball = #balls | |
end | |
elseif n == 3 and z == 1 and not shift and #balls > 0 then | |
-- select next ball | |
cur_ball = cur_ball%#balls+1 | |
end | |
end | |
gr.event = function(x,y,state) | |
if state==1 then | |
gr.led(x,y,15) | |
table.insert(balls, newball(x*8,y*8)) | |
cur_ball = #balls | |
end | |
redrawgrid() | |
end | |
function newball(v,w) | |
return { | |
x = v, | |
y = w, | |
v = 0.5*math.random()+0.5, | |
a = math.random()*2*math.pi, | |
n = math.floor(math.random()*#notes+1), | |
} | |
end | |
function drawball(b, hilite) | |
screen.level(hilite and 15 or 5) | |
screen.circle(b.x, b.y, hilite and 2 or 1.5) | |
screen.fill() | |
end | |
function updateball(b) | |
b.x = b.x + math.sin(b.a)*b.v | |
b.y = b.y + math.cos(b.a)*b.v | |
ledx = math.ceil(b.x/8) | |
ledy = math.ceil(b.y/8) | |
--print (ledx) | |
--print (ledy) | |
gr.led(ledx,ledy,6) | |
local minx = 2 | |
local miny = 2 | |
local maxx = 126 | |
local maxy = 62 | |
if b.x >= maxx then | |
b.x = maxx | |
b.a = 2*math.pi - b.a | |
enqueue_note(b, 0) | |
elseif b.x <= minx then | |
b.x = minx | |
b.a = 2*math.pi - b.a | |
enqueue_note(b, 1) | |
elseif b.y >= maxy then | |
b.y = maxy | |
b.a = math.pi - b.a | |
enqueue_note(b, 2) | |
elseif b.y <= miny then | |
b.y = miny | |
b.a = math.pi - b.a | |
enqueue_note(b, 3) | |
end | |
end | |
function enqueue_note(b, z) | |
local f = freqs[b.n] | |
if z == 0 then | |
f = f * 2 | |
elseif z == 1 then | |
f = f / 2 | |
end | |
table.insert(freq_queue, f) | |
end | |
function play_notes() | |
while #freq_queue > 0 do | |
engine.hz(table.remove(freq_queue)) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment