[Solved]Looping song from end to middle?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
FroggestSpirit
Prole
Posts: 11
Joined: Tue Jan 26, 2016 7:13 pm

[Solved]Looping song from end to middle?

Post by FroggestSpirit »

I'm new here, but going over some of the documentation, it seems that there are some functions to set the current sample of the audio playing. I'm hoping there is an easy way to have audio when it reaches the end of a file, to loop back to a specific sample (so it plays the intro of a song once, and loops the rest of it). Also, I love sequenced music, and I was wondering what kind of looping options are available for the supported sequenced formats.

Edit: As a side question, can one make an audio player for android that can loop music like this while the screen is off?
Last edited by FroggestSpirit on Wed Jan 27, 2016 5:09 pm, edited 1 time in total.
This isn't easy to say, but…
User avatar
zorg
Party member
Posts: 3468
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Looping song from end to middle?

Post by zorg »

Don't know about your android question, but for the other, here's some code as an example:

Code: Select all

local song
local loopStart, loopEnd
function love.load()
  -- mp3 files can't "wrap" precisely, due to how they work, so don't use them.
  song = love.audio.newSource("song.ogg")
  -- good for this kind of custom loop points
  song:setLooping(true)
  -- only doing this for show really, setting the loop points this way makes it always work :3
  local duration = song:getDuration('samples')
  -- you can support both types of loops, whether they go around the file's end or not
  loopStart = math.floor(3 * (duration / 4))
  loopEnd = math.floor(duration / 4) 
  -- the above makes it loop from the 3rd quarter to the first, skipping anything between those.
  song:play()
end

function love.update(dt)
  -- note that with vsync on, this might not be fast enough for the code to be precise enough.
  local now = song:tell("samples")
  -- the now < loopStart part kinda forces the music to not start at the beginning, if that's set somewhere else;
  -- this can be solved in more than one way, depending on what you want to accomplish
  if loopStart < loopEnd and (now < loopStart or now > loopEnd) then
    -- probably could use a better point to seek to, calculated by now - loopEnd or something,
    -- but that may have issues if one were to use it simply like that
    song:seek(loopStart ,"samples")
  elseif loopEnd < loopStart and (now < loopEnd or now > loopStart) then
    -- same here
    song:seek(loopStart, "samples")
  end
end
Also, sadly, since the module formats (and the other sequenced ones) are decoded into audio streams, you can't really control their playback any differently from what you can do with mp3-s and oggs and the like. You'd need to load in an external library to handle that how you'd want to, though this will most likely mean using the FFI. (Like libopenmpt or some midi library, depending on what you want to use)
Me and my stuff :3True 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.
User avatar
FroggestSpirit
Prole
Posts: 11
Joined: Tue Jan 26, 2016 7:13 pm

Re: Looping song from end to middle?

Post by FroggestSpirit »

Thank you a ton! I modified the code a little, and it seems to work pretty good.

Code: Select all

local song
local loopStart, loopEnd, loopLength
function love.load()
  -- mp3 files can't "wrap" precisely, due to how they work, so don't use them.
  song = love.audio.newSource("song.ogg")
  -- good for this kind of custom loop points
  song:setLooping(true)
  -- only doing this for show really, setting the loop points this way makes it always work :3
  local duration = song:getDuration('samples')
  -- you can support both types of loops, whether they go around the file's end or not
  loopStart = 515161 --my loop points in samples
  loopEnd = 4131460 --make sure to leave a few seconds at the end for more precise looping
  loopLength = loopEnd-loopStart
  --The song will now play from the beginning, and jump to loopStart when it reaches loopEnd
  song:play()
end

function love.update(dt)
  -- note that with vsync on, this might not be fast enough for the code to be precise enough.
  local now = song:tell("samples")
  if(now >= loopEnd) then
    song:seek(song:tell("samples")-loopLength ,"samples")
	--have it recalculate the current position, and jump backwards relatively. this helps make the loop more seamless
  end
end
With it looping from the current spot, relative to the starting spot, it makes the loop pretty seamless (I didn't notice any skipping in the music when it looped).
This isn't easy to say, but…
User avatar
pgimeno
Party member
Posts: 3674
Joined: Sun Oct 18, 2015 2:58 pm

Re: [Solved]Looping song from end to middle?

Post by pgimeno »

Nice job, it should be less vulnerable to frame rate drops that way, and theoretically perfect if your song has at least a fragment of the start of the loop right after the end of the loop (the fragment should be at least long enough to cover the frame time during a frame rate drop).

Just a suggestion, you can use 'now' instead of calling 'song:tell("samples")' a second time
User avatar
FroggestSpirit
Prole
Posts: 11
Joined: Tue Jan 26, 2016 7:13 pm

Re: [Solved]Looping song from end to middle?

Post by FroggestSpirit »

I believe that using 'now' again would return the value of when it was first called, the second time would probably be just slightly later, though I haven't tested that. Not sure if the 'if' check would cause a noticeable delay. As a suggestion though, it'd be cool if setLooping() had an optional 2nd or 3rd argument that could be passed to achieve this.
This isn't easy to say, but…
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 4 guests