Skip to content
Permalink
9f77383ee2
Go to file
 
 
Cannot retrieve contributors at this time
313 lines (275 sloc) 7.6 KB
-- ??? (nc02-rs)
-- @synthetivv
sc = softcut
dirty = false
next_head = 1
onsets = { -- generated by `aubioonset -t 0.66 -O energy nc02-perc.wav`
0.000000, 0.427479, 0.495688, 0.999646, 1.496604,
1.993625, 2.499792, 2.996063, 3.089292, 3.191354,
3.465250, 4.338583, 4.519729, 4.594812, 4.680313,
4.745062, 4.915563, 4.995354, 5.134729, 5.343125,
5.981979, 6.270688, 6.463500, 6.521500, 6.780729,
7.289479, 7.353229, 7.497542, 7.615104, 7.698021,
7.857584, 7.950875, 8.077105, 8.157979, 8.261771,
8.419791, 8.547334, 8.718875,
10, 11, 12, 13
}
instruments = {
{ o = 11, v = 1, l = 0.45, d = 0.98, e = 0.1 }, -- bd
{ o = 5, v = 0.7, l = 0.5, d = 0.7, e = 0.2 }, -- ch
{ o = 5, v = 0.7, l = 0.5, d = 1, e = 0.5 }, -- oh
{ o = 1, v = 1, l = 0.5, d = 1, e = 0.6 }, -- hc
{ o = 4, v = 1, l = 0.5, d = 0.98, e = 0.7 }, -- sd
{ o = 39, v = 0.3, l = 16, d = 1, e = 0.1 }, -- tonal
{ o = 40, v = 0.3, l = 16, d = 1, e = 0.1 } -- tonal
}
Voice = {}
Voice.__index = Voice
function Voice.new(buffer)
local v = setmetatable({}, Voice)
local head = next_head
next_head = head + 1
sc.enable(head, 1)
sc.buffer(head, buffer)
sc.level(head, 1.0)
sc.loop(head, 0)
sc.loop_start(head, 1)
sc.loop_end(head, 2)
sc.position(head, 0)
sc.fade_time(head, 0.0025)
sc.level_slew_time(head, 0.01)
sc.rate(head, 1.0)
sc.play(head, 1)
sc.level_slew_time(head, 0.01)
v.head = head
v.sidechain_level = 0
v.sidechain_factor = 0.9
return v
end
EchoVoice = {}
EchoVoice.__index = EchoVoice
function EchoVoice.new()
local v = setmetatable(Voice.new(2), EchoVoice)
local head = v.head
sc.loop_start(head, 1)
sc.loop_end(head, 1.125)
sc.loop(head, 1)
sc.position(head, 1)
sc.rate(head, 1/3)
sc.level(head, 1)
sc.rec_level(head, 1)
sc.pre_level(head, 0.5)
sc.rec(head, 1)
sc.play(head, 1)
sc.pre_filter_fc(head, 9000)
sc.pre_filter_dry(head, 0)
sc.pre_filter_lp(head, 1)
sc.pre_filter_rq(head, 0.8)
sc.rate_slew_time(head, 0.3)
return v
end
function EchoVoice:sidechain_decay()
self.sidechain_level = self.sidechain_level * self.sidechain_factor
sc.level(self.head, 1 - self.sidechain_level)
end
PercVoice = {}
PercVoice.__index = PercVoice
function PercVoice.new()
local v = setmetatable(Voice.new(1), PercVoice)
v.tick = 0
v.step_index = 1
v.shift = 0
v.shift_carry = 0
v.send = 0
v.flash_level = 0
v.decay_level = 0
v.instrument = instruments[1]
return v
end
function PercVoice:envelope_decay()
self.decay_level = self.decay_level * self.instrument.d
self.sidechain_level = self.sidechain_level * self.sidechain_factor
local level = self.instrument.v * self.decay_level * (1 - self.sidechain_level)
sc.level(self.head, level)
sc.level_cut_cut(self.head, echo.head, self.send * level)
end
function PercVoice:flash_decay()
if self.flash_level > 0 then
self.flash_level = math.floor(self.flash_level * 0.6)
dirty = true
end
end
function PercVoice:play()
local head = self.head
local start = onsets[self.instrument.o]
local length = self.instrument.l
local length_sec = clock.get_beat_sec(length)
local instrument = self.instrument
local send = 0
if math.random() <= instrument.e then
send = 1
end
sc.loop_start(head, onsets[instrument.o])
sc.loop_end(head, start + length)
sc.position(head, start)
sc.level(head, instrument.v)
sc.level_cut_cut(head, echo.head, send * instrument.v)
sc.play(head, 1)
drums[3].sidechain_level = drums[3].sidechain_level + instrument.v
echo.sidechain_level = echo.sidechain_level + instrument.v
self.send = send
self.decay_level = 1
self.start = start
self.length = length
self.flash_level = 16
end
function PercVoice:run()
self.clock = clock.run(function()
while true do
clock.sync(0.25) -- 16th notes
local tick = self.tick
tick = tick + 1
local step_index = self.step_index
local step = self.pattern[step_index]
if tick > (step._l or step.l) then
tick = 1
step_index = step_index % #self.pattern + 1
step = self.pattern[step_index]
local shift_carry = self.shift_carry
local _l = step.l
if math.random() <= step.r then
_l = _l - shift_carry
shift_carry = 0
end
if math.random() <= step.s then
_l = _l + 1
shift_carry = shift_carry + 1
end
if math.random() <= step.s then
_l = _l - 1
shift_carry = shift_carry - 1
end
self.shift_carry = shift_carry
step._l = _l
self.instrument = instruments[step.i]
if math.random() <= step.p then
self:play()
end
self.step_index = step_index
end
self.tick = tick
end
end)
end
function PercVoice:stop()
if self.clock ~= nil then
clock.cancel(self.clock)
end
end
echo = EchoVoice.new()
drums = {}
for d = 1, 3 do
local drum = PercVoice.new()
drum.start = d
drum.length = 0.25
drum.rate = 0.25
drums[d] = drum
end
drums[1].start = onsets[11] -- kick
drums[1].length = 0.45
drums[2].decay_factor = 0.98
drums[1].pattern = {
{ p = 1, i = 1, l = 4, s = 0.25, r = 0.7 },
{ p = 0.33, i = 1, l = 2, s = 0.25, r = 0.5 },
{ p = 0.05, i = 4, l = 2, s = 0.25, r = 0.5 },
{ p = 1, i = 1, l = 4, s = 0.25, r = 0.7 },
{ p = 0.1, i = 4, l = 4, s = 0.25, r = 0.5 }
}
drums[2].pattern = {
{ p = 0.2, i = 2, l = 2, s = 0, r = 1 },
{ p = 0.8, i = 2, l = 2, s = 0, r = 1 },
{ p = 0.2, i = 3, l = 2, s = 0, r = 1 },
{ p = 0.8, i = 2, l = 2, s = 0, r = 1 }
}
drums[3].start = 11
drums[3].length = 16
drums[3].sidechain_factor = 0.9
drums[3].decay_factor = 1
drums[3].pattern = {
{ p = 1, i = 7, l = 16, s = 0, r = 0.25 },
{ p = 0.2, i = 7, l = 8, s = 0, r = 0.25 },
{ p = 0.2, i = 7, l = 8, s = 0, r = 0.25 },
{ p = 0.7, i = 7, l = 16, s = 0, r = 0.25 },
{ p = 1, i = 7, l = 8, s = 0, r = 0.25 },
{ p = 0.2, i = 7, l = 8, s = 0, r = 0.25 },
{ p = 0.2, i = 7, l = 8, s = 0, r = 0.25 }
}
sc.rate(drums[3].head, 2)
function load_file(filename, buffer, buffer_start)
local path = _path.code .. 'nc02-rs/lib/' .. filename
sc.buffer_read_mono(path, 0, buffer_start, -1, 1, buffer) -- -1 = read whole file, I guess?
end
envelope_metro = metro.init()
envelope_metro.time = 0.01
envelope_metro.event = function()
for d = 1, 3 do
drums[d]:envelope_decay()
end
end
redraw_metro = metro.init()
redraw_metro.time = 1/15
redraw_metro.event = function()
for d = 1, 3 do
drums[d]:flash_decay()
end
if dirty then
redraw()
end
end
flutter_metro = metro.init()
flutter_metro.time = 0.3
flutter_metro.event = function()
local deviation = (math.random() - 0.5) * 0.05
sc.rate(echo.head, 1/3 * math.pow(2, deviation))
end
function init()
load_file('nc02-perc.wav', 1, 0)
load_file('nc02-tonal.wav', 1, 10)
params:set('clock_tempo', 120)
drums[1]:run()
drums[2]:run()
drums[3]:run()
envelope_metro:start()
redraw_metro:start()
flutter_metro:start()
end
function enc(n, d)
if n == 3 then
params:delta('drum_onset', d)
end
end
function redraw()
screen.clear()
for d = 1, 3 do
local drum = drums[d]
local x = 26 + (d - 1) * 32
screen.level(drum.flash_level)
screen.rect(x, 27, 10, 10)
screen.fill()
for e = 1, 4 do
screen.level(math.floor(drum.send * drum.flash_level / (e + 1)))
screen.move(x, 37 + e * 3)
screen.line_rel(10, 0)
screen.stroke()
screen.move(x, 28 - e * 3)
screen.line_rel(10, 0)
screen.stroke()
end
end
screen.update()
end
function cleanup()
redraw_metro:stop()
envelope_metro:stop()
flutter_metro:stop()
end