Looping sounds with fixed start/end positions?

BlitzMax Forums/BlitzMax Programming/Looping sounds with fixed start/end positions?

Johnsprogram(Posted 2011) [#1]
I know there are programmatic ways to play a song with one part played once and the other part loop forever; I've made one myself as two sound files. But the problem with my solution is that it's prone for so-called "silent gaps" to happen during the switch from one-played song to looping-song. Therefore, adjusting the framerate maximum to lower than 60 fps would make the gaps more noticeable; especially for slower computers.

I take it that any audio playing in the blitz app will be running asynchronously with the actual blitz program, correct? (Which includes both the app and the modules.) Therefore, I wonder if the DirectSound, OpenAL, or FreeSound drivers could be able to play a sound and loop at different points?

Why do I want to loop at different points the hard way than the easy programmatic way? It's because of the following reasons...
1) Depending how slow the blitz app is, you'll notice the silent gaps more easily.
2) The audio would play upon end while the app is too busy to respond in time to loop the audio; especially if you drag the blitz app window cross.
3) I thought it would sound more professional to have the audio to loop (from one point to another) smoothly.


Kryzon(Posted 2011) [#2]
Just high-level information. You'll have to research further.

When working with OpenAL, you could create 2 buffers: one that contains the beginning of the sound, and the second containing the rest of the sound that's supposed to loop.

Then queue both buffers into the same Source with alSourceQueueBuffers(), and play it.
In your game loop or on a separate thread, keep polling the source to see how many buffers were processed (using alGetSourcei() with the AL_BUFFERS_PROCESSED constant). If it has processed 1, we know it's currently playing the second buffer. Therefore, at that moment we can take action and set the source's playing mode (alSourcei() and AL_LOOP constant) to AL_TRUE.

With this I think the source will lock at looping the second buffer, which is the section of the sound you want to play like that.
I'm sure DirectSound has similar functionality, but you need to research. The BlitzMax audio modules source code can be of help here.

Last edited 2011


Midimaster(Posted 2011) [#3]
perhaps it will help you:

sound used:
http://www.blitzforum.de/upload/file.php?id=11057
Graphics 800,600
Global Channel:TChannel, Zeit%
Global Klang:TSound=LoadSound("rock.ogg")
Repeat
	PlayAgain
Until KeyHit(1)

Function PlayAgain()
	If Zeit<MilliSecs()
	Print "play"
		oldChannel=Channel
		Channel=PlaySound(Klang)
		Delay 200
		If oldchannel<>Null
			StopChannel oldchannel
		EndIf
		Zeit=MilliSecs()+5620
	EndIf
End Function


it demonstrates how to punch out of a sound (before finished) and start the next one without gaps

have a look on the sound with audacity. it fades in and out


Johnsprogram(Posted 2011) [#4]
Midimaster: I'm planning on a new game, so I cannot use this because the code just focuses on the audio only.

Kryzon: I wonder if there's a way to set OpenAi only once to play two song (with the 2nd one looping) and not periodically check the driver to tell it to switch songs?

I've tried switching sounds by threading before, but the application ends up being too slow. I might try that approach again, but I wanted to find out if I could just send instructions to the sound drivers themselves.


Midimaster(Posted 2011) [#5]
the sample code focuses on the audio, but of course it also works in a game where you use a 60Hz timer. Also the DELAY only should demonstrate you to stop the first sound 200msec after starting the same in a second channel.

Of course it also works in a event driven GUI.

Where do you see problems using my solution?

We never had problems with gaps! And we are doing a lot of music stuff with BMax! Do you know you have to find the right point to punch out? Perhaps your gaps are a result of not searching for a zero-crossing?

Last edited 2011


Kryzon(Posted 2011) [#6]
You can't do automation with OpenAL or DirectSound. The only thing close is queueing buffers, and you can't loop them with an offset (i.e: play something all the way to the end then loopback to some specific point in the buffer, like a specific section of the buffer).

There is a feasible way though: with both songs loaded into one buffer each, queue the first song to some Source, then the second song to this same Source. Play the Source.
Game loop: Keep polling the Source's number of buffers processed. As soon as the Source is done processing at least one buffer, queue the second song again.

In the end, you are controlling the loop yourself. You will never hear a pop - the buffers are queued by the driver itself, and you never have to wait until everything stops playing to recycle data (you're doing it while it's playing).

This is all explained in detail in this real-time streaming article: http://www.devmaster.net/articles/openal-tutorials/lesson8.php