SFML community forums

Help => Audio => Topic started by: Astrof on February 11, 2009, 01:15:15 am

Title: Looping a music from a certain point
Post by: Astrof on February 11, 2009, 01:15:15 am
A lot of songs have some kind of intro sequence in the beginning but then start to loop from another point of the song.  Is there a way to do this in SFML? If not, would the best alternative way be to just manually split the song, play the intro piece, then time it, play the other part then loop?  The only problem with the latter is I seem to have some kind of lag when I play musics, (it's not a loading issue, I load at a different part of the program much before execution begins.
Title: Looping a music from a certain point
Post by: Core Xii on February 11, 2009, 04:21:30 am
One thing that might interfere with your attempts is the MP3 format, which cannot be looped seamlessly. MP3s work with some kind of block structure or whatnot, and can't loop perfectly.
Title: Looping a music from a certain point
Post by: Astrof on February 11, 2009, 05:15:02 am
i thought that SFML can't support mp3?
Title: Looping a music from a certain point
Post by: Core Xii on February 11, 2009, 06:30:06 am
Well in fact, I don't know. I just wanted to point that out, in case you ever have problems :P
Title: Looping a music from a certain point
Post by: Laurent on February 11, 2009, 07:57:34 am
Quote
would the best alternative way be to just manually split the song

Probably. Or using another audio library which allows more advanced control (FMod, Bass, Audiere, ...).

Quote
The only problem with the latter is I seem to have some kind of lag when I play musics

Could you show a minimal and complete piece of code which reproduces this problem (with the audio file you're using), so that I can test it?

Quote
i thought that SFML can't support mp3?

Correct. But Ogg files, which are supported by SFML, use a block structure too.
Title: Looping a music from a certain point
Post by: Core Xii on February 11, 2009, 10:32:26 am
Quote from: "Laurent"

Correct. But Ogg files, which are supported by SFML, use a block structure too.


Really? They loop perfectly though.
Title: Looping a music from a certain point
Post by: Laurent on February 11, 2009, 10:45:44 am
Yeah, the seeking function of stb_vorbis (the library I use for loading ogg) is pretty good ;)

But it still might be a little bit unaccurate sometimes, this is explained in the documentation of stb_vorbis.
Title: Looping a music from a certain point
Post by: Astrof on February 14, 2009, 11:01:11 pm
i just do a simple:
Code: [Select]

sf::Music music;
music.OpenFromFile("SolarisPhase2Theme.aif");
music.SetLoop(true);
music.Play();

there seems to be like a half a second lag.
Title: Looping a music from a certain point
Post by: Astrof on February 15, 2009, 07:01:46 am
I think the problem might just be with the Music files themselves.  (two files seemed to lag though one started right away).  I guess I'll just have to look into that some more.
Title: Looping a music from a certain point
Post by: Astrof on February 25, 2009, 08:53:23 pm
Would a way to loop the music from a certain point work by waiting until the song finishes (or gets to a certain point) then restarting from the desired part? (seeking with the GetPlayingOffset )?
This would use threads a lot woudn't it; could the sleep function be used to sleep until the music is over (time it) and then restart from a point? how much of a lag would there be?
Title: Looping a music from a certain point
Post by: Laurent on February 25, 2009, 08:54:59 pm
SetPlayingPosition is not implemented for sound streams, it works only for sounds.
Title: Looping a music from a certain point
Post by: Astrof on February 25, 2009, 10:54:59 pm
hmm, can this be implemented for sound streams later? (like in sfml 2)? I don't know about other people, but I find this feature useful.
Title: Looping a music from a certain point
Post by: Laurent on February 25, 2009, 11:04:12 pm
I really wish I could do that ;)

But this would require seeking into audio files (as they're not decoded in memory), which is very hard to do for ogg-vorbis files. In particular, the library I'm using to decode ogg-vorbis files (stb_vorbis) is currently not able to do it.
Title: Looping a music from a certain point
Post by: Astrof on February 25, 2009, 11:13:11 pm
darn...so i'm back to my either split files or use a different library approach.  I really do not want to use a different library (one reason why I chose SFML was because it did the graphics, audio, (joystick if I wanted to do that) and networking all together.  

If possible it would be really cool if this feature could be added to SFML in the future, though I do realize your limitations on this issue with stb_vorbis.  Are ogg files the only problem? Could a different ogg library be used? I do not know what is required of a library to be added to the framework; I realize you chose sdb_vorbis over other libs.  

On another note, this issue isn't too big of a deal, as I'm more worried about getting gameplay working first.  But I'll definitely have to come back to this later.
Title: Looping a music from a certain point
Post by: Laurent on February 25, 2009, 11:29:57 pm
There is the official libvorbis library, which is open source and has a nice license, but it requires 4 external dependencies. stb_vorbis is only one file and can be embedded directly into SFML. Moreover, I can rely on the author to fix any bug I find :)
Title: Looping a music from a certain point
Post by: Jesse 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 (http://www.sfml-dev.org/forum/viewtopic.php?t=1051)). 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 (http://xiph.org/vorbis/doc/vorbisfile/ov_pcm_seek.html). 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).
Title: Looping a music from a certain point
Post by: Laurent 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?
Title: Looping a music from a certain point
Post by: Jesse 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 :)
Title: Looping a music from a certain point
Post by: Astrof 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?
Title: Looping a music from a certain point
Post by: Jesse 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 (http://xiph.org/vorbis/doc/vorbisfile/reference.html).

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.
Title: Looping a music from a certain point
Post by: Jesse 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.)
Title: Looping a music from a certain point
Post by: Laurent 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.
Title: Looping a music from a certain point
Post by: Jesse 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.
Title: Looping a music from a certain point
Post by: Laurent 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
Title: Looping a music from a certain point
Post by: Jesse 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.
Title: Looping a music from a certain point
Post by: Astrof 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?
Title: Looping a music from a certain point
Post by: Jesse 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 :)
Title: Looping a music from a certain point
Post by: Laurent 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?
Title: Looping a music from a certain point
Post by: nitram_cero 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.