"Performers" can handle melodies

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

View File

@ -2,8 +2,10 @@ pico-8 cartridge // http://www.pico-8.com
version 42 version 42
__lua__ __lua__
#include shared/_meta.lua #include shared/_meta.lua
#include shared/instrument.lua
#include shared/nflags.lua #include shared/nflags.lua
#include shared/pattern.lua #include shared/pattern.lua
#include shared/performer.lua
#include shared/pflags.lua #include shared/pflags.lua
#include shared/track.lua #include shared/track.lua
#include unique.lua #include unique.lua
@ -15,10 +17,11 @@ __gfx__
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__sfx__ __sfx__
010f2000000500c05007055030421c03028030230351f022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010f20001e2241e2201e22525224252202522523224232222322521224202241e2241c2241c2251a2241a22519224192201922023224232202322022224222222222222225000001c2241e224202242122423224
010f20000000007040130400e0450a032230302f0302a035260220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010f2000252242522523224232252a2242a2252c2242c2252d2242d2252f2242d2242c2242c2252a2242a22528224282252a22428224262242622528224262242522425220252202522500000000000000000000
010f200000000000000e0401a04015045110322a03036030310352d02200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010f200000000000000e0401a04015045110322a03036030310352d02200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
010f200000000000000000015040210401c04518032310203d0203802534012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010f200000000000000000015040210401c04518032310203d0203802534012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__music__ __music__
00 00010203 00 00404040
00 01404040

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() self:validate()
end end
function nflags:clone()
return nflags:new(self)
end
function nflags:validate() function nflags:validate()
local c,e,v,w,p local c,e,v,w,p
=self.c,self.e,self.v,self.w,self.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] return self.frames[offset+1][channel+1]
end end
function track:plot(channel,offset,inst) function track:plot(channel,offset,ndata)
assert_range(channel,0,4,"channel") assert_range(channel,0,4,"channel")
assert_range(offset,0,self.next_frame_start,"offset") assert_range(offset,0,self.next_frame_start,"offset")
local tup=self.ix_to_frame[offset] local tup=self.ix_to_frame[offset]
assert(tup) -- should be unable to fail assert(tup) -- should be unable to fail
local frame,offset=unpack(tup) local frame,offset=unpack(tup)
self.frames[frame+1][channel+1]:plot(offset,inst) self.frames[frame+1][channel+1]:plot(offset,ndata)
end end
function track:build( function track:build(
@ -73,6 +73,6 @@ function track:build(
for i=0,3 do for i=0,3 do
poke(fmaddr+i,map_to_real_pattern(self.frames[frame][i+1])) poke(fmaddr+i,map_to_real_pattern(self.frames[frame][i+1]))
end end
fmaddr+=1 fmaddr+=4
end end
end end

View File

@ -18,20 +18,60 @@ end
function build_bgm() function build_bgm()
local bgm=track:new() local bgm=track:new()
bgm:add(32)
bgm:add(32) bgm:add(32)
local root=0 trumpet=instrument:new(play_trumpet)
for chan=0,7 do local perf=performer:new(bgm,0,trumpet,0,{30})
local p=root+chan*7 perf:play(3,0)
local start=0+chan*1 perf:play(3,7)
local v=5-chan/3 perf:play(3,5,"warb")
local c=chan%4 perf:play(1,3)
bgm:plot(c,start+0,{v=v,p=p}) perf:play(1,2)
bgm:plot(c,start+1,{v=v,p=p+12}) perf:play(1,0)
bgm:plot(c,start+2,{v=v,p=p+7,e=5}) perf:play(2,-2)
bgm:plot(c,start+3,{v=v-1,p=p+3,e=2}) perf:play(2,-4)
-- bgm:plot(c,start+4,{v=v-1,p=p}) perf:play(3,-5,"hold")
end perf:play(3,5,"hold")
perf:play(4,4,"warb")
perf:rest(1)
perf:play(1,-2)
perf:play(1,0)
perf:play(1,2)
perf:play(1,3)
perf:play(1,5)
perf:play(2,7)
perf:play(2,5)
perf:play(2,12)
perf:play(2,14)
perf:play(2,15)
perf:play(1,17)
perf:play(1,15)
perf:play(2,14)
perf:play(2,12)
perf:play(2,10)
perf:play(1,12)
perf:play(1,10)
perf:play(2,8)
perf:play(1,10)
perf:play(1,8)
perf:play(4,7)
perf:rest(4)
return bgm return bgm
end end
function play_trumpet(duration,pitch,verbs)
local e=0
if (verbs.slide) e=1
if (verbs.warb) e=2
local out={}
for i=1,duration do
out[i]=nflags:new{p=pitch,v=2,w=2,e=e}
end
if (not verbs.slide) out[1].e=4
if (not verbs.hold and #out>1) out[#out].e=5
return out
end