Last active
July 27, 2024 04:40
-
-
Save dndrks/48affab46f87bcebac252bb17393db77 to your computer and use it in GitHub Desktop.
W/Tape: i2c recording sequencer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- W/Tape: i2c recording sequencer | |
-- as shown in https://youtu.be/2RUHr-iX1VE?si=Ny_3t0TNqKlAaWoQ&t=1216 | |
-- requires crow | |
-- patch crow output 1 to an oscillator's v/8 | |
-- patch crow output 2 to an envelope generator | |
-- execute 'auto_rec()' to start recording loops at different speeds | |
-- execute 'auto_play()' to play through each of the loops | |
tl = timeline | |
function init() | |
notes = sequins{0, 4, 7, 9, 11} | |
clock.run(play_note) | |
clock.run(trigger_envelope) | |
record_speeds = {1, 0.5, 2, 2/3} -- for 'auto_rec()' | |
record_duration = 12 -- 12 beats of recording | |
playback_durations = {8, 6, 12, 14} -- for 'auto_play()' | |
-- keep track of our loop points and their playback speeds: | |
loops = { | |
id = {}, | |
speed = {} | |
} | |
loop_index = 1 | |
-- default state: | |
ii.wtape[1].loop_active(0) -- no loop | |
ii.wtape[1].speed(1) -- 1x playback | |
ii.wtape[1].record(0) -- no recording | |
-- clear all audio (optional): | |
-- ii.wtape[1].WARNING_clear_tape() | |
end | |
function play_note() | |
while true do | |
clock.sync(1/3) | |
output[1].volts = notes()/12 | |
end | |
end | |
function trigger_envelope() | |
while true do | |
clock.sync(1 / 2) | |
state = state == 10 and 0 or 10 | |
output[2].volts = state | |
end | |
end | |
-- a callback event for 'loop_start' commands: | |
ii.wtape[1].event = function(event, value) | |
if event.name == 'loop_start' then | |
ii.wtape[1].timestamp(value) -- move tape playback to the value | |
ii.wtape[1].loop_active(1) -- activate looping | |
end | |
end | |
function auto_rec() | |
tl.score{ | |
0, function() capture_loop(record_speeds[1]) end, | |
record_duration, function() capture_loop(record_speeds[2]) end, | |
record_duration * 2, function() capture_loop(record_speeds[3]) end, | |
record_duration * 3, function() capture_loop(record_speeds[4]) end, | |
} | |
end | |
function auto_play() | |
tl.loop{ | |
playback_durations[1], function() jump_to_loop(1) end, | |
playback_durations[2], function() jump_to_loop(2) end, | |
playback_durations[3], function() jump_to_loop(3) end, | |
playback_durations[4], function() jump_to_loop(4) end, | |
} | |
end | |
function capture_loop(speed) | |
speed = speed and speed or 1 | |
local next_loop = false | |
if loops.id[loop_index] then | |
next_loop = true | |
ii.wtape[1].loop_next(1) | |
loop_index = loop_index + 1 | |
print("next loop", loop_index) | |
end | |
tl.score{ | |
0, | |
function() | |
if not next_loop then | |
print("loop start") | |
ii.wtape[1].loop_start() | |
else | |
print("jump to start") | |
ii.wtape[1].get("loop_start") | |
end | |
ii.wtape[1].play(1) | |
ii.wtape[1].record(1) | |
ii.wtape[1].speed(1) | |
end, | |
3, | |
function() | |
if not next_loop then | |
print("loop end") | |
ii.wtape[1].loop_end() | |
end | |
ii.wtape[1].record(0) | |
ii.wtape[1].speed(speed) | |
loops.id[loop_index] = true | |
loops.speed[loop_index] = speed | |
end | |
} | |
end | |
function jump_to_loop(id) | |
if loops.id[id] then | |
local move_by = id - loop_index | |
if move_by < 0 then | |
for i = move_by,-1 do | |
ii.wtape[1].loop_next(-1) | |
end | |
else | |
for i = 1,move_by do | |
ii.wtape[1].loop_next(1) | |
end | |
end | |
print("jumping by "..id - loop_index) | |
ii.wtape[1].get("loop_start") | |
ii.wtape[1].speed(loops.speed[id]) | |
loop_index = id | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment