Synced lyrics
Last time I had written out the lyrics for Forest Spirit Sound, this time I've synced it up with a little demo.
I put the lyrics in a json object with timestamps down to the milisecond and loaded that in three.js. Using performance.now() I started a timer to keep track of time regardless of performance. You could get 4 frames per second or 2000 and the lyrics would still be synced to the music. The lyrics json looks something like this:
{
"lines": [
{
"startTimeMs": "26000",
"words": "Why can't I talk about it?"
},
{
"startTimeMs": "29000",
"words": "I don't even know what to say to you."
},
{
"startTimeMs": "34000",
"words": "(you)"
},
[...]
]
}
I started out with some super overclomplicated code to load the lyrics on each frame but rewrote that to become this:
if (
lyrics.timeDelta + lyrics.timeOffset >=
lyrics.lines[lyrics.lineIndex]?.startTimeMs &&
!lyrics.ended
) {
console.log(lyrics.lines[lyrics.lineIndex].words);
lyrics.lineIndex++;
}
if (typeof lyrics.lines[lyrics.lineIndex] == "undefined") {
lyrics.ended = true;
}
This might look a little crazy but it's quite straightforward and efficient. Basically what happens is the timeDelta (calculated on each frame outside this function) is the time since the music started playing and this frame. We add or subtract an offset if needed (as to not have to rewrite the whole lyrics json) and then check if the startTimeMs of the current line has passed. If it has, we log the line and increment the lineIndex.
For this demo I log the lyrics, but I can do anything here super easily. Next, we check if the next lyrics line exists or not. If it doesn't, we've ran out of lines and thus reached the end of the lyrics. If this is the case we set the lyrics.ended variable to true to prevent this from being checked on each frame.
This gives back some performance for other 3D tasks. This might seems useless, especially on desktop environments, but this is important on mobile because of the limited processing power. Each frame you can squeeze out of it is good, and for that to happen every milisecond counts.