diff --git a/pulsar.p8 b/pulsar.p8 index b5a69fe..3be02fb 100644 --- a/pulsar.p8 +++ b/pulsar.p8 @@ -2,8 +2,10 @@ pico-8 cartridge // http://www.pico-8.com version 42 __lua__ #include shared/_meta.lua +#include shared/instrument.lua #include shared/nflags.lua #include shared/pattern.lua +#include shared/performer.lua #include shared/pflags.lua #include shared/track.lua #include unique.lua @@ -15,10 +17,11 @@ __gfx__ 00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __sfx__ -010f2000000500c05007055030421c03028030230351f022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -010f20000000007040130400e0450a032230302f0302a035260220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +010f20001e2241e2201e22525224252202522523224232222322521224202241e2241c2241c2251a2241a22519224192201922023224232202322022224222222222222225000001c2241e224202242122423224 +010f2000252242522523224232252a2242a2252c2242c2252d2242d2252f2242d2242c2242c2252a2242a22528224282252a22428224262242622528224262242522425220252202522500000000000000000000 010f200000000000000e0401a04015045110322a03036030310352d02200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010f200000000000000000015040210401c04518032310203d0203802534012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __music__ -00 00010203 +00 00404040 +00 01404040 diff --git a/shared/instrument.lua b/shared/instrument.lua new file mode 100644 index 0000000..11909c5 --- /dev/null +++ b/shared/instrument.lua @@ -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 \ No newline at end of file diff --git a/shared/nflags.lua b/shared/nflags.lua index 588cd7b..d4db462 100644 --- a/shared/nflags.lua +++ b/shared/nflags.lua @@ -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 diff --git a/shared/performer.lua b/shared/performer.lua new file mode 100644 index 0000000..060acb4 --- /dev/null +++ b/shared/performer.lua @@ -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 + diff --git a/shared/track.lua b/shared/track.lua index a7a0407..c754bb2 100644 --- a/shared/track.lua +++ b/shared/track.lua @@ -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 \ No newline at end of file diff --git a/unique.lua b/unique.lua index 34b55a7..ca20fb5 100644 --- a/unique.lua +++ b/unique.lua @@ -18,20 +18,60 @@ end function build_bgm() local bgm=track:new() + bgm:add(32) bgm:add(32) - local root=0 - for chan=0,7 do - local p=root+chan*7 - local start=0+chan*1 - local v=5-chan/3 - local c=chan%4 - bgm:plot(c,start+0,{v=v,p=p}) - bgm:plot(c,start+1,{v=v,p=p+12}) - bgm:plot(c,start+2,{v=v,p=p+7,e=5}) - bgm:plot(c,start+3,{v=v-1,p=p+3,e=2}) - -- bgm:plot(c,start+4,{v=v-1,p=p}) - end + trumpet=instrument:new(play_trumpet) + local perf=performer:new(bgm,0,trumpet,0,{30}) + perf:play(3,0) + perf:play(3,7) + perf:play(3,5,"warb") + perf:play(1,3) + perf:play(1,2) + perf:play(1,0) + perf:play(2,-2) + perf:play(2,-4) + perf:play(3,-5,"hold") + 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 -end \ No newline at end of file +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