Created
June 20, 2024 09:18
-
-
Save thykka/a3cd52b9e559001270d1dd89c977ef84 to your computer and use it in GitHub Desktop.
PICO-8 Timeline module with Beat sync & drift correction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function init_timeline(state) | |
tl_scenes={} | |
tl_state={ | |
time=0,duration=0, | |
seek_time=0,frame=0, | |
loop=true, | |
music_bpm=120.5, | |
music_sig=4, | |
music_idx=nil, | |
fixsync=true, | |
sync_time=0 | |
} | |
for k,v in pairs(state) do | |
tl_state[k]=v | |
end | |
return tl_state | |
end | |
function set_music(idx,spd) | |
tl_state.music_idx=idx | |
music_spd(spd) | |
end | |
function music_spd(spd,bars) | |
tl_state.music_bpm=(7229.50819/(bars or 4))/(spd or 15) | |
end | |
function music_beat(time) | |
return (tl_state.music_bpm/60)*time | |
end | |
function music_bar(time) | |
return (tl_state.music_bpm/60)*time/tl_state.music_sig | |
end | |
function bars_to_seconds(bars) | |
return (bars * tl_state.music_sig * 60) / tl_state.music_bpm | |
end | |
function add_scene(sstart,sstop,init,update,draw,unload,start,stop) | |
add(tl_scenes,{ | |
start=start or sstart and bars_to_seconds(sstart) or 0, | |
stop=stop or sstop and bars_to_seconds(sstop) or 0, | |
show=false,time=-1, | |
init=init,update=update,draw=draw,unload=unload | |
}) | |
for scn in all(tl_scenes) do | |
tl_state.duration=max(tl_state.duration,scn.stop) | |
end | |
end | |
function get_time() | |
return tl_state.seek_time+tl_state.sync_time+t() | |
end | |
function local_time(scn) | |
return (tl_state.time-scn.start)/(scn.stop-scn.start) | |
end | |
function seek_time(bars) | |
local seek_seconds=bars_to_seconds(bars) | |
tl_state.seek_time+=seek_seconds | |
local music_pos=music_bar(get_time())%music_bar(tl_state.duration) | |
if music_pos>63 then | |
music_pos=63 | |
end | |
music(music_pos) | |
end | |
function update_timeline() | |
local s=tl_state | |
s.time=get_time() | |
s.frame+=1 | |
-- bpm detection | |
s.music_bar_last=s.music_bar or 0 | |
-- sync correction | |
s.music_bar=music_bar(s.time) | |
if s.fixsync then | |
s.music_bar=stat(54)+stat(56)/256 | |
s.sync_time+=bars_to_seconds( | |
s.music_bar-music_bar(s.time) | |
) | |
s.time=get_time() | |
end | |
s.music_bar_active=flr(s.music_bar)!=flr(s.music_bar_last) | |
s.music_beat_last=s.music_beat or 0 | |
s.music_beat=music_beat(s.time) | |
s.music_beat_active=flr(s.music_beat)!=flr(s.music_beat_last) | |
for scn in all(tl_scenes) do | |
if not scn.show and (s.time>=scn.start) | |
and s.time<scn.stop then | |
scn.show=true | |
if scn.init then scn.init(s) end | |
elseif scn.show and (s.time>=scn.stop or s.time<scn.start) then | |
scn.show=false | |
if scn.unload then scn.unload(s) end | |
end | |
if scn.show and scn.update then | |
s.local_time=local_time(scn) | |
scn.update(s) | |
end | |
end | |
if s.time>s.duration then | |
if s.loop then | |
extcmd('reset') | |
else | |
extcmd('shutdown') | |
end | |
end | |
if s.debug then | |
if(btnp(⬅️)) seek_time(-1) | |
if(btnp(➡️)) seek_time(1) | |
end | |
end | |
function draw_timeline(s) | |
local s=tl_state | |
for scn in all(tl_scenes) do | |
if scn.show and scn.draw then | |
scn.draw(local_time(scn),s) | |
end | |
end | |
if (btnp(❎) and btnp(🅾️)) then | |
s.debug=not s.debug | |
end | |
if s.debug then | |
line(0,127,127,127,1) | |
line(0,127,flr(s.time/s.duration*127),127,5) | |
for si,scn in ipairs(tl_scenes) do | |
line( | |
flr(scn.start/s.duration*127),126-si, | |
flr(scn.stop/s.duration*127),126-si,si) | |
end | |
print('bar '..flr(s.music_bar)..':'..( | |
{'-','\\','|','/'})[flr(s.music_beat%4)+1]..'='..s.music_beat, | |
0,0,2) | |
print('trk '..(s.seek_time),0,6) | |
print('snc '..(s.sync_time),0,12) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment