"Performers" can handle melodies
This commit is contained in:
		| @@ -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
									
								
							
							
						
						
									
										31
									
								
								shared/instrument.lua
									
									
									
									
									
										Normal 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 | ||||||
| @@ -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
									
								
							
							
						
						
									
										28
									
								
								shared/performer.lua
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
| @@ -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 | ||||||
							
								
								
									
										64
									
								
								unique.lua
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								unique.lua
									
									
									
									
									
								
							| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user