hotswap
This new library is designed for live-coding style interactions. It provides some simple syntax helpers for the sequins
and timeline
libraries so you can modify your compositions on the fly. Before diving in here, it’s highly recommended to have a solid grip on how both of these other libraries work!
Fundamentally, hotswap
is just a global table that you can save your sequins & timelines into. Using some lua magic (metatables), we’re able to update a sequins or timeline as it’s playing, preserving the current state of that object. Let’s start with a sequins object in a clock
routine that plays a melody to the outputs:
function init()
notes = sequins{0,4,7,11} -- major 7th arpeggio
output[2].action = ar() -- assign a simple AR envelope to output 2
clock.run(function()
while true do
clock.sync(1)
output[1].volts = notes()/12 -- convert the next sequins value to volts
output[2]() -- execute an AR envelope
end
end)
end
This script will happily arpeggiate away on a major 7th chord. But what if we want to change the chord?
>>> druid
> notes = sequins{0,3,7,10} -- change to minor 7th
This will work just fine; however, whenever you call the line above, the arpeggio will be reset to the root note of the arpeggio. That’s ok for exploration, but if you’re performing live you’ll very likely want to be able to switch on the fly! That’s where hotswap
comes in.
Just place the notes
variable inside the hotswap
table:
hotswap.notes = sequins{0,4,7,11}
And now we can update it via druid without missing a beat!
>>> druid
> hotswap.notes = sequins{0,3,7,10} -- minor 7th!
The arpeggio will switch to a minor 7th seamlessly, no matter when you call it!
hotswap and timeline
To get to the true power of hotswap
though, we’ll use it for a timeline
object rather than just a sequins
. We’ll create the arpeggio as before, but add another sequins
to create a more complex rhythm:
function init()
output[2].action = ar() -- assign a simple AR envelope to output 2
hotswap.pattern = timeline.loop{ sequins{3,3,2}, {make_note, sequins{0,4,7,11}}}
end
function make_note(v)
output[1].volts = v/12 -- assign the next note as a voltage
output[2]() -- execute an AR envelope
end
Notice that the make_note
function has been pulled out to separate the timing / sequence logic from the note-generation logic. More importantly, see how the whole timeline
has been assigned into the hotswap
table. We can now apply a sequence of transformations in druid
to take a tiny composition in new directions:
>>> druid
-- first we change the rhythm
> hotswap.pattern = timeline.loop{ sequins{3,2,3}, {make_note, sequins{0,4,7,11}}}
-- now switch to half-diminished chord
> hotswap.pattern = timeline.loop{ sequins{3,2,3}, {make_note, sequins{0,3,6,10}}}
-- too much tension! make it minor 7th
> hotswap.pattern = timeline.loop{ sequins{3,2,3}, {make_note, sequins{0,3,7,10}}}
As you make these modifications you’ll hear the sequence carry on, and your changes are gradually introduced.
The above example code gets pretty long in druid
which we can address in two ways. Firstly, it’s idiomatic to alias the libraries to 1 or 2 letter abbreviations at the top of your script. Simply add the following before init
:
s = sequins
tl = timeline
hs = hotswap
This brings us down to:
>>> druid
> hs.pattern = tl.loop{ s{3,2,3}, {make_note, s{0,4,7,11}}}
But we can also pull out the inner-sequins into their own hotswap
variables if you just want to manage them individually. Here’s an updated version of the script which creates rhythm
and melody
hotswap variables for seamless modification:
s = sequins
tl = timeline
hs = hotswap
function init()
output[2].action = ar() -- assign a simple AR envelope to output 2
hs.rhythm = s{3,3,2}
hs.melody = s{0,4,7,11}
hs.pattern = tl.loop{ hs.rhythm, {make_note, hs.melody}}
end
function make_note(v)
output[1].volts = v/12 -- assign the next note as a voltage
output[2]() -- execute an AR envelope
end
This gives us a tight little API for manipulating our composition on the fly:
>>> druid
> ^^r -- run our script
> hs.rhythm = s{3, 3.1, 1.9} -- get it swinging~~
> hs.melody = s{0,3,7,10}
> hs.melody = s{0,3,7,10,14} -- add the 9th
> hs.melody = hs.melody:step(2) -- now step through the arp hitting every 2nd note
Tech Note
hotswap
is just calling the sequins:settable
and timeline:hotswap
methods. The key is that it prevents you from having to change the syntax of each call when live-coding. You just freely re-assign the objects as if you were creating them for the first time.
When you change the structure of either object, hotswap
will do it’s best to navigate the change – it will preserve the state of all the previously existing elements. Swapping a sequins
element for a nested sequins
will work just fine, as will applying the flow-modifiers (:count
, :every
etc).
This implementation leaves open the possibility of adding this feature to other stateful classes in the future. One thing that may be added is the function-tables of timeline
, and perhaps asl
structures (but that’s a big maybe).
Closing
hotswap
doesn’t add any dramatic new sonic capability, but it can make live-coding experience on crow much more satisfying & immediate!