SSound - take the trouble out of dealing with several needs in sound playback

Previous topic - Next topic

Wampus

The attached proggy is an alternative way of handling sound in GLBasic. It should be simple to use and especially helpful for platforms that may only play a small number of sounds concurrently. At its base the code uses standard GLBasic commands. Because of this it should compile fine on all platforms. You can also use it in addition to other sound code without having to replace what you've done already, unless you want to.

Why do this at all? Because I wanted 1) a suitable and simple approach to the issue described in this thread, 2) an easy way to deal with needing multiple instances of the same sound playing at once, 3) universal volume control and 4) looping sounds.

The attached proggy uses only 4 channels. I did this deliberately for demonstration purposes. Of course, you'll probably want more than that with your apps. :)

Clicking the left mouse buttons plays a shooting sound. Pressing space starts or stops a looped sound. Clicking the right mouse button plays a wibbly sound that can't be interrupted until its finished. If what you see on screen seems confusing, sorry. There is a bunch of internal information you don't need to know being displayed for test purposes. I don't have the time to write a more suitable demonstration right now.

It should be fairly easy to use. For instance, this is a comparison of loading, playing and stopping a sound in GLBasic and how you would do it with SSound (keeping in mind SSound does more than what is shown here):-








GLBasic    ---    SSound
GLOBAL mysound%, channel%    ---    GLOBAL mysound%, channel%
mysound% = GENSOUND()
LOADSOUND "explosion.wav", mysound%, 1
    ---    mysound% =  SSLoad("explosion.wav")
channel% = PLAYSOUND(mysound%, 0.0, 1.0)    ---    channel% = SSPlay(mysound%)
STOPSOUND channel%    ---    SSKillSound(mysound%) or SSKillChan(channel%)
HUSH    ---    SSKillAllSounds()

However, if you want understand better how it works and what its doing you need to grasp these components:-

A sound is any standard .wav file you've loaded.

A buffer is the number of times a sound has been stored in memory. The more of these you assign for any sound, the more instances of that sound you can overlap at the same time without any cutting out or failing to play (depending on the mode - see below)

A channel is one of a limited set of available tracks that a sound can be played on. For example, on my Nexus 7 the number of sounds that can be played at the same time is set to 8 in GLBasic. Therefore the maximum number of channels should be set / would be set to 8.

The mode the sound is played with determines how it is treated by the routine. 0 is standard - the sound will be played on the next available channel. If no channel is available then it will be played on the channel that is the oldest, i.e. the sound that has been playing the longest is cut off to make way for the new sound. Also, if there aren't enough buffers for a new channel then an already used channel playing the sound is used. This works out fine on the ear in most cases. 1 is looped - the sound will continue to loop unless you tell it to stop and cannot be interrupted like a standard sound. 2 is not a looped sound but can't be interrupted, so will continue to play until it is finished unless you kill it. If no channels are available because all are taken up with uninterruptable sounds then a call to play a new sound will do nothing <- this should be rare because SSound was created to help prevent this in all but the worst cases.

OK, here are the commands:-

soundenum% = SSLoad ( filename$, buffers% )
Loads a sound from the current set directory with the name filename$. If your require it to be possible for more than one instance of the sound to be played at once, e.g. more than one overlapping sounds of bullets or explosions, then set the optional value buffers% to how many you anticipate. The value soundenum% is the index of the sound returned by SSLoad.

channel% = SSplay ( soundenum%, volume#, mode%, pan# )
Plays a sound loaded into the index soundenum%. The channel used is returned to channel% but you probably don't need to know this for most purposes so can leave it out. Values for volume#, mode% and pan# are also optional. Volume# and pan# work the same as GLBasic PLAYSOUND(). For mode% these are possible values:-
0 - Standard. Use this unless you need a looped sound or sound that must not be interrupted (e.g. a voice over).
1 - Looped sound. Sound will loop indefinitely unless stopped with SSKillSound, SSKillChan or SSKillAllSounds.
2 - Uninterruptable sound. Similar to GLBasic default behaviour, the sound will continue to play until it is completely finished and can't be interrupted.


SSInitialise ( numofchannels% )
If you want to use more or less channels than the default 8 then you need to call this function before you start loading sounds. numofchannels% is the required number of channels you want to use.

num% = SSTestNumSoundChannels% ( filename$, chanmax%)
Uses the .wave file in filename$ to test how many sound channels are available for use. I don't advise using this every time an app starts up. Just execute it on first boot and store the value for later reference. Use 1/4 second of total silence for the .wav file or the test may destroy the ears and/or speakers of the person using your app! The value chanmax% is the maximum number of channels to test for. By default its set to 64 but can be much larger. My main PC returns positive for > 2048 channels. Note: This function has not been tested on more than one PC and a good, recent android device. Not sure how reliable it will be unless tested.

SSUpdate ()
If you want to use sound looping then this must be present in your main loop. If you aren't going to use looping sounds then you don't need to use this function.

SSVolume ( vol# )
Sets the universal volume to vol#. All sounds played are proportional to the universal volume. For example, if you played a collision sound at full volume using SSPlay(collisionsound%, 1.0) and the universal volume was set to half at 0.5 then the resulting sound would be half the full volume.

SSKillSound ( soundenum% )
Stops playing the sound with index soundenum%. All channels playing the sound will be halted and all buffers for the sound are released.

SSKillChan ( channel% )
Alternative to SSKillSound. Stops playing the sound playing on channel channel%. Only the channel specified and consequent buffer will be clear. All other sounds are left alone.

SSKillAllSounds ()
Stops all sounds, freeing all buffers and channels.

---------

There are other functions but almost all of them are internal to the commands above so you don't need to know anything about them.

erico

The so called super sound library!

Thanks Wampus, I will take a look as soon as I get this java/android/apk (argh! :rant:) going on here.
Super thanks for the effort! :good:

Wampus

Well, I don't know about super sound. With any luck it should be simple sound though.  :-[

It might be a bit difficult to learn to use it at first. In theory it could speed up development time. Sound always seems to be time consuming, confusing to me or throws up unexpected problems during rapid development for 1GAM, Ludum Dare, etc. This routine was meant to help me with that. I hope its useful to someone else too.

kanonet

Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

erico


mentalthink

Thanks Wampus I think it's very nice and profitable lib... only a question I only touch for a  few seconds, but I try to find somthing for get in my hands  :x , it's possible pause in example the music and restart the music from the last point I stopped...

I like a lot the part on explains the chuncks and this things... I like make somthing whit waws... but really this it's a very kaos format files...  :rant:

Thanks a lot for sharing your work  :good:

Super Simple Sound System (SSSS) I meant ;) this it's more than SubsurfaceScatering  :D :D :D

spicypixel

http://www.spicypixel.net | http://www.facebook.com/SpicyPixel.NET

Comps Owned - ZX.81, ZX.48K, ZX.128K+2, Vic20, C64, Atari-ST, A500.600.1200, PC, Apple Mini-Mac.

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

kanonet

Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

erico