S2E1 Found Shapes
nb. descriptive hyperlinks connect to timestamped moments in the video above
an overview of the concepts that will be covered:
- sequins
- clocks
- between the two: instant sequencer-style things
within the episode, Trent executes crow commands via druid on the left side of the screen while taking longform notes in a text editor on the right side of the screen. also within the episode, Trent receives a package – it is unknown what the package contains. perhaps it’s unimportant, but it seems to have captured the imagination of the live viewers.
clean slate
to begin, let’s make sure our crow isn’t doing anything else but what we tell it to by executing the following in druid:
crow.reset()
making events happen in musical time
crow v3 borrows the concept of a ‘clock’ from norns. this just means that crow has a built-in understanding of tempo (eg. 98 bpm), which means you can execute events on a quantized beat/tick (either on a recurring timed loop or as a single execution). these events can be notes or modulations or anything you want – the important thing is that you can lock these to occur in musical time. this is super rad, because it allows you execute part of a program in specified intervals, whereas ‘normal’ program flow tries to execute all events as instantaneously as possible.
we do this by using a function named clock.run
, which lets crow know to look out for a few things:
- an event we’d like to execute in musical time
- to which beat interval we’d like to sync this event’s execution
- whether that event should execute again and again, or just once
watch Trent explain and set up a clock.run
function. note that Trent is writing this in the text editor, which can be uploaded to crow as a script later on. for the purposes of this document, we’ll be executing single lines via druid.
check + change tempo
to check the current tempo of your crow, execute:
print(clock.tempo)
to change the tempo to (for example) 150 bpm, simply execute:
clock.tempo = 150
since clock.tempo
is just a variable, it can also be used in equations like this:
ii.wdel.time(60/clock.tempo) -- sets w/'s delay time to a quarter note length at the current bpm
or like this:
clock.tempo = clock.tempo/2
make a note every beat
at this point in the video, Trent uses a special protocol and command to communicate to another module’s (w/) digital synthesis mode:
clock.run(function() while true do clock.sync(1); ii.wsyn.play_note(0,0.9) end end)
if you don’t have access to this module, here’s a version of the code he’s written which will send v/8 CV to crow output 1 and a trigger pulse to crow output 2:
clock.run(function() while true do clock.sync(1); output[1].volts = 0.9; output[2](pulse()) end end)
to clear all running clocks, execute:
clock.cleanup()
establishing a sequence with sequins
watch Trent get bored and figure out how to solve his boredom with sequins.
sequins is a library that’s built in crow v3. it provides a framework to store values, sequence them, and pass these values to other functions across crowspace.
to define a sequence, we create a variable which stores and accesses a sequins. try executing this in druid:
mys = sequins{0,2,4,7,9}
this establishes mys
as a sequins-capable function. we assigned mys
a table of semitones, which will automatically be stepped through every time we execute mys()
.
so, to iterate through the table, execute:
print( mys() )
…again and again and again.
you’ll get:
> print( mys() )
0
> print( mys() )
2
> print( mys() )
4
every time we execute mys()
, it will return the next step’s value, eg:
> print( mys(), mys(), mys() )
7 9 0
while it’s easier to think about sequences in semitones, you’ll often want to pass raw voltage to your crow destinations. to convert a semitone to voltage, just divide it by 12, eg
> print( mys()/12 )
0.3333333
running our sequence
prettified w/syn code:
mys = sequins{0,2,4,7,9}
clock.run(
function()
while true do
clock.sync(1)
ii.wsyn.play_note(mys()/12,0.9)
end
end
)
one-line w/syn code:
mys = sequins{0,2,4,7,9}; clock.run(function() while true do clock.sync(1); ii.wsyn.play_note(mys()/12,0.9) end end)
if you don’t have access to this module, here’s a version of the code he’s written which will send v/8 CV to crow output 1 and a trigger pulse to crow output 2.
prettified v/8 + pulse code:
mys = sequins{0,2,4,7,9}
clock.run(
function()
while true do
clock.sync(1)
output[1].volts = mys()/12
output[2](pulse())
end
end
)
one-line v/8 + pulse code:
mys = sequins{0,2,4,7,9}; clock.run(function() while true do clock.sync(1); output[1].volts = mys()/12; output[2](pulse()) end end)
changing sequence step size
watch Trent change the size of the sequins step
to modify the step size of a sequins while its running, execute:
mys:step(2)
…which will increment by 2 steps instead of the default 1.
creating ‘presets’ + switching between them
watch Trent duplicate a sequins current configuration
since a sequins is just a variable (for us so far, mys
), we can copy it for further experimentation or posterity very easily.
to make a copy of the current sequence, execute:
mys1 = mys
this allows us to freely redefine mys
while the sequence is running:
mys = sequins{0,3,6,9,12,15,18,21}
notice that when we redefine mys
, it steps by 1 (even if you had previously applied a step modification). this is because we are forcing mys
to forget what it used to know, which includes the step size. if you execute:
mys = mys1
you’ll get back to your previous settings, including any step size mods!
sequins-ing time
watch Trent use another sequins to modify clock.sync
let’s stop our currently running clocks:
clock.cleanup()
and use myt
to sequence the clock.sync()
division while mys
sequences pitch.
prettified w/syn code:
mys = sequins{0,2,4,7,9}
myt = sequins{1,1,1,1/2,1/2}
clock.run(
function()
while true do
clock.sync(myt())
ii.wsyn.play_note(mys()/12,0.9)
end
end
)
one-line w/syn code:
mys = sequins{0,2,4,7,9}; myt = sequins{1,1,1,1/2,1/2}; clock.run(function() while true do clock.sync(myt()); ii.wsyn.play_note(mys()/12,0.9) end end)
if you don’t have access to this module, here’s a version of the code he’s written which will send v/8 CV to crow output 1 and a trigger pulse to crow output 2.
prettified v/8 + pulse code:
mys = sequins{0,2,4,7,9}
myt = sequins{1,1,1,1/2,1/2}
clock.run(
function()
while true do
clock.sync(myt())
output[1].volts = mys()/12
output[2](pulse())
end
end
)
one-line v/8 + pulse code:
mys = sequins{0,2,4,7,9}; myt = sequins{1,1,1,1/2,1/2}; clock.run(function() while true do clock.sync(myt()); output[1].volts = mys()/12; output[2](pulse()) end end)
to get a little funky, try changing myt
’s step size using what we’ve learned so far!
replacing (only) the values in a sequins
watch Trent replace the values in our time sequins without overwriting the other settings
to retain the current step and step size settings, but change the values in our myt
sequins, execute:
myt:settable{1,1/2,1/2,1/4,1/4,1/8,1/8,1/4}
additional techniques
for the rest of the episode, Trent digs into some extended techniques which mix + remix the concepts above. rather than repeat the baseline information which enables these explorations, we’ll link to moments of particular impact:
- storing scales in sequins
- sequencing sequins
:count
, which captures focus and produces n values in a row before moving on to another sequins- sequins-ing a single position in a sequins
:every
, which produces a value every nth call- sequins-ing
:step
- creating modulation via
clock.sleep
and sequins - generating envelopes + LFOs with crow
- generating chords with sequins, which also showcases how sequins can store + call functions (as well as numbers + strings)