Here's my code so far
This commit is contained in:
parent
3c33a8d08d
commit
7d14424033
191
engine.lua
Normal file
191
engine.lua
Normal file
@ -0,0 +1,191 @@
|
||||
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
|
20
pulsar.p8
Normal file
20
pulsar.p8
Normal file
@ -0,0 +1,20 @@
|
||||
pico-8 cartridge // http://www.pico-8.com
|
||||
version 42
|
||||
__lua__
|
||||
#include engine.lua
|
||||
#include song.lua
|
||||
__gfx__
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
__sfx__
|
||||
010f2000000500c05007055030421c03028030230351f022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
010f20000000007040130400e0450a032230302f0302a035260220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
010f200000000000000e0401a04015045110322a03036030310352d02200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
010f200000000000000000015040210401c04518032310203d0203802534012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
__music__
|
||||
00 00010203
|
||||
|
37
song.lua
Normal file
37
song.lua
Normal file
@ -0,0 +1,37 @@
|
||||
function _init()
|
||||
local bgm=build_bgm()
|
||||
local free_patterns={}
|
||||
for i=0,63 do add(free_patterns,i) end
|
||||
|
||||
bgm:build(free_patterns,0)
|
||||
|
||||
cstore(0x3100,0x3100,0x1200)
|
||||
music(0)
|
||||
end
|
||||
function _update()
|
||||
end
|
||||
function _draw()
|
||||
cls(0)
|
||||
print("enjoy the music!")
|
||||
end
|
||||
|
||||
function build_bgm()
|
||||
local bgm=song:new()
|
||||
|
||||
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
|
||||
|
||||
return bgm
|
||||
end
|
Loading…
Reference in New Issue
Block a user