Skip to content

Instantly share code, notes, and snippets.

@trentgill
Last active March 21, 2021 01:34
Show Gist options
  • Save trentgill/fbc5b32c85b0ca4a4a56df93f98992d1 to your computer and use it in GitHub Desktop.
Save trentgill/fbc5b32c85b0ca4a4a56df93f98992d1 to your computer and use it in GitHub Desktop.
demonstrating usage of the forthcoming 'sequins' lua library for ordering values
--- sequins.
-- a demonstration
engine.name = 'PolyPerc'
local MusicUtil = require "musicutil"
-- TODO operate by reference so the scale can change without recreating the sequin
dim = {3,6,9,15,18,21,-6}
bass = {-6,-12,-15}
lyd = {12,14,16,18,19,9,11,24}
function init()
local s = sequins --alias for brevity
-- create our sequin which interleaves the playback of two tables of notes (from above)
local mysequin =
s.new( { s.new( bass, 'rand' )
, s.count( 3, s.new( dim, 'next' ) )
}
, 'next' )
-- iniates a timebase which will pull a note from the sequin on each step
myarp = run_arp( play_note
, mysequin
, 1/4
)
end
function play_note(v)
v = v + 48 -- shift up to good range
local freq = MusicUtil.note_num_to_freq(v)
engine.hz(freq)
end
function run_arp(fn,seq,sync)
return clock.run(
function()
while true do
clock.sync(sync)
fn( seq() )
end
end)
end
--- TODO this is a new file called sequins.lua
sequins = {}
-- arg1: value table eg{0,2,4,7,9}
-- arg2: behaviour enum:{'next','prev',rand','drunk'} -- n as next#
-- retv: function that generates the next note
function sequins.new( vals, behaviour )
local ix = 1
local function generate()
local newix = 0
if behaviour == 'next' then
newix = ix + 1
elseif behaviour == 'prev' then
newix = ix - 1
elseif behaviour == 'rand' then
newix = math.random(#vals)
elseif behaviour == 'drunk' then
newix = ix + math.random(-1,1)
end
-- clamp to vals table length
while newix < 1 do newix = newix + #vals end
while newix > #vals do newix = newix - #vals end
local val = vals[newix]
-- currently we explictly step the index forward in some cases but not others
-- ideally this would be cleaned up & have a single return point
if type(val) == 'function' then
local v, action = val() -- allows nested tables
if action == 'skip' then
ix = newix -- nb: doesn't matter if it's before/after recursion
return generate( vals, behaviour )
elseif action == 'again' then
-- ix stays the same!
else -- was a nested table, but just returned a value (no action)
ix = newix
end
return v
else -- assume a number
ix = newix
return val
end
end
return generate -- named function so we can use recursion inside
end
-- returns a value on everyth call. otherwise instructs the caller to skip it.
function sequins.every( everyth, sequin )
local e = everyth
return
function()
e = e%everyth +1
if e == 1 then
return sequin()
else
return 0, 'skip'
end
end
end
-- returns count values in a row, stopping the calling sequin from moving forward until count is exhausted
function sequins.count( count, sequin )
local c = count
return
function()
c = c%count +1
if c == 1 then
print'match'
return sequin()
else
return sequin(), 'again'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment