"Performers" can handle melodies

This commit is contained in:
2024-03-16 16:23:31 -07:00
parent 6bcbb0524c
commit fa282184a9
6 changed files with 125 additions and 19 deletions

31
shared/instrument.lua Normal file
View File

@ -0,0 +1,31 @@
instrument=klass()
function instrument:init(callback)
self.callback=callback
self.volume=1.0
end
function instrument:spackle(track,channel,t0,t1,note,verbs)
-- a one-indexed table of note data
-- (one-indexed because Lua kind of sucks)
local nflagses,keep_silence=self.callback(t1-t0,note,instrument_split_verbs(verbs))
for i,nflags in pairs(nflagses) do
if nflags.v>0 or keep_silence then
nflags = nflags:clone() -- avoid breaking instrument
local min_v=0
if (nflags.v>0) min_v = 1
nflags.v = mid(flr(nflags.v * self.volume + 0.5),min_v,7)
track:plot(channel,t0+i-1,nflags)
end
end
end
instrument_split_verbs=function(x)
if (not x) return {}
local t={}
for i in all(split(x)) do
t[i]=true
end
return t
end

View File

@ -9,6 +9,10 @@ function nflags:init(o)
self:validate()
end
function nflags:clone()
return nflags:new(self)
end
function nflags:validate()
local c,e,v,w,p
=self.c,self.e,self.v,self.w,self.p

28
shared/performer.lua Normal file
View File

@ -0,0 +1,28 @@
performer=klass()
function performer:init(track,channel,instrument,time,roots)
assert_range(#roots,1,33,"#roots")
self.track=track
self.channel=channel
self.instrument=instrument
self.time=time
self.roots=roots
self.selected_root=1
end
function performer:root(root)
assert_range(root,1,#self.roots,"root")
self.selected_root=root
end
function performer:play(duration,note,verbs)
local base=self.roots[self.selected_root]
local note=base+note
local t0=self.time
local t1=t0+duration
self.time+=duration
self.instrument:spackle(self.track,self.channel,t0,t1,note,verbs)
end
function performer:rest(duration)
self.time+=duration
end

View File

@ -31,13 +31,13 @@ function track:pattern(channel,offset)
return self.frames[offset+1][channel+1]
end
function track:plot(channel,offset,inst)
function track:plot(channel,offset,ndata)
assert_range(channel,0,4,"channel")
assert_range(offset,0,self.next_frame_start,"offset")
local tup=self.ix_to_frame[offset]
assert(tup) -- should be unable to fail
local frame,offset=unpack(tup)
self.frames[frame+1][channel+1]:plot(offset,inst)
self.frames[frame+1][channel+1]:plot(offset,ndata)
end
function track:build(
@ -73,6 +73,6 @@ function track:build(
for i=0,3 do
poke(fmaddr+i,map_to_real_pattern(self.frames[frame][i+1]))
end
fmaddr+=1
fmaddr+=4
end
end