I've just finished a simple system to listen to a few tracks in sequence, looping them for different times and with pauses between. And I wanted to share my approach with you.
Let's start with the basics. I have 4 songs I wanted to play in sequence, at first each for the same amount of time - 72 seconds in this example, with a 15 seconds pause between them. Simple stuff handled in an event, which starts the next song in the list every time it's called. This means that when entering a room, restarting it or going to the main menu, the next song starts.
on playSong do
if musicOn==1 then
currentSong++
if currentSong>4 then
currentSong = 1
end
store "currentSong"
loop "song{currentSong}"
wait 72 then
stop
wait 15 then
call "playSong"
end
end
end
end
But what happens if I turn the music on and off? When turning it off, it stops the current song and when turning it on it calls this event, starting the next one. But! There is that nasty wait there that doesn't go away when stopping the previous song. Meaning that now there will be two wait calls. And if I keep toggling the music I will have even more wait calls. Not good.
To solve this, we use a lock. This makes sure that only the last wait call executes the code, stopping the current song and starting a new one, while the other waits do nothing. Here is the code:
songWaitLock++
wait 72 then
songWaitLock--
if songWaitLock==0 then
stop
wait 15 then
if songWaitLock==0 then // checks a wait hasn't been called in the meantime
call "playSong"
end
end
end
end
Works beautifully! But at this point I decided I wanted different play times for each song. Which I set up like this:
if currentSong==1 then
waitSong = 96
elseif currentSong==3 then
waitSong = 72
else
waitSong = 40
end
songWaitLock++
wait 72 then
// same code as before inside the wait
end
This code works fine if I don't toggle the music on/off. But what happens if I toggle it after the first song starts, with a waitTime of 96? It starts the second song, with a waitTime of 40. But remember, the previous wait, which lasts for much longer hasn't yet stopped. When the second wait (the one for 40) ends, the songWaitLock will go from 2 to 1, meaning nothing happens. Only after the first wait (the one for 96) ends too, will the song be stopped. Meaning that instead of stopping the second song after the intended 40 seconds, it stops after much longer. Not our intended behavior.
This is where the wait limitation kicks in. I had to avoid calling wait altogether and track the time myself, to avoid stacked up wait calls. We know that Pulp calls the game loop event 20 times per second. So we multiply our waitSong with 20 to get the number of frames we need to wait.
In the game loop event, we call a new event handleWaitSong. In that event, which remember, is called every frame, we tick down the waitSong. When it reaches zero, we stop the current song. If by any chance a new song was started in the meantime, it means waitSong was reset to the value for that song, which is what we want. We handle pausing between songs similarly, with waitSongPause which is ticked down only if waitSong is zero - otherwise we're waiting to first stop the song. Here is the final code:
on playSong do
if musicOn==1 then
currentSong++
if currentSong>4 then
currentSong = 1
end
store "currentSong"
loop "song{currentSong}"
if currentSong==1 then
waitSong = 96
elseif currentSong==3 then
waitSong = 72
else
waitSong = 40
end
waitSong *= 20
end
end
on loop do
call "handleWaitSong"
end
on handleWaitSong do
if waitSong>0 then
waitSong--
if waitSong==0 then
stop
waitSongPause = 300
end
elseif waitSongPause>0 then
waitSongPause--
if waitSongPause==0 then
call "playSong"
end
end
end