Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Looping a music from a certain point  (Read 20699 times)

0 Members and 1 Guest are viewing this topic.

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #15 on: February 28, 2009, 05:10:47 pm »
I've been dealing with this issue as well, so I thought I'd share the info I've gathered so far.

I recently posted to this forum regarding seamless music looping in SFML (you can find the thread here). Laurent was nice enough to add support for seamless looping, and as far as I can tell this now works correctly in the current SVN version.

At this point though I'm still using SDL_mixer because (like the OP) I need support for looping from a specific loop point rather than from the beginning of the track.

Now, SDL_mixer doesn't offer this feature either, but it exposes a 'music hook' callback that allows you to do the music mixing yourself. Currently I'm doing the decoding myself using the Ogg Vorbis library, and feeding the data to SDL_mixer via the music mixing callback.

For looping, I'm using the function ov_pcm_seek(), which is documented here. As far as I can tell there's no mention of any seeking inaccuracy in the docs, and I haven't had any problems with it so far. Perhaps the Ogg Vorbis library is able to seek with no error?

If in fact the Ogg Vorbis library is able to do this while stb_vorbis cannot, then perhaps this is a feature that could be added to SFML (either by switching to Ogg Vorbis, or by finding a way to add support for seeking to stb_vorbis). From my point of view at least, seamless looping from arbitrary loop points would really make the 'music' part of the SFML audio API complete (if it would be of any help I'd be glad to share my decoding/looping code, although there's nothing really mysterious about it).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Looping a music from a certain point
« Reply #16 on: February 28, 2009, 07:34:51 pm »
Yeah, I know. This is very annoying because, as I already said, switching back to libvorbis will introduce many new external dependencies.

Quote
Now, SDL_mixer doesn't offer this feature either, but it exposes a 'music hook' callback that allows you to do the music mixing yourself

Can't you do the same thing by inheriting from sf::SoundStream?
Laurent Gomila - SFML developer

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #17 on: February 28, 2009, 07:45:17 pm »
Quote
Can't you do the same thing by inheriting from sf::SoundStream?

Quite possibly! I will look into it :)

Astrof

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Looping a music from a certain point
« Reply #18 on: March 01, 2009, 07:22:56 am »
Quote from: "Jesse"
Quote
Can't you do the same thing by inheriting from sf::SoundStream?

Quite possibly! I will look into it :)


If you could find a way to do this using SoundStream and the ogg libs, could you share your code, possible even uploading it onto the wiki?

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #19 on: March 01, 2009, 07:49:04 pm »
Quote
If you could find a way to do this using SoundStream and the ogg libs, could you share your code, possible even uploading it onto the wiki?

I don't know if I'll be able to work up a complete, working example (my current code uses SDL_mixer, and would require some revision to work with SFML), but I can at least offer some ideas as to how it might be done.

The first step would be to get the Ogg Vorbis library built and/or installed, and become familiar with the basics of its use. You can find the docs here.

I started by just loading the entire ogg file into memory and playing it back normally (i.e. not streamed). Obviously you won't want to do it this way in practice, but this way you can get familiar with the Vorbis library, and be sure that the basics are working.

Now, looking at the SoundStream docs, I see two functions of interest, OnStart() and OnGetData(). I'm going to venture a guess that OnStart() is called when streaming begins (e.g. in response to a play request), and OnGetData() is called whenever the buffer needs to be refilled.

The Chunk struct appears to contain a buffer of signed 16-bit samples, the size of which is determined by NbSamples. This will need to be filled (presumably) with raw audio extracted from the ogg stream.

You'll need to make sure that the format of the ogg data matches the current audio format. Technically, ogg files can have multiple bitstreams, each with its own sample rate, and even number of channels. I don't know how often this happens in practice though. I've made allowances for it in my code, but as far as I can tell, all the ogg files I'm using only have one bitstream. In short, if you can be sure that the format of the ogg file will match the current audio format, you won't need to perform any conversions and can just copy the ogg audio data directly to the buffer.

If it sounds a bit complicated, I suppose it is (it took me a couple of days to get it all working), but the payoff is seamlessly looped music tracks with the option of arbitrary loop points (which, IMO, is pretty much necessary for a polished, professional game, since looping back to the beginning of a music track can be fairly unnatural if the music is not completely dry).

Also, although I mentioned it earlier, I'll mention again that 'normal' looping works correctly and seamlessly in the current SVN version, so if you're still using the latest binary, you might try compiling from source and see if that fixes the lag issue.

Sorry I can't provide a complete code example right now, but feel free to ask if you have any questions about any of the above.

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #20 on: March 03, 2009, 03:39:37 pm »
Just posting a quick follow-up in case anyone finds this thread in the future. Although my 'looping music from an arbitrary point' code worked fine on my PC, I found that it didn't work so well in OS X. I'm not sure why (maybe because my Mac is underpowered relative to the PC, or just because I was doing something wrong), but it seemed that the culprit was ov_pcm_seek(), which was taking too long and hanging up the sound thread.

I think this could probably be addressed via multithreading, but that would have been a lot of work :) So instead I switched to a 'track queuing' system. In this system it's only ever necessary to rewind to the beginning of a track, but multiple tracks can be linked in sequence, with seamless transitions between them. This allows you to do the same thing (intro+loop with proper effects carryover), and also offers additional flexibility in that you can create arbitrarily complex arrangements without using unreasonable amounts of memory.

Since it doesn't involve seeking, 'track queuing' might be an easier feature to add to SFML, and wouldn't require switching to another ogg decoding library. (In fact, now that I'm not using the 'seek' feature, I might try switching to stb_vorbis, since it's more lightweight.)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Looping a music from a certain point
« Reply #21 on: March 03, 2009, 03:59:50 pm »
Well, I guess this kind of system could be implemented on top of what SFML provides. I'm not sure this is a core feature that needs to be included in it, it's rather a higher-level feature.
Laurent Gomila - SFML developer

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #22 on: March 03, 2009, 04:25:57 pm »
Quote
...it's rather a higher-level feature.

True. And as you pointed out earlier, this sort of feature could probably be implemented using sf::SoundStream if someone really needed it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Looping a music from a certain point
« Reply #23 on: March 03, 2009, 04:49:07 pm »
By the way, can you confirm that the last audio fix works for you?
http://www.sfml-dev.org/forum/viewtopic.php?p=6873#6873
Laurent Gomila - SFML developer

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #24 on: March 03, 2009, 04:54:49 pm »
Quote
By the way, can you confirm that the last audio fix works for you?

Absolutely, I'll try it in the next couple of days and post back.

Astrof

  • Full Member
  • ***
  • Posts: 135
    • View Profile
Looping a music from a certain point
« Reply #25 on: March 03, 2009, 07:08:48 pm »
Quote from: "Laurent"
Well, I guess this kind of system could be implemented on top of what SFML provides. I'm not sure this is a core feature that needs to be included in it, it's rather a higher-level feature.


I don't know about others, but I definately would find this feature useful (hence the topic).  Many professional level games have music pieces that start with an intro and go into a full loop (as stated above). Now, i'm sure a workaround would be to break the file into two pieces, but then there's the whole "did I cut the file at the right point" and timing issue (there could be a lag between stopping the first part and starting the next part).  Also, because of the lack of such a feature, many songs that have an intro are just looped multiple times, thus creating a bigger file size.  

Should I repost this in the feature request forum and maybe take a poll?  

Even if it can't be implemented officially, could maybe a wiki post be used with this and SoundStreams?

Jesse

  • Newbie
  • *
  • Posts: 16
    • View Profile
Looping a music from a certain point
« Reply #26 on: March 03, 2009, 07:11:35 pm »
Quote
By the way, can you confirm that the last audio fix works for you?

Seems to be fixed - I tried my example program from the other thread with the newest debug build, and received no errors :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Looping a music from a certain point
« Reply #27 on: March 03, 2009, 07:51:20 pm »
Quote
I don't know about others, but I definately would find this feature useful (hence the topic). Many professional level games have music pieces that start with an intro and go into a full loop (as stated above). Now, i'm sure a workaround would be to break the file into two pieces, but then there's the whole "did I cut the file at the right point" and timing issue (there could be a lag between stopping the first part and starting the next part). Also, because of the lack of such a feature, many songs that have an intro are just looped multiple times, thus creating a bigger file size.

Yes, I know it's a very important feature. But as I said, stb_vorbis is unable to perform random seeking. And according to Jesse, libvorbis has some seeking issues on OSX as well.

Quote
Should I repost this in the feature request forum and maybe take a poll?

If you want ;)
But I think I already know the results:
- many people will agree that it's very useful
- no one will provide an implementation, because it's complicated and there's no proper support on the low-level side.

Quote
Even if it can't be implemented officially, could maybe a wiki post be used with this and SoundStreams?

Of course, but how are you going to implement it if no library is able to perform seeking properly?
Laurent Gomila - SFML developer

nitram_cero

  • Full Member
  • ***
  • Posts: 166
    • View Profile
Looping a music from a certain point
« Reply #28 on: May 20, 2009, 11:48:47 pm »
This question has more to do with the first post than any of the following.
Instead of looping from a certain position, would it be much trouble to just queue the loop after an intro SoundStream/Sound?

I'm doing something like:

Sound intro;
Music loop;

//...after loading the stuff...
intro.Play();

//...in the game loop...
if(intro.GetStatus()==Sound::Stopped)
   loop.Play();

but because of frame limiting (or something else) I get silence for a little moment.
EDIT: Doing it in a thread doesn't help. So it's not the frame limit. I'll try with WAVs now.
EDIT2: no success with wavs. I'll try to time it with a Clock instead of testing the status.
EDIT3: No success neither. Playing the loop before the intro stops helps, but this is not an acceptable as it's not very predictable how much it will take in different computers.

Any ideas?
Thanks.
-Martín

OK, I've solved my problem
It's a hack to the Music class and I had to befriend SoundBuffer to this one.
It's actually quite easy:
In the SoundStream::FillQueue() that is executed by at the beginning only, I inject the introduction SoundBuffer before anything else.
Then in the SoundStream::Run() I check if I own the unqueued buffer that get's freed by OpenAL. If I not I skip everything, if I do: I reuse it.

And it works continuously and perfectly.

Maybe an improvement to the Music class would be to add an optional intro and ending SoundBuffer, as MOST songs have or should have an intro and ending.