Code quality fixes
This commit is contained in:
		
							
								
								
									
										191
									
								
								engine.lua
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								engine.lua
									
									
									
									
									
								
							| @@ -1,191 +0,0 @@ | |||||||
| function klass() |  | ||||||
|  local k={} |  | ||||||
|  k.__index=k |  | ||||||
|  function k:new(...) |  | ||||||
|   local n={} |  | ||||||
|   setmetatable(n,k) |  | ||||||
|   n:init(...) |  | ||||||
|   return n |  | ||||||
|  end |  | ||||||
|  return k |  | ||||||
| end |  | ||||||
|  |  | ||||||
| song=klass() |  | ||||||
| function song:init() |  | ||||||
|  self.frames={} |  | ||||||
|  self.ix_to_frame={} |  | ||||||
|  self.next_frame_start=0 |  | ||||||
| end |  | ||||||
| function song:add(len) |  | ||||||
|  for i=0,len-1 do |  | ||||||
|   self.ix_to_frame[self.next_frame_start+i]={#self.frames+1,i} |  | ||||||
|  end |  | ||||||
|  add(self.frames,{ |  | ||||||
|   pattern:new({len=len}), |  | ||||||
|   pattern:new({len=len}), |  | ||||||
|   pattern:new({len=len}), |  | ||||||
|   pattern:new({len=len}), |  | ||||||
|  }) |  | ||||||
|  self.next_frame_start+=len |  | ||||||
| end |  | ||||||
| function song:pattern(channel,offset) |  | ||||||
|  offset = offset or -1 |  | ||||||
|  channel &= 0xffff |  | ||||||
|  offset &= 0xffff |  | ||||||
|  assert(channel>=0 and channel<4, "channel must be [0,4)") |  | ||||||
|  local n_frames_long=#self.frames |  | ||||||
|  if offset<0 then |  | ||||||
|   assert(offset>=-n_frames_long, "offset must not exceed -"..n_frames_long) |  | ||||||
|   offset+=n_frames_long+1 |  | ||||||
|  else |  | ||||||
|   assert(offset>=0 and offset<n_frames_long) |  | ||||||
|   offset+=1 |  | ||||||
|  end |  | ||||||
|  return self.frames[offset][channel+1] |  | ||||||
| end |  | ||||||
| function song:plot(channel,offset,instant) |  | ||||||
|  assert(channel>=0 and channel<4, "channel must be [0,4)") |  | ||||||
|  local tup=self.ix_to_frame[offset] |  | ||||||
|  assert(tup, "invalid offset for current length: "..offset)  |  | ||||||
|  local f,offset=unpack(tup) |  | ||||||
|  self.frames[f][channel+1]:plot(offset, instant) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function song:build( |  | ||||||
|  free_patterns, |  | ||||||
|  frame_a, |  | ||||||
|  frame_z |  | ||||||
| ) |  | ||||||
|  local n_frames_long = #self.frames |  | ||||||
|  if (not frame_z) frame_z = frame_a + n_frames_long |  | ||||||
|  assert(frame_z-frame_a == n_frames_long, "wrong number of frames (must be "..frame_a.." to "..frame_a+n_frames_long..")") |  | ||||||
|  |  | ||||||
|  -- dump patterns and frames |  | ||||||
|  mapped_patterns={} |  | ||||||
|  function map_to_real_pattern(pat) |  | ||||||
|   if (pat:silent()) return 0 | (1<<6) |  | ||||||
|  |  | ||||||
|   local key = pat:key() |  | ||||||
|   mapped_patterns[key] = mapped_patterns[key] or {} |  | ||||||
|   for other in all(mapped_patterns[key]) do |  | ||||||
|    if (pat:eq(other)) return other.map_ix |  | ||||||
|   end |  | ||||||
|   assert(#free_patterns>0, "out of free patterns") |  | ||||||
|   pat:map_to(deli(free_patterns,1)) |  | ||||||
|   add(mapped_patterns[key],pat) |  | ||||||
|   return pat.map_ix  |  | ||||||
|  end |  | ||||||
|  |  | ||||||
|  local fmaddr=0x3100+(frame_a)*4 |  | ||||||
|  for frame=1,n_frames_long do |  | ||||||
|   for i=1,4 do |  | ||||||
|    poke(fmaddr+i-1,map_to_real_pattern(self.frames[frame][i])) |  | ||||||
|   end |  | ||||||
|   fmaddr+=1 |  | ||||||
|  end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| pattern=klass() |  | ||||||
| function pattern:init(o) |  | ||||||
|  speed = o.speed or 15 |  | ||||||
|  len = o.len or 32 |  | ||||||
|  noiz = o.noiz or 0 |  | ||||||
|  buzz = o.buzz or 0 |  | ||||||
|  detune = o.detune or 0 |  | ||||||
|  reverb = o.reverb or 0 |  | ||||||
|  dampen = o.dampen or 0 |  | ||||||
|  editormode = true |  | ||||||
|  |  | ||||||
|  assert(speed >= 1 and speed <255, "speed must be [1,255)") |  | ||||||
|  assert(len >= 1 and len < 33, "len must be [1,33)") |  | ||||||
|  assert(noiz >= 0 and noiz < 2, "noiz must be [0,2)") |  | ||||||
|  assert(buzz >= 0 and buzz < 2, "buzz must be [0,2)") |  | ||||||
|  assert(detune >= 0 and detune < 3, "detune must be [0,3)") |  | ||||||
|  assert(reverb >= 0 and reverb < 3, "reverb must be [0,3)") |  | ||||||
|  assert(dampen >= 0 and dampen < 3, "dampen must be [0,3)") |  | ||||||
|  |  | ||||||
|  self.instants={} |  | ||||||
|  self.len=len  |  | ||||||
|  -- https://pico-8.fandom.com/wiki/Memory#Music |  | ||||||
|  self.speed=speed |  | ||||||
|  self.pattern_flags=( |  | ||||||
|   ( |  | ||||||
|    tonum(editormode) | |  | ||||||
|    noiz<<1 | |  | ||||||
|    buzz<<2 |  | ||||||
|   ) +  |  | ||||||
|   detune*8 +  |  | ||||||
|   reverb*24 +  |  | ||||||
|   dampen*72 |  | ||||||
|  ) |  | ||||||
|  |  | ||||||
|  for i=0,self.len-1 do |  | ||||||
|   self.instants[i]=0 |  | ||||||
|  end |  | ||||||
| end |  | ||||||
| function pattern:plot(ix, iat) |  | ||||||
|  assert(ix>=0 and ix<self.len, "index invalid") |  | ||||||
|  self.instants[ix]=encode_instant(iat) |  | ||||||
| end |  | ||||||
| function pattern:silent() |  | ||||||
|  for i=0,self.len-1 do |  | ||||||
|   if (self.instants[i]&0x0e00!=0) return |  | ||||||
|  end |  | ||||||
|  return true |  | ||||||
| end |  | ||||||
| function pattern:key() |  | ||||||
|  local key=0 |  | ||||||
|  for i=0,self.len-1 do |  | ||||||
|   key ^= self.instants[i]<<(i%16) |  | ||||||
|  end |  | ||||||
|  return key |  | ||||||
| end |  | ||||||
| function pattern:eq(other) |  | ||||||
|  if (self.len!=other.len) return  |  | ||||||
|  for i=0,self.len-1 do |  | ||||||
|   if (self.instants[i]!=other.instants[i]) return  |  | ||||||
|  end |  | ||||||
|  return true |  | ||||||
| end |  | ||||||
| function pattern:map_to(ix) |  | ||||||
|  self.map_ix=ix |  | ||||||
|  local at=0x3200+ix*68 |  | ||||||
|  for i=0,31 do |  | ||||||
|   poke2(at+i*2,self.instants[i] or 0) |  | ||||||
|  end |  | ||||||
|  poke(at+64,self.pattern_flags) |  | ||||||
|  poke(at+65,self.speed) |  | ||||||
|  -- start, end |  | ||||||
|  poke(at+66,self.len) |  | ||||||
|  poke(at+67,0) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function encode_instant(o) |  | ||||||
|  custom = o.c or false |  | ||||||
|  effect = o.e or 0 |  | ||||||
|  volume = o.v or 0 |  | ||||||
|  waveform = o.w or 0 |  | ||||||
|  pitch = o.p or 0 |  | ||||||
|  |  | ||||||
|  assert(custom == false or custom == true, "custom must be true or false") |  | ||||||
|  assert(effect >= 0 and effect < 8, "effect must be [0,8)") |  | ||||||
|  assert(volume >= 0 and volume < 8, "volume must be [0,8)") |  | ||||||
|  assert(waveform >= 0 and waveform < 8, "waveform must be [0,8)") |  | ||||||
|  assert(pitch >= 0 and pitch < 64, "pitch must be [0,64)") |  | ||||||
|  |  | ||||||
|  custom = custom |  | ||||||
|  effect = effect & 0xffff |  | ||||||
|  volume = volume & 0xffff |  | ||||||
|  waveform = waveform & 0xffff |  | ||||||
|  pitch = pitch & 0xffff |  | ||||||
|  |  | ||||||
|  -- not a method: handle the nil instant |  | ||||||
|  -- https://pico-8.fandom.com/wiki/Memory#Music |  | ||||||
|  return ( |  | ||||||
|   (tonum(custom) << 15) | |  | ||||||
|   (effect << 12) | |  | ||||||
|   (volume << 9) | |  | ||||||
|   (waveform << 6) | |  | ||||||
|   (pitch) |  | ||||||
|  ) |  | ||||||
| end |  | ||||||
| @@ -1,8 +1,12 @@ | |||||||
| pico-8 cartridge // http://www.pico-8.com | pico-8 cartridge // http://www.pico-8.com | ||||||
| version 42 | version 42 | ||||||
| __lua__ | __lua__ | ||||||
| #include engine.lua | #include shared/_meta.lua | ||||||
| #include song.lua | #include shared/nflags.lua | ||||||
|  | #include shared/pattern.lua | ||||||
|  | #include shared/pflags.lua | ||||||
|  | #include shared/track.lua | ||||||
|  | #include unique.lua | ||||||
| __gfx__ | __gfx__ | ||||||
| 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | ||||||
| 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								shared/_meta.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								shared/_meta.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | function klass() | ||||||
|  |  local k={} | ||||||
|  |  k.__index=k | ||||||
|  |  function k:new(...) | ||||||
|  |   local n={} | ||||||
|  |   setmetatable(n,k) | ||||||
|  |   n:init(...) | ||||||
|  |   return n | ||||||
|  |  end | ||||||
|  |  return k | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function assert_range(i,mn,mx,name) | ||||||
|  |  assert(i >= mn and i < mx, name.." must be ["..mn..","..mx..")") | ||||||
|  | end | ||||||
							
								
								
									
										41
									
								
								shared/nflags.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								shared/nflags.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | nflags=klass() | ||||||
|  | function nflags:init(o) | ||||||
|  |  self.c = o.c or 0  -- custom | ||||||
|  |  self.e = o.e or 0 -- effect | ||||||
|  |  self.v = o.v or 0 -- volume | ||||||
|  |  self.w = o.w or 0 -- waveform | ||||||
|  |  self.p = o.p or 0 -- pitch | ||||||
|  |  | ||||||
|  |  self:validate() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function nflags:validate() | ||||||
|  |  local c,e,v,w,p | ||||||
|  |   =self.c,self.e,self.v,self.w,self.p | ||||||
|  |  | ||||||
|  |  assert_range(c,0,2,"custom") | ||||||
|  |  assert_range(e,0,8,"effect") | ||||||
|  |  assert_range(v,0,8,"volume") | ||||||
|  |  assert_range(w,0,8,"waveform") | ||||||
|  |  assert_range(p,0,64,"pitch") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function nflags:encode() | ||||||
|  |  self:validate() | ||||||
|  |  local c,e,v,w,p | ||||||
|  |   =self.c,self.e,self.v,self.w,self.p | ||||||
|  |  | ||||||
|  |  c &= 0xffff | ||||||
|  |  e &= 0xffff | ||||||
|  |  v &= 0xffff | ||||||
|  |  w &= 0xffff | ||||||
|  |  p &= 0xffff | ||||||
|  |  | ||||||
|  |  return ( | ||||||
|  |   (c << 15) | | ||||||
|  |   (e << 12) | | ||||||
|  |   (v << 9) | | ||||||
|  |   (w << 6) | | ||||||
|  |   (p) | ||||||
|  |  ) | ||||||
|  | end | ||||||
							
								
								
									
										45
									
								
								shared/pattern.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								shared/pattern.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  |  | ||||||
|  | pattern=klass() | ||||||
|  | function pattern:init(p) | ||||||
|  |  self.pflags=pflags:new(p) | ||||||
|  |  | ||||||
|  |  self.nflags={} | ||||||
|  |  for i=0,31 do  -- because the user could change the length | ||||||
|  |   self.nflags[i]=nflags:new{} | ||||||
|  |  end | ||||||
|  | end | ||||||
|  | function pattern:plot(ix, n) | ||||||
|  |  assert_range(ix,0,self.pflags.len,"ix") | ||||||
|  |  self.nflags[ix]=nflags:new(n) | ||||||
|  | end | ||||||
|  | function pattern:silent() | ||||||
|  |  for i=0,31 do | ||||||
|  |   if (self.nflags[i].v!=0) return | ||||||
|  |  end | ||||||
|  |  return true | ||||||
|  | end | ||||||
|  | function pattern:key() | ||||||
|  |  local key=0 | ||||||
|  |  for i=0,self.pflags.len-1 do | ||||||
|  |   key ^= self.nflags[i]:encode()>>(i%16) | ||||||
|  |  end | ||||||
|  |  return key | ||||||
|  | end | ||||||
|  | function pattern:eq(other) | ||||||
|  |  if (self.pflags:encode() != other.pflags:encode()) return | ||||||
|  |  | ||||||
|  |  for i=0,self.pflags.len-1 do | ||||||
|  |   if (self.nflags[i]:encode()!= other.nflags[i]:encode()) return | ||||||
|  |  end | ||||||
|  |  return true | ||||||
|  | end | ||||||
|  | function pattern:map_to(ix) | ||||||
|  |  self.map_ix=ix | ||||||
|  |  | ||||||
|  |  local at=0x3200+ix*68 | ||||||
|  |  poke4(at+64,self.pflags:encode()) | ||||||
|  |  | ||||||
|  |  for i=0,31 do | ||||||
|  |   poke2(at+i*2,self.nflags[i]:encode()) | ||||||
|  |  end | ||||||
|  | end | ||||||
							
								
								
									
										53
									
								
								shared/pflags.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								shared/pflags.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | pflags=klass() | ||||||
|  | function pflags:init(o) | ||||||
|  |  self.speed = o.speed or 15 | ||||||
|  |  self.len = o.len or 32 | ||||||
|  |  self.noiz = o.noiz or 0 | ||||||
|  |  self.buzz = o.buzz or 0 | ||||||
|  |  self.detune = o.detune or 0 | ||||||
|  |  self.reverb = o.reverb or 0 | ||||||
|  |  self.dampen = o.dampen or 0 | ||||||
|  |  self.editormode = o.editormode or 1 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function pflags:validate() | ||||||
|  |  local speed,len,noiz,buzz,detune,reverb,dampen,editormode | ||||||
|  |   =self.speed,self.len,self.noiz,self.buzz, | ||||||
|  |    self.detune,self.reverb,self.dampen,self.editormode | ||||||
|  |   | ||||||
|  |  assert_range(speed,1,255,"speed") | ||||||
|  |  assert_range(len,1,33,"len") | ||||||
|  |  assert_range(noiz,0,2,"noiz") | ||||||
|  |  assert_range(buzz,0,2,"buzz") | ||||||
|  |  assert_range(detune,0,3,"detune") | ||||||
|  |  assert_range(reverb,0,3,"reverb") | ||||||
|  |  assert_range(dampen,0,3,"dampen") | ||||||
|  |  assert_range(editormode,0,2,"editormode") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function pflags:encode() | ||||||
|  |  local speed,len,noiz,buzz,detune,reverb,dampen,editormode | ||||||
|  |   =self.speed,self.len,self.noiz,self.buzz, | ||||||
|  |    self.detune,self.reverb,self.dampen,self.editormode | ||||||
|  |  | ||||||
|  |  speed &= 0xffff | ||||||
|  |  len &= 0xffff | ||||||
|  |  noiz &= 0xffff | ||||||
|  |  buzz &= 0xffff | ||||||
|  |  detune &= 0xffff | ||||||
|  |  reverb &= 0xffff | ||||||
|  |  dampen &= 0xffff | ||||||
|  |  editormode &= 0xffff | ||||||
|  |  | ||||||
|  |  self:validate() | ||||||
|  |  local byte0 = ( | ||||||
|  |   dampen*72 + | ||||||
|  |   reverb*24 + | ||||||
|  |   detune*8 + | ||||||
|  |   buzz*4 + | ||||||
|  |   noiz*2 + | ||||||
|  |   editormode  -- "in editor mode" flag | ||||||
|  |  ) | ||||||
|  |  return len | speed>>8 | byte0 >>16 | ||||||
|  | end | ||||||
|  |  | ||||||
							
								
								
									
										78
									
								
								shared/track.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								shared/track.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | track=klass() | ||||||
|  | function track:init() | ||||||
|  |  self.frames={} | ||||||
|  |  self.ix_to_frame={} | ||||||
|  |  self.next_frame_start=0 | ||||||
|  | end | ||||||
|  | function track:add(len) | ||||||
|  |  for i=0,len-1 do | ||||||
|  |   self.ix_to_frame[self.next_frame_start+i]={#self.frames,i} | ||||||
|  |  end | ||||||
|  |  add(self.frames,{ | ||||||
|  |   pattern:new({len=len}), | ||||||
|  |   pattern:new({len=len}), | ||||||
|  |   pattern:new({len=len}), | ||||||
|  |   pattern:new({len=len}), | ||||||
|  |  }) | ||||||
|  |  self.next_frame_start+=len | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function track:pattern(channel,offset) | ||||||
|  |  offset = offset or -1 | ||||||
|  |  channel &= 0xffff | ||||||
|  |  offset &= 0xffff | ||||||
|  |  | ||||||
|  |  assert_range(channel,0,4,"channel") | ||||||
|  |  local n_frames_long=#self.frames | ||||||
|  |  assert_range(offset,-n_frames_long,n_frames_long,"offset") | ||||||
|  |  if offset<0 then | ||||||
|  |   offset+=n_frames_long | ||||||
|  |  end | ||||||
|  |  return self.frames[offset+1][channel+1] | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function track:plot(channel,offset,inst) | ||||||
|  |  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) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function track:build( | ||||||
|  |  free_patterns, | ||||||
|  |  frame_a, | ||||||
|  |  frame_z | ||||||
|  | ) | ||||||
|  |  local n_frames_long = #self.frames | ||||||
|  |  if (not frame_z) frame_z = frame_a + n_frames_long | ||||||
|  |  assert(frame_z-frame_a == n_frames_long,  | ||||||
|  |   "wrong number of frames (must be ".. | ||||||
|  |   frame_a.." to "..frame_a+n_frames_long..")") | ||||||
|  |  | ||||||
|  |  -- dump patterns and frames | ||||||
|  |  local mapped_patterns={} | ||||||
|  |  local function map_to_real_pattern(pat) | ||||||
|  |   if (pat:silent()) return 0 | (1<<6) | ||||||
|  |  | ||||||
|  |   local key = pat:key() | ||||||
|  |   mapped_patterns[key] = mapped_patterns[key] or {} | ||||||
|  |   local t = mapped_patterns[key] | ||||||
|  |   for other in all(t) do | ||||||
|  |    if (pat:eq(other)) return other.map_ix | ||||||
|  |   end | ||||||
|  |   assert(#free_patterns>0, "out of free patterns") | ||||||
|  |   pat:map_to(deli(free_patterns,1)) | ||||||
|  |   add(t,pat) | ||||||
|  |   return pat.map_ix  | ||||||
|  |  end | ||||||
|  |  | ||||||
|  |  local fmaddr=0x3100+(frame_a)*4 | ||||||
|  |  for frame=1,n_frames_long do | ||||||
|  |   for i=0,3 do | ||||||
|  |    poke(fmaddr+i,map_to_real_pattern(self.frames[frame][i+1])) | ||||||
|  |   end | ||||||
|  |   fmaddr+=1 | ||||||
|  |  end | ||||||
|  | end | ||||||
| @@ -16,7 +16,7 @@ function _draw() | |||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function build_bgm() | function build_bgm() | ||||||
|  local bgm=song:new() |  local bgm=track:new() | ||||||
| 
 | 
 | ||||||
|  bgm:add(32) |  bgm:add(32) | ||||||
| 
 | 
 | ||||||
		Reference in New Issue
	
	Block a user