Multiple sound channels
BlitzMax Forums/BlitzMax Programming/Multiple sound channels
| ||
Hi. On BlitzPlus if I played several of the same sound at once on different channels, it sounded really noisy, almost distorted. Of course this is due to the combined output peaking and overloading of course. However, I've noticed that this doesn't seem to be as big an issue in Max, it doesn't sound as bad. Anyone else found this? In BPlus I made an array of sound channels to limit the amount that could be played at once, and for certain sounds I only let one play at once, I just retriggered it. I considered adding an option where if you play a new sound, all the volumes on the other ones are reduced to balance it, but I never got round to it. In Max, currently if I have 10 UFOs and they all explode at once, each has its own channel and will play an explosion noise. I could of course have a single global explosion channel, but then if a couple explode one after the other, restarting the sample (instead of playing it on another channel) sounds rubbish. So I could make an array and limit the number and perhaps put volume balancing it, but I'm not sure I need to. Basically what are your views on the matter and how have you "resolved" this issue. Thanks in advance. |
| ||
I seem to remember you asking this question on a number of occasions and on each I posted my solution :) I won't dig it out again, it's on here somewhere :D |
| ||
Well I had your problem to, as in my game there is a very short "explosion" (well its not really an explosion) sample - so I made a boolean Array. Like this : IsExplosionSamplePlaying[32] '32 Channels ExplosionSampleStartTime[32] If Explosion If ExplosionSamplePlaying[i]=False 'here you would search for the first free place in the array PlaySound Boom 'no channel i:+1 IsExplosionSamplePlaying[i]=True ExplosionSampleStartTime[i]=Millisecs() End If End If For i=1 to 32 If ExplosionSamplePlaying[i]=True If ExplosionSampleStartTime[i]-Millisecs()>= 50 'assuming the sample is 80 milliseconds long. ExplosionSamplePlying[i]=False End If End If Next |
| ||
This code wraps sounds in a type and records the last time a particular sound was played. If the last time the sound was played was only a few milliseconds ago, it doesn't play the sound. I set it to only a few milliseconds because my goal wasn't simply to avoid having sounds be loud, but instead to avoid the flanging effect you get when two identical sounds are played just milliseconds apart, and the way sounds are louder when repeated soon after one another. You can increase the delay if it isn't long enough for your tastes. I set it to what worked well in my Lego game.Type Sound Global List:TList = CreateList() Global Path$ = "sfx\" Global Volume_SFX# = 1.0 Global Volume_Music# = 1.0 Global MusicChannel:TChannel Global MusicTrack% = -1 Field _TSound:TSound Field _Looping% Field _LastPlayTime% ' ------------------------------------------------------------------------------------------------------------------------------------------------------- ' This method loads a sound. ' Specifying Null for Url will create a null sound which will do nothing if played. This is useful for creating placeholder sound instances. ' ------------------------------------------------------------------------------------------------------------------------------------------------------- Function Load:Sound(Url:Object, Loop%=False) Local NS:Sound NS = New Sound NS._TSound = LoadSound(Url, Loop) If (NS._TSound = Null) And (Url <> Null) Then RuntimeError("Error in Sound.Load() : ''" + String(Url) + "'' failed to load. Please reinstall the game.") NS._Looping = Loop List.AddLast(NS) Return NS End Function ' ------------------------------------------------------------------------------------------------------------------------------------------------------- ' Volume# allows you to set the sound's volume. ' Rate# allows you to adjust the speed at which the sound is played back up or down. ' ------------------------------------------------------------------------------------------------------------------------------------------------------- Method Play:TChannel(Volume#=1.0, Rate#=1.0) Local Channel:TChannel If _TSound = Null Then Return Null If Volume# < 0 Then Volume# = 0 If Volume# > 1 Then Volume# = 1 ' If the timer has looped, or this sound wasn't played too recently... If (_LastPlayTime > MilliSecs()) Or (MilliSecs() > (_LastPlayTime + 60)) ' Note: ' If any sounds are looped, we'll need to create a channel type to hold the currently active channels and so we can alter their volume when ' the sound effects volume slider is moved. ' Get sound ready to play. Channel = CueSound(_TSound) ' Set sound volume and pitch. Channel.SetVolume(Volume_SFX#*Volume#) Channel.SetRate(Rate#) ' Start playing sound. Channel.SetPaused(False) ' Record the time at which this sound was played so that we can avoid playing the same sound more than once in quick succession. _LastPlayTime = MilliSecs() Return Channel EndIf End Method End Type ' ------------------------------------------------------------------------------------------------------------------------------------------------------- ' This function loads all the sounds the game needs. ' ------------------------------------------------------------------------------------------------------------------------------------------------------- Global SOUND_MouseClick:Sound Global SOUND_HighlightFruit:Sound Global SOUND_PickFruit:Sound Global SOUND_UnpickFruit:Sound Global SOUND_SwapFruit:Sound Function LoadSounds() SOUND_MouseClick = Sound.Load(Sound.Path$ + "mouseclick.wav") SOUND_HighlightFruit = Sound.Load(Sound.Path$ + "highlightfruit.wav") SOUND_PickFruit = Sound.Load(Sound.Path$ + "pickfruit.wav") 'SOUND_UnpickFruit = Sound.Load(Sound.Path$ + "unpickfruit.wav") SOUND_SwapFruit = Sound.Load(Sound.Path$ + "swapfruit.wav") End Function |
| ||
I knew Indiepath would have a module ;-) Actually I think I have a link or the source somewhere. VomitOnLino: Yeah I see what you are doing, but try checking out the ChannelPlaying function. Surely it must return false when the sample stops (maybe not...) sswift: thanks, that's a good idea too, a different approach. Yeah I was just really looking for ideas and finding out if anyone has tried volume balancing. |