How does the built-in LoopSound() work flawlessly?

Blitz3D Forums/Blitz3D Beginners Area/How does the built-in LoopSound() work flawlessly?

Rob the Great(Posted 2013) [#1]
In a game that I'm designing, I made some custom music that features an introduction that only plays once but then leads into the actual part of the music that will loop in the game. The built-in sound functions don't naturally support a system like this, so I designed my own. Here's the general idea of what I ended up with:
Local intro = LoadSound("intro.wav")
Local loop = LoadSound("loop.wav")
;LoopSound loop ;I did use this in my game, but I removed it to demonstrate the problem
Local intro_playing = PlaySound(intro)
Local loop_playing = 0

While Not KeyDown(1)

      If Not ChannelPlaying(intro_playing)
            If Not ChannelPlaying(loop_playing)
                  loop_playing = PlaySound(loop)
                  ;Note that this cycle is repeated every time loop_playing ends.
            EndIf
      EndIf

Wend


Pretty basic, and it does what I need it to do.

I like to play the music while loading files so the user doesn't have to sit in silence looking at a loading screen. But as you may have already guessed, my system breaks down if the scope inside the main loop isn't called before the loading is finished.

I've found a workaround to the problem, but I got thinking about how the built-in LoopSound (or any of the sound commands) work in Blitz. It doesn't matter how long I take to complete one cycle in my game, the sound played with LoopSound always plays flawlessly. looping exactly when it should. My system could never work that well simply because if the game takes a hypothetical ten seconds to complete one cycle and the music quits in that time, there will be ten seconds of silence while the game makes its way back to loop checker. How does the built-in LoopSound avoid this issue?

The only thing that I can think of is that maybe the Blitz engine is somehow giving a unique thread to all of the top priority commands that are time sensitive, such as playing music and sounds. My knowledge of multi-threading is very limited, so I'm not even sure if that's a possibility. If anyone has an explanation about this question, please share. I'm not necessarily looking for a solution to the music looping problem, just hoping someone can shed some light on the situation.


Yasha(Posted 2013) [#2]
Blitz3D's sound support is provided by FMOD, so for the gritty details... well I don't know who you'd ask because FMOD isn't open source. At any rate this is getting into "not developed by Mark" territory.

A cursory search for 'fmod loop thread' turns up this post which offhandedly confirms that FMOD plays sounds in its own thread: http://katyscode.wordpress.com/2012/10/05/cutting-your-teeth-on-fmod-part-1-build-environment-initialization-and-playing-sounds/

All you really need to know though is that a thread can do exactly one thing at a time, which translates to sounds - and in fact anything that uses a "fire and forget" model - necessarily running in a different thread.

If a thread is running your Blitz3D code, that's the thing and the whole of the thing that it is doing. If it enters lower-level or system code, it must complete that task and return to your Blitz code for the program to continue. A single linear stream of instructions. That's why the 3D scene doesn't just get fired once and then run on its own: 3D renders in the main thread, as does your code, and that means your code has to have a niche where it allows 3D to happen and increments the state of the scene and so on. If sound didn't run in its own thread, you'd need to have a "ContinueChannel" function that "moved" each channel on by however many milliseconds, the same way UpdateWorld does for animations... which of course would be chaos as it wouldn't give any of your other code any time to run, because sound needs to be continuous. Somewhere that's actually happening, but it's been offloaded into a second thread so that its loop won't interfere or interact at all with your ongoing logic code.

I know little about sound (so I'm oversimplifying how it works), but the biggest problem with writing threaded code in general is sharing data and synchronising for returning values (to oversimplify threads as well). A sound thread never returns anything, and it only writes to its own completely separate output target - speakers instead of monitor - so it doesn't have very much it needs to synchronise or interact with the main thread for, and thus using a separate thread is a very clean and logical solution in this case.


Rob the Great(Posted 2013) [#3]
Very nice. I figured that threading was the only way that LoopSound could work so well.

Like I said, I'm not looking to mimic the LoopSound command using Blitz code (that would be a nightmare). Rather, I was just curious how the system worked.

Thanks Yasha!