From 3e53832512545ed92d41b5ac8f6ddf93e1a1ba22 Mon Sep 17 00:00:00 2001 From: Nyeogmi Date: Sat, 16 Mar 2024 21:09:11 -0700 Subject: [PATCH] Improve APIs further --- pulsar.p8 | 30 +++++----- shared/_meta.lua | 2 +- shared/conductor.lua | 77 ++++++++++++++++++++++++ shared/pitchblocks.lua | 14 +++++ unique.lua | 133 ++++++++++++++++------------------------- 5 files changed, 159 insertions(+), 97 deletions(-) create mode 100644 shared/conductor.lua create mode 100644 shared/pitchblocks.lua diff --git a/pulsar.p8 b/pulsar.p8 index 163883b..d193ce5 100644 --- a/pulsar.p8 +++ b/pulsar.p8 @@ -2,11 +2,13 @@ pico-8 cartridge // http://www.pico-8.com version 42 __lua__ #include shared/_meta.lua +#include shared/conductor.lua #include shared/instrument.lua #include shared/nflags.lua #include shared/pattern.lua #include shared/performer.lua #include shared/pflags.lua +#include shared/pitchblocks.lua #include shared/track.lua #include unique.lua __gfx__ @@ -20,18 +22,18 @@ __sfx__ 010fa0001ab741211512115101040e1740e1740e1740e174101050412404135161250806034a433cb5736b273eb5338a4338a3336a331ab7522b362ab7630b2736b473ab573ab1732b37069231c012280622e847 090a20001837018341183411834118341183411834118341183411834118341183411834118341183411834118341183411834118341183411834118341183411834118341183411834118341183411834118341 010120002667126361233610e3610e3610a3610636103361013600036301363013630135000350003500035002350023500235002550025400254001540004400000000000000000000000000000000000000000 -010f200000000000000000015040210401c04518032310203d0203802534012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -010f20000a8522285114852168520a8522285114852168520a8520a853148520a8520a85314852198521b852168522e8512085222852168522e85120852228521685216853208521685216853208522585227852 -010f200013a700a95314952169521e6730a953149521695213a700a953149520a9531e67314952199531b95213a701d95327952299521e6731d953279522995213a701d953279521d9531e673279522c9532e952 -010f2000293252932529345293652932529325293452936529325293252934529365293252932533345333653132531345313653136531345313453136531365303453034530365303652c3652c365303652c365 -010f2000228523a8512c8522e852228523a8512c8522e85222852228532c85222852228532c852318523385227852278532085227852278532085227852278532085227852278532085219852188521985218852 -010f200013a702995333952359521e67329953339523595213a702995333952299531e67333952389533a95213a703795313a70379531e6733095213a703795313a70379531e6733095213a702b95213a701f952 -010f20002932529325293452936529325293252934529365293252932529345293652932529325333453336500000000000000000000000000000000000000000000000000000000000000000000000000000000 -001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +090120003f6503f6413f6413363133635000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +010f20000a8720a842000000a8720a8420a8420a8720a8420a8420a8720a8420a84200000000000f8720f8420d8720d842000000d8720d8420d8420d872000000f8720f84200000000000f8720f8420f8420f842 +010f20001197211942000001197211942119421197200000129721294200000129721397213942139720000014972149420000014972149421494214972000001397213942000001397212972129421297200000 +010f200013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673252351eb230000013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673252351eb2300000 +010f20000a8720a842000000a8720a8420a8420a872000000f8720f84200000000000f8720f8420f8420f8420d8720d842000000d8720d8420d8420d8720d8420f8720f8720f8420f84200000000000f8720f842 +010f20001197211942119721194214972149421497214942169721694216972169421897218942189721894216972169421697216942149721494214972149421397213942139721394212972129421297212942 +010f200013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673272351eb230000013a70292351eb23192351e673000001eb232923513a70192351eb2300000192352a2351eb2300000 +010f200013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673252351eb230000013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673252351eb2300000 +010f20000a8720a842000000a8720a8420a8420a872000000f8720f84200000000000f8720f8420f8420f8420d8720d842000000d8720d8420d8420d8720d8420f8720f8720f8420f84200000000000f8720f842 +010f20001197211942119721194214972149421497214942169721694216972169421897218942189721894216972169421697216942149721494214972149421397213942139721394212972129421297212942 +010f200013a70252351eb23192351e673000001eb232523513a70192351eb23000001e673272351eb230000013a70292351eb23192351e673000001eb232923513a70192351eb2300000192352a2351eb2300000 +010f200013a702533513a70193351e6730000013a702533513a701933513a70000001e6732733513a700000013a702933500000193351e67300000193352933513a701933513a7000000193352a33513a7000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -82,8 +84,8 @@ __sfx__ 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 002000001885000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __music__ -00 08090a40 -00 0b0c0d40 +00 04050640 +00 07080940 00 40404040 00 40404040 diff --git a/shared/_meta.lua b/shared/_meta.lua index f8e3881..891ef0e 100644 --- a/shared/_meta.lua +++ b/shared/_meta.lua @@ -11,5 +11,5 @@ function klass() end function assert_range(i,mn,mx,name) - assert(i >= mn and i < mx, name.." must be ["..mn..","..mx..")") + assert(i >= mn and i < mx, name.." must be ["..mn..","..mx..") and not "..i) end \ No newline at end of file diff --git a/shared/conductor.lua b/shared/conductor.lua new file mode 100644 index 0000000..c000982 --- /dev/null +++ b/shared/conductor.lua @@ -0,0 +1,77 @@ +conductor=klass() +function conductor:init(track,time) + self.track=track + self.time=time +end + +function conductor:perform( + performers, + pitchblocks, + notation +) + local n_performers=#performers + local n_pitchblocks=#pitchblocks.chunks + + assert(#notation==n_performers,"need "..n_performers.." parts for "..n_performers.." performers") + + for i=1,n_performers do + assert(#notation[i]==n_pitchblocks,"performers should have "..n_pitchblocks.." for "..n_pitchblocks.." pitchblocks") + + local function resolve_pitch(t,ix) + local block = pitchblocks.chunks[t+1] + assert_range(ix,0,#block,"pitch ix") + return block[ix+1] + end + + local running_note=nil + + local function touch_running_note( + t,pitch,force_new,verbs + ) + if force_new or (running_note and running_note.pitch != pitch) or (not running_note and pitch!=nil) then + if running_note then + performers[i].time=self.time+running_note.t + performers[i]:play(t-running_note.t,running_note.pitch,running_note.verbs) + running_note=nil + end + if pitch then + running_note={ + t=t, + pitch=pitch, + verbs=verbs + } + end + end + end + + for t=0,n_pitchblocks-1 do + local note_char=notation[i][t+1] + local pitch + local force_start_new + local verbs="" + + if note_char >= "a" and note_char <= "z" then + ix = ord(note_char) - ord("a") + pitch=resolve_pitch(t,ix) + elseif note_char >= "A" and note_char <= "Z" then + ix = ord(note_char) - ord("A") + pitch=resolve_pitch(t,ix) + force_start_new = true + elseif note_char == "." then + pitch=nil + elseif note_char == "@" then + pitch,verbs=0,"kick" + elseif note_char == "!" then + pitch,verbs=0,"snare" + elseif note_char == "'" then + pitch,verbs=0,"hihat" + else + assert(false,"wtf? "..note_char) + end + + touch_running_note(t,pitch,force_start_new,verbs) + end + touch_running_note(n_pitchblocks,nil) + performers[i].time=self.time + end +end \ No newline at end of file diff --git a/shared/pitchblocks.lua b/shared/pitchblocks.lua new file mode 100644 index 0000000..6d79b6c --- /dev/null +++ b/shared/pitchblocks.lua @@ -0,0 +1,14 @@ +pitchblocks=klass() +function pitchblocks:init(width) + assert_range(width,0,8,"width") + self.width=width + self.chunks={} +end + +function pitchblocks:add(n,notes) + assert(#notes==self.width) + for i=1,n do + add(self.chunks,notes) + end + return self +end \ No newline at end of file diff --git a/unique.lua b/unique.lua index 94130d9..566f3bc 100644 --- a/unique.lua +++ b/unique.lua @@ -1,7 +1,7 @@ function _init() local bgm=build_bgm() local free_patterns={} - for i=8,63 do add(free_patterns,i) end + for i=4,63 do add(free_patterns,i) end bgm:build(free_patterns,0) @@ -23,86 +23,56 @@ function build_bgm() bgm:add(32) bgm:add(32) - local bassline=instrument:new(devil(8,2,5,5)) - local yowler=instrument:new(devil(9,2,5,3)) - local p0=performer:new(bgm,0,bassline,0,{12-2}) - local p1=performer:new(bgm,1,yowler,0,{24-2}) - - function generators(r,a,b,c,d) - a+=r b+=r c+=r d+=r - local oct=12 - if (b < a) oct=-12 - local e=a+oct - local f=b+oct - local g=c+oct - local t={ - gen4=function() - p0:play(1,a) p0:play(1,a+24,"slide") p0:play(1,d) p0:play(1,e) - p1:play(1,a,"chop") p1:play(1,a,"chop") p1:play(1,d) p1:play(1,e) - end, - - gen3=function() - p0:play(1,a) p0:play(1,a,"chop") p0:play(1,d) - p1:play(1,a,"chop") p1:play(1,a,"chop") p1:play(1,d) - end, - - gen2=function(off) - off = off or 0 - p0:play(1,f+off) p0:play(1,g+off) - p1:play(1,f+off,"chop") p1:play(1,g+off) - end - } - t.gen16=function() - t.gen4() t.gen4() t.gen3() t.gen3() t.gen2() - end - t.gen12=function() - t.gen3() t.gen3() t.gen3() t.gen3() - end - return t - end - p1.offset=-12 - generators(0,0,3,5,10).gen16() - p1.offset=-5 - generators(12,0,3,5,10).gen16() - generators(24,0,3,5,10).gen16() - p1.offset=4 - generators(29,0,-2,-3,-7).gen12() - p1.offset=7 - generators(29,0,-2,-3,-7).gen2() - p1.offset=-5 - generators(29,0,-2,-3,-7).gen2() - - local drums=instrument:new(drums) - local pd=performer:new(bgm,1,drums,0,{0}) - - for i=0,5 do - pd:play(1,0,"kick") - pd:rest(3) - pd:play(1,0,"snare") - pd:rest(3) - end - pd:play(1,0,"kick") pd:rest(1) pd:play(1,0,"kick") pd:rest(1) pd:play(1,0,"snare") pd:rest(1) - pd:play(1,0,"kick") pd:rest(1) pd:play(1,0,"kick") pd:rest(1) pd:play(1,0,"snare") pd:rest(1) - pd:play(1,0,"kick") pd:rest(1) pd:play(1,0,"kick") pd:rest(1) - + local bassline=instrument:new(devil(8,2,7,4)) + local yowler=instrument:new(devil(9,2,7,4)) local melo1=instrument:new(melo1) - local pm=performer:new(bgm,2,melo1,0,{48-2}) + local drums=instrument:new(drums) + local p0=performer:new(bgm,0,bassline,0,{12-2}) + local p1=performer:new(bgm,1,yowler,0,{12-2}) + local p2=performer:new(bgm,2,melo1,0,{12-2}) + local pd=performer:new(bgm,2,drums,0,{0}) + local ph=performer:new(bgm,2,drums,0,{0}) + --local pm=performer:new(bgm,2,melo1,0,{48-2}) - local function generate_ostinato(a,b,c,d,e,stophalf) - pm:play(1,a,"qq") pm:play(1,a,"qq") pm:play(1,a,"q") pm:play(1,a) - pm:play(1,a,"qq") pm:play(1,a,"qq") pm:play(1,a,"q") pm:play(1,a) - pm:play(1,a,"qq") pm:play(1,a,"qq") pm:play(1,a,"q") pm:play(1,a) - pm:play(1,a,"qq") pm:play(1,a,"qq") pm:play(1,e,"q") pm:play(1,e) - if (stophalf) return - pm:play(1,d,"qq") pm:play(1,d,"q") pm:play(1,d) pm:play(1,d) - pm:play(1,d,"q") pm:play(1,d,"q") pm:play(1,d) pm:play(1,d) - pm:play(1,c,"q") pm:play(1,c,"q") pm:play(1,c) pm:play(1,c) - pm:play(1,b) pm:play(1,b) pm:play(1,c) pm:play(1,b) - end + conductor:new(bgm,0):perform( + {p0,p1,p2,pd,ph}, + pitchblocks:new(4) + :add(8,{0,7,15,27}) + :add(4,{0,8,15,27}) + :add(4,{5,9,15,27}) + :add(8,{3,10,15,27}) + :add(4,{5,9,15,27}) + :add(4,{5,8,15,27}) + , + { + "Aa.AaaAaaAaa..Aa" .. "Aa.AaaA.Aa..Aaaa", + "Bb.BbbB.Bb.BbbB." .. "Bb.BbbB.Bb.BbbB.", + "Cd.Cd.Cd.Cd.Cdd." .. "Cd.Cd.Cd.Cd.Cdd.", + "@...!...@...!..." .. "@...!...@.@.!.@.", + "..'...'...'...'." .. "..'...'...'...'." + } + ) - generate_ostinato(-5,-2,2,3,5) - generate_ostinato(-5,-2,2,3,5,true) - pm:rest(16) + conductor:new(bgm,32):perform( + {p0,p1,p2,pd,ph}, + pitchblocks:new(4) + :add(4,{0,7,15,27}) + :add(4,{0,10,15,27}) + :add(4,{5,12,15,29}) + :add(4,{5,14,15,29}) + :add(4,{3,12,15,31}) + :add(4,{3,10,15,31}) + :add(4,{5,9,15,33}) + :add(4,{5,8,15,32}) + , + { + "Aa.AaaA.Aa..Aaaa" .. "Aa.AaaAaaAaa..Aa", + "BbBbBbBbBbBbBbBb" .. "BbBbBbBbBbBbBbBb", + "Cd.Cd.Cd.Cd.Cdd." .. "Cd.Cd.Cd.Cd.Cdd.", + "@.@.!.@.@.@.!.@." .. "@...!...@.@...@.", + "..''..'...''..'." .. "..'...'...'...'." + } + ) return bgm end @@ -133,17 +103,16 @@ function drums(duration,pitch,verbs) } end if (verbs.snare) return {nflags:new{p=30,v=7,w=6,e=3}} + if (verbs.hihat) return {nflags:new{p=30,v=2,w=11,e=3}} return {} end function melo1(duration,pitch,verbs) - local v=6 - if (verbs.q) v=4 - if (verbs.qq) v=2 + local v=3 local out={} for i=1,duration do - out[i]=nflags:new{p=pitch,w=3,v=v,e=5} + out[i]=nflags:new{p=pitch,w=2,v=v,e=5} end return out end \ No newline at end of file