Skip to content

Instantly share code, notes, and snippets.

@okyeron
Last active September 16, 2018 17:41
Show Gist options
  • Save okyeron/cd3d30223669c46270199db6b3c14aac to your computer and use it in GitHub Desktop.
Save okyeron/cd3d30223669c46270199db6b3c14aac to your computer and use it in GitHub Desktop.
rebound by nf adding basic grid support (for 256)
-- 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