Code quality fixes
This commit is contained in:
parent
7d14424033
commit
6bcbb0524c
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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user