Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
159 lines (139 sloc) 3.88 KB
local BeatClock = {}
BeatClock.__index = BeatClock
function BeatClock.new(name)
local i = {}
setmetatable(i, BeatClock)
i.name = name or ""
i.playing = false
i.ticks_per_step = 6
i.current_ticks = i.ticks_per_step - 1
i.steps_per_beat = 4
i.beats_per_bar = 4
i.step = i.steps_per_beat - 1
i.beat = i.beats_per_bar - 1
i.external = false
i.send = false
i.midi = false
i.metro = metro.alloc()
i.metro.count = -1
i.metro.callback = function() i:tick() end
i:bpm_change(110)
i.on_step = function(e) print("BeatClock executing step") end
i.on_start = function(e) end
i.on_stop = function(e) end
i.on_select_internal = function(e) print("BeatClock using internal clock") end
i.on_select_external = function(e) print("BeatClock using external clock") end
i:enable_midi()
return i
end
function BeatClock:start(dev_id)
self.playing = true
if not self.external then
self.metro:start()
end
self.current_ticks = self.ticks_per_step - 1
if self.midi and self.send then
for id, device in pairs(midi.devices) do
if id ~= dev_id then
device:send({251})
end
end
end
self.on_start()
end
function BeatClock:stop(dev_id)
self.playing = false
self.metro:stop()
if self.midi and self.send then
for id, device in pairs(midi.devices) do
if id ~= dev_id then
device:send({252})
end
end
end
self.on_stop()
end
function BeatClock:advance_step()
self.step = (self.step + 1) % self.steps_per_beat
if self.step == 0 then
self.beat = (self.beat + 1) % self.beats_per_bar
end
self.on_step()
end
function BeatClock:tick(dev_id)
self.current_ticks = (self.current_ticks + 1) % self.ticks_per_step
if self.playing and self.current_ticks == 0 then
self:advance_step()
end
if self.midi and self.send then
for id, device in pairs(midi.devices) do
if id ~= dev_id then
device:send({248})
end
end
end
end
function BeatClock:reset(dev_id)
self.step = self.steps_per_beat - 1
self.beat = self.beats_per_bar - 1
self.current_ticks = self.ticks_per_step - 1
if self.midi and self.send then
for id, device in pairs(midi.devices) do
if id ~= dev_id then
device:send({250})
if not self.playing then -- force reseting while stopped requires a start/stop (??)
device:send({252})
end
end
end
end
end
function BeatClock:clock_source_change(source)
self.current_ticks = self.ticks_per_step - 1
if source == 1 then
self.external = false
if self.playing then
self.metro:start()
end
self.on_select_internal()
else
self.external = true
self.metro:stop()
self.on_select_external()
end
end
function BeatClock:bpm_change(bpm)
self.bpm = bpm
self.metro.time = 60/(self.ticks_per_step * self.steps_per_beat * self.bpm)
end
function BeatClock:add_clock_params()
params:add_option("clock", "clock", {"internal", "external"}, self.external or 2 and 1)
params:set_action("clock", function(x) self:clock_source_change(x) end)
params:add_number("bpm", "bpm", 1, 480, self.bpm)
params:set_action("bpm", function(x) self:bpm_change(x) end)
params:add_option("clock_out", "clock out", { "no", "yes" }, self.send or 2 and 1)
params:set_action("clock_out", function(x) if x == 1 then self.send = false else self.send = true end end)
end
function BeatClock:enable_midi()
self.midi = true
end
function BeatClock:process_midi(data)
if self.midi then
status = data[1]
data1 = data[2]
data2 = data[3]
if self.external then
if status == 248 then -- midi clock
self:tick(id)
elseif status == 250 then -- midi clock start
self:reset(id)
self:start(id)
elseif status == 251 then -- midi clock continue
self:start(id)
elseif status == 252 then -- midi clock stop
self:stop(id)
end
end
end
end
return BeatClock