Hello everyone,
I've been doing some research about rhythm games for my next project.
Unfortunately, I can't seem to understand how one would implement rhythm-based games with LÖVE, only with the Sound and Audio APIs.
Currently I'm hardcoding the length of each beat and it kind of seems to work; but what if I wanted to game to adapt to different tracks (given the BPM is pre-defined, no need to detect it)?
Ideally I would love to play the audio, then make a function call that would return the current position of the listener relative to the bpm of the song (e.g. "3.1" would mean it's slightly after the third beat).
Could someone please clear this up?
Thanks!
Implementing rhythm-based mechanics
Implementing rhythm-based mechanics
Last edited by Ulydev on Mon May 02, 2016 9:20 pm, edited 1 time in total.
Re: Implementing rhythm-based mechanics
To get the data with LÖVE, use [wiki]love.sound.newSoundData[/wiki] to load the sound, instead of [wiki]love.audio.newSource[/wiki]. You can then apply love.audio.newSource to the SoundData object you obtain, and also [wiki]Data:getString[/wiki] (or [wiki]Data:getPointer[/wiki] if you're willing to use FFI).
As for what to do with the data for the purpose of determining the tempo (BPM) of a song, a quick overview is here:
http://sound.stackexchange.com/question ... ually-work
The complete thing is in the GameDev article linked from there:
http://archive.gamedev.net/archive/refe ... index.html
Sounds complicated? That's because it is! There's even a contest on beat detection algorithms:
http://nema.lis.illinois.edu/nema_out/m ... s/abt/mck/
(Irrelevant after seeing your edit)
Last edited by pgimeno on Tue May 03, 2016 12:04 am, edited 1 time in total.
- zorg
- Party member
- Posts: 3470
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Implementing rhythm-based mechanics
Also, just to be pedantic a bit, since löve uses openAL's positional audio stuff, saying that you want "a function call that would return the current position of the listener relative to the bpm of the song" is wrong, since you want the position of the playback cursor, or in other words, the temporal / time position of the song itself, not the (spatial) position of any listener.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: Implementing rhythm-based mechanics
The formula for the current beat of a song given a song's playing position (in seconds) and a BPM: bpm / 60 * songTime
So if your BPM was 120 and the song is at 1 second, then the current beat is 2. This gets a lot more complicated with BPM changes, but if you're not dealing with that, then this should be good enough.
EDIT: For future reference, most of what you'd need to do involving song beats can be derived from two formulas:
Get the number of seconds in a beat: 60 / bpm
Get the number of beats in a second: bpm / 60
This makes up a good chunk of the math you're probably going to need.
So if your BPM was 120 and the song is at 1 second, then the current beat is 2. This gets a lot more complicated with BPM changes, but if you're not dealing with that, then this should be good enough.
EDIT: For future reference, most of what you'd need to do involving song beats can be derived from two formulas:
Get the number of seconds in a beat: 60 / bpm
Get the number of beats in a second: bpm / 60
This makes up a good chunk of the math you're probably going to need.
Re: Implementing rhythm-based mechanics
You're probably looking for [url=Source:tell]https://love2d.org/wiki/Source:tell[/url].
Divide this by your beat length in seconds (which is your bpm/60).
Don't forget that there might be an offset at the beginning of the audio file, because of silence etc.
So make sure to take that into account so your function is beat aligned.
Divide this by your beat length in seconds (which is your bpm/60).
Don't forget that there might be an offset at the beginning of the audio file, because of silence etc.
So make sure to take that into account so your function is beat aligned.
Re: Implementing rhythm-based mechanics
Also make sure you're interpolating the audio time value. (interpolating values you get from the Source:tell function).
These two functions may prove useful:
Now you said you need to work with the beat to beat calculation.. hmm
First, i'd get the current milliseconds between every beat of the song (you can calculate this based on the BPM).
Then, starting from 0 i'd generate a list with every beat time in milliseconds..
Finally, to figure out how far are we from the next beat, we just get the ((time from the next beat)-(time from last beat))/(milliseconds per beat). And concatenate this with the current index of the beat on the table, hence, resulting in something like 3.4 or something of the sort.
@edit
I'm stupid, so the function was very very wrong. But it's fixed now!
These two functions may prove useful:
Code: Select all
--Taken from beatfever source code
function playInterpolated() --Runs the music, but enables interpolated timer reporting. Used ingame as an interpolated timer.
previousFrameTime = love.timer.getTime()*1000
lastReportedPlaytime = 0
songTime = 0
songPlay:play()
end
function getInterpolatedTimer()
songTime = songTime + (love.timer.getTime()*1000) - previousFrameTime
previousFrameTime = love.timer.getTime()*1000
if songPlay:tell("seconds")*1000 ~= lastReportedPlaytime then --Updates music time, but with easing
songTime = (songTime + (songPlay:tell("seconds")*1000))/2
lastReportedPlaytime = songPlay:tell("seconds")*1000
eased = true
end
return songTime
--for more info about this, take a look
--https://www.reddit.com/r/gamedev/comments/13y26t/how_do_rhythm_games_stay_in_sync_with_the_music/
end
First, i'd get the current milliseconds between every beat of the song (you can calculate this based on the BPM).
Then, starting from 0 i'd generate a list with every beat time in milliseconds..
Code: Select all
Say we have 300 milliseconds per beat for a given song. The list on it's first position would be 300, on the second position 600, on the third position 900... and so on until the BPM changes or the music reaches it's end.
@edit
I'm stupid, so the function was very very wrong. But it's fixed now!
Last edited by Sulunia on Wed Jun 08, 2016 1:11 pm, edited 4 times in total.
https://github.com/Sulunia
Re: Implementing rhythm-based mechanics
Looks like I'm going to end up using Source:tell() a lot.
But at least, I know where I'm going now: thanks a lot for your help, everyone!
But at least, I know where I'm going now: thanks a lot for your help, everyone!
Re: Implementing rhythm-based mechanics
I don't get it.
But why are you doing this?
The way I see it your song time approaches the actual song time asymptotically.Sulunia wrote:Code: Select all
function getInterpolatedTimer(dt) songTime = songTime + dt - previousFrameTime -- this should be ~0 for the first frame songTime = (songTime + (songPlay:tell("seconds")*1000))/2 -- which means this should be half of the song time after the first frame? end
But why are you doing this?
Re: Implementing rhythm-based mechanics
It makes sure that whilst no new Source:tell() value is reported, we ease the last value forward a bit using the DT as a base value for such easing.undef wrote: The way I see it your song time approaches the actual song time asymptotically.
But why are you doing this?
This is useful pretty much if you're using the song time to calculate any note or game element position, since it'll make it "slide" more smoothly, as the value is always coming in a steady stream.
Backstory: on the earlier implementation of my rhythm game on python in the raspberry pi, if we didn't ease the value this way the notes would jitter quite a bit since the songTimer didn't really refresh that often. In love2d the difference is actually quite small, but it's there.
There is a link on the source code that explains this a bit better.
https://github.com/Sulunia
Re: Implementing rhythm-based mechanics
Ah, I shouldn't have looked at that reddit post earlier.
Great resource! Thanks for pointing it out!
Great resource! Thanks for pointing it out!
Who is online
Users browsing this forum: No registered users and 4 guests