Skip to content

Instantly share code, notes, and snippets.

@trentgill
Last active February 16, 2022 00:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trentgill/84ec5b68816eb03508566addb5a41dd4 to your computer and use it in GitHub Desktop.
Save trentgill/84ec5b68816eb03508566addb5a41dd4 to your computer and use it in GitHub Desktop.
crow v3.1 livecoding & sequencing propositions
--- new elements for sequencing fun!
----------------------------------------------------------------------
----------------------------------------------------------------------
s = sequins
-- table call with a string is treated as a table of chars
cs = s"abcd" -- equivalent to s{'a','b','c','d'}
-- deep copy
s1 = s{1,2,3}
s2 = s1:copy()
-- arithmetic metamethods on sequins
s3 = ~s2
s4 = s2 + 1
s5 = s2 - 2
s6 = s2 * 3
s7 = s2 / 12
s8 = s2 % 5
-- permutation focused
-- :transform(operation)
-- switch on or off / change to a different transform
-- want to keep the original sequins as the core reference
s10 = s{1,2,3} + s{4,5}
-- 5,6,7,6,7,8 -- sequential
-- 5,7,7, -- interleaved
-- synthesis focused
-- patterned transformation (combining multiple sequins)
-- :flatten
-- print a sequins with it's transformations
-- :settable to handle nested sequins
s9 = s{1, s{2,3}}
s9:settable{1, s{4,5}} -- currently s{4,5} is replaced, not updated
----------------------------------------------------------------------
----------------------------------------------------------------------
tl = timeline
-------------------------------------
--- timeline.loop
-- table of beat-duration (clock.sync units), action (functions) pairs
tl{duration, action}
-- table can be n-pairs long
t1{ duration, action
, duration, action
} -- etc.
mykick = tl{1, function() output[1]() end}
mykick.stop()
-- either or both of duration & action can be sequins
tl{ s{2,2,1}, s{kick,hats} }
tl{ s"x x x", s{kick,hats} } -- could support this string natively
rs = s"x x x"
rs = s"x xx"
rs = s"x x x "
tl{ rs, s{kick,hats} } -- could support this string natively
-- action can be a table which will call arg[1] with args[2..n]
tl(1, {ii.wsyn.play_note, 0, 2})
-- any action table element (fn and args) may be a sequins
tl(1, {ii.wsyn.play_note, s{0,2,4,7,9}:step(2), 2})
sq1 = s{0,2,4,7,9}:step(2)
tl(1, {ii.wsyn.play_note, sq1, 2})
-- predicate methods may stop looping
-- predicates are fns or sequins
tl{}:unless(p) -- loop unless p (or p()) is true
tl{}:times(n) -- shortcut for countdown closure in :unless
tl{}:once() -- sugar for :unless(true)
-- timelines will, by default, wait until clock.sync(1) to start
-- use a bigger val for bars, or `0` for no-sync
-- [implementation note: might need to precede .loop]
tl{}:sync(n)
-- quantization
-- global vs local
tl.quantization(4) -- global
-------------------------------------
--- timeline.score
-- relative-beats instead of duration
-- same ability re: n-pairs, sequins, action-tables
tl.score{ 0, kick
, 1, snare
, 3, snare
}
-- scores can be looped with the special timeline.reset function
tl.score{ 0, kick
, 64, snare
, 256, tl.reset -- reset counter and start again
}
-- if we have access to sequins arithmetic...
stimings = s{0,64,256}
tl.score{ stimings, s{kick, snare, s{tl.reset}:every(16)}
}
stimings = stimings * 2 -- slow down the whole composition
-- timeline.reset can take a predicate function for conditional looping
tl.score{ 0, kick
, 2, snare
, 4, {tl.reset, function() return math.random() > 0.5 end}
}
----------
-- alt .score repetition
-- feels like reset as a line item is awkward. can we method?
tl.score{ 0, {kick, snare}
, 0, snare
, 2, snare
}:reset(4)
-- timeline.reset can take a predicate function for conditional looping
tl.score{ 0, kick
, 2, snare
}:reset(4, {tl.reset, function() return math.random() > 0.5 end})
-- optionally change the start-sync to other than clock.sync(1)
tl.score{}:sync(n)
-- QUESTION
-- what feels most natural to call multiple events at the same time?
-------------------------------------
--- timeline.stamp
-- absolute time version of score (seconds, not beats)
tl.stamp{ seconds, action
, ...
}
-- optionally change the start-sync to other than clock.sync(1)
tl.stamp{}:sync(n)
-- naming?!
----------------------------------------------------------------------
----------------------------------------------------------------------
fox = foxdot
-- naming?
-- collection of (character -> function) mappings
-- step-sequence city!
-- register events by assigning fox keys to functions
fox['+'] = kick -- can just be a function name
fox['-'] = snare
fox.X = function() print'X' end -- or an anonymous fn
fox['9'] = function() for i=1,4 do output[i]() end end -- key must be a char!
-- ^ this is the character '9' not the number 9
-- integeration with timeline
tl{1, {fox, s"+ -- "}}
-- eg: swinging step sequencer
d1 = tl{s{1,2}, {fox, s"+ -- "}}
----------------------------------------------------------------------
----------------------------------------------------------------------
hs = hotswap
-- problem:
s1 = s{1,2,3}
s1() --> 1
s1 = s{4,5,6} -- will reset to first element
s1() --> 4, but we want 5
-- current workaround:
s1 = s{1,2,3}
s1:settable{4,5,6} -- but uses different syntax
-- proposed solution:
hs.s1 = s{1,2,3} -- put the sequins in the hotswap table
s1() --> 1
hs.s1 = s{4,5,6}
s1() --> 5, now we maintain the index & just swap the data
-- same for timelines (maintain reference beat)
-- support anonymous sequins inside timelines
-- eg foxdot
hs.f1 = s"+ -- "
hs.f1 = tl{1, {fox, s.f1}}
hs.f1 = s"+ +- " -- modify the sequins on the fly
hs.f1 = s"X -- --"
---------------
//////////// recap
send the executable script to the gang.
sequins arithmetic operators
- have a :transform() method to apply changes
- want to maintain focus on the original sequins
- the transform can be flattened with :flatten() or :copy('flatten')
- transforms are themselves objects which can be copied / swapped
livecode helpers
- when :methods are called, print a record of the effect
- better introspection to visualize what your code is doing
-> answers: is my code doing what i want it to?
-> helps develop trust in the tool more rapidly
- switchable (globally?) so it's not too noisy
permutations
auto-completion in REPL (ie ii.jf.<tab> displays all jf functions)
tl.score
- great at addressing a weakpoint of norns too
- currently it's hard to do this stuff without manually managing indexing
launch-quantization (aka :sync)
- another weakpoint of norns / crow
- key to be able to say "at this point in the future" do a thing
- could be global or diff syntax form for delayed start
record events as they happen so they can replayed
- assume that the thing i'm doing with code is a "performance"
- this is an instrument
- typing in a repl is equivalent to playing midi keyboard
- so why can't i record them both!
just flip a record flag and commit every event to a timeline!!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment