SDL_mixer: automatic playlist advance

Hi,

has anybody a neat idea how to start another music track after the the
current track expired?
The simplest way would be a small callback which simply calls
Mix_PlayMusic() with the next Mix_Music pointer, but that’s not allowed.
Setting a boolean variable like trackfinished is easy too, but needs
constantly polling when to switch to the next song and may lead to
unnecessary delays. Creating a short lived thread each time isn’t too
complicate either, but probably very wasteful.

Any other ideas or comments?

Thanks in advance–
Christoph Nelles

E-Mail : @Christoph_Nelles
Jabber : eazrael at evilazrael.net ICQ : 78819723

PGP-Key : ID 0x424FB55B on subkeys.pgp.net
or http://evilazrael.net/pgp.txt

Hi,

has anybody a neat idea how to start another music track after the the
current track expired?
The simplest way would be a small callback which simply calls
Mix_PlayMusic() with the next Mix_Music pointer, but that’s not allowed.

I suppose this is because Mix_PlayMusic() needs to do some heavy
initialization, or at least some memory allocation and other "realtime unsafe"
stuff… Doing that in the contexts of the audio callback would obviously be a
bad idea.

Setting a boolean variable like trackfinished is easy too, but needs
constantly polling when to switch to the next song and may lead to
unnecessary delays.

I don’t know what you’re doing here, but games tend to have a main loop
spinning at some 30+ fps. Polling from there wouldn’t cause any significant in
this context.

If you need it tighter than that, I don’t think you can get away without
hacking SDL_mixer internals, or perhaps using SDL_sound or something instead.

SDL_sound + custom mixing code would do the trick, and you’d even be able to
cross-fade instead of just playing the songs back-to-back. Initialize songs
some time (seconds) before they’re supposed to start playing, and you’ll be
ready to start streaming exactly when you need to.

Creating a short lived thread each time isn’t too complicate either, but
probably very wasteful.

Creating and destroying threads should definitely be avoided in the audio
callback, especially if you’re targeting various general purpose operating
systems. It may not even be possible, if the audio callback is running in some
sort of interrupt context, though you probably won’t see that often these
days. (Win16 and Mac OS prior to X did that.)

If going for threads, I’d set up a permanent background thread for such
things, and have that block on a suitable locking mechanism, waiting for
commands from other contexts. To avoid timing issues on less realtime friendly
platforms, you may use lock-free mechanisms and have that thread poll at a
sensible rate.On Monday 30 November 2009, at 16.44.05, Christoph Nelles wrote:


//David Olofson - Developer, Artist, Open Source Advocate

.— Games, examples, libraries, scripting, sound, music, graphics —.
| http://olofson.net http://kobodeluxe.com http://audiality.org |
| http://eel.olofson.net http://zeespace.net http://reologica.se |
’---------------------------------------------------------------------’

Hi,
I suppose this is because Mix_PlayMusic() needs to do some heavy
initialization, or at least some memory allocation and other "realtime
unsafe"
stuff… Doing that in the contexts of the audio callback would
obviously
be a
bad idea.

I went through the code, it uses SDL_LockAudio which seems to be like a
non-recursive mutex.

I don’t know what you’re doing here, but games tend to have a main loop
spinning at some 30+ fps. Polling from there wouldn’t cause any
significant in
this context.

If you’re lucky enough to get 30+ fps. The timing is not the real problem,
but i am relunctant to resort to polling when there’s a callback.

Creating a short lived thread each time isn’t too complicate either,
but

probably very wasteful.

Creating and destroying threads should definitely be avoided in the
audio
callback, especially if you’re targeting various general purpose
operating
systems. It may not even be possible, if the audio callback is running
in
some
sort of interrupt context, though you probably won’t see that often
these
days. (Win16 and Mac OS prior to X did that.)

I think that’s not a problem anymore. There were threads in those good old
days?

If going for threads, I’d set up a permanent background thread for such
things, and have that block on a suitable locking mechanism, waiting for

commands from other contexts. To avoid timing issues on less realtime

So let a thread wait for a signal would be better?

friendly
platforms, you may use lock-free mechanisms and have that thread poll at
a
sensible rate.

Then i could poll again in the main thread. Which is really the simplest
way. But there must be some more fancy way.On Mon, 30 Nov 2009 17:10:19 +0100, David Olofson wrote:

On Monday 30 November 2009, at 16.44.05, Christoph Nelles <@Christoph_Nelles> wrote:


Christoph Nelles

E-Mail : @Christoph_Nelles
Jabber : eazrael at evilazrael.net ICQ : 78819723

PGP-Key : ID 0x424FB55B on subkeys.pgp.net
or http://evilazrael.net/pgp.txt

[…]

I suppose this is because Mix_PlayMusic() needs to do some heavy
initialization, or at least some memory allocation and other "realtime
unsafe"
stuff… Doing that in the contexts of the audio callback would obviously
be a bad idea.

I went through the code, it uses SDL_LockAudio which seems to be like a
non-recursive mutex.

That would probably generate a loooooong drop-out…! :smiley:

I don’t know what you’re doing here, but games tend to have a main loop
spinning at some 30+ fps. Polling from there wouldn’t cause any
significant in
this context.

If you’re lucky enough to get 30+ fps. The timing is not the real problem,
but i am relunctant to resort to polling when there’s a callback.

Of course, but then it’s either doing the job right then and there, or relying
on some proper blocking mechanism.

[…]

It may not even be possible, if the audio callback is running in some
sort of interrupt context, though you probably won’t see that often these
days. (Win16 and Mac OS prior to X did that.)

I think that’s not a problem anymore. There were threads in those good old
days?

Threads and various other strange contexts have coexisted on many Windows
versions at least, and I suppose they still do, although in an "emulated"
form, in the Win16 compatibility layer… And of course, there are Kernel
Streams in later NT based systems. (2000 and later, IIRC.)

If you want to include less common systems, there are various industrial
realtime platforms (Linux/RTAI, for example) that “piggy-back” on a general
purpose OS, where realtime threads and normal treads play by rather different
rules.

That said, I think the only time you’ll see any of this with SDL is if
you’re running on a pre-OSX Mac. Don’t know about handheld devices and game
consoles, though…

If going for threads, I’d set up a permanent background thread for such
things, and have that block on a suitable locking mechanism, waiting for
commands from other contexts. To avoid timing issues on less realtime

So let a thread wait for a signal would be better?

Yes. At least, that’s designed to be fast and low overhead, whereas creating
and destroying threads is not.

friendly
platforms, you may use lock-free mechanisms and have that thread poll at
a sensible rate.

Then i could poll again in the main thread. Which is really the simplest
way.

Yes, exactly.

Or, since you’re probably checking for SDL events somewhere anyway, possibly
even blocking on them, how about sending an SDL_USEREVENT to your mainloop?

That said, a worker thread is motivated in some situations, such as:
* You have a main loop that blocks, waiting for input events.
* You’re writing a library, and don’t want to force applications
to call some do_some_background_work() on a regular basis.
* You need to do some long term heavy work in the background,
while the game/UI loop keeps running.

I suppose none of those motivations really apply here, though.

But there must be some more fancy way.

Well, the cleanest, most accurate and most efficient way would probably be to
have playlist support in SDL_mixer, but I suspect that might be non-trivial to
implement. Initializing a new song probably isn’t a “realtime safe” operation
with some music formats (and this is assuming all data is already in RAM!), so
SDL_mixer would have to send that off to a background thread.

Basically, there’s no way you can avoid that issue without risking audio drop-
outs when switching songs. It’s just a matter of where and how it’s
implemented.On Monday 30 November 2009, at 17.35.43, Christoph Nelles wrote:


//David Olofson - Developer, Artist, Open Source Advocate

.— Games, examples, libraries, scripting, sound, music, graphics —.
| http://olofson.net http://kobodeluxe.com http://audiality.org |
| http://eel.olofson.net http://zeespace.net http://reologica.se |
’---------------------------------------------------------------------’

I’ve implemented seamless track queueing with SDL_mixer by doing my own streaming and mixing via the ‘music’ mixer hook. The downside is that you have to do your own streaming, but it does make for perfectly smooth transitions.

Whether this is worth the trouble or not probably depends on the situation. I’m using track queueing to assemble arrangements from multiple sections; the music is rhythmic in nature, so seamless transitions are required. If you’re just playing tracks in sequence though, and/or the music is not strongly rhythmic, you may be able to get away with polling or using the ‘music finished’ callback instead.

Sounds interesting :slight_smile:
Have you done any wrapping API to this, if we want to use it without
knowing much about streaming?

Jesse A. a ?crit :> I’ve implemented seamless track queueing with SDL_mixer by doing my

own streaming and mixing via the ‘music’ mixer hook. The downside is
that you have to do your own streaming, but it does make for perfectly
smooth transitions.

Whether this is worth the trouble or not probably depends on the
situation. I’m using track queueing to assemble arrangements from
multiple sections; the music is rhythmic in nature, so seamless
transitions are required. If you’re just playing tracks in sequence
though, and/or the music is not strongly rhythmic, you may be able to
get away with polling or using the ‘music finished’ callback instead.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

David Olofson schrieb:

Or, since you’re probably checking for SDL events somewhere anyway, possibly
even blocking on them, how about sending an SDL_USEREVENT to your mainloop?

Oh, i will do this nevertheless to give the user/programmer the
possibility to intervene.

That said, a worker thread is motivated in some situations, such as:

  • You have a main loop that blocks, waiting for input events.
  • You’re writing a library, and don’t want to force applications
    to call some do_some_background_work() on a regular basis.

That’s exactly my case g Perhaps this a good idea when there i am
implementing the other parts.

I suppose none of those motivations really apply here, though.

But there must be some more fancy way.

Well, the cleanest, most accurate and most efficient way would probably be to
have playlist support in SDL_mixer, but I suspect that might be non-trivial to
implement. Initializing a new song probably isn’t a “realtime safe” operation
with some music formats (and this is assuming all data is already in RAM!), so
SDL_mixer would have to send that off to a background thread.

I haven’t looked to close into the code, but i assume (unproofed) that
this could be an atomic operation if you provide another Mix_Music
yourself (i hope so)

Basically, there’s no way you can avoid that issue without risking audio drop-
outs when switching songs. It’s just a matter of where and how it’s
implemented.

Yes, probably an own mixer function like Jesse proposed is the best way,
but that’s too low level for me.

Thanks for the enlightenment in the thread stuff.


Christoph Nelles

E-Mail : @Christoph_Nelles
Jabber : eazrael at evilazrael.net ICQ : 78819723

PGP-Key : ID 0x424FB55B on subkeys.pgp.net
or http://evilazrael.net/pgp.txt

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAksW1fIACgkQBcR1PkJPtVuYMACeLrb/HkobnCAyyoLlxWaVbt7J
6MIAn0mNpMpBDxva1y0mTrB1Z8DHZy+G
=PDz+
-----END PGP SIGNATURE-----> On Monday 30 November 2009, at 17.35.43, Christoph Nelles <@Christoph_Nelles> wrote: