Hi Sean,
I hope this code helps, its a multi-channel sound system I developed for BMax that allows queing, overlapping, no-overlapping. It will support as many channels as you want and any queue depth. It will also clean up after itself.
This code is based on something done for Blitz3D some years ago by someone else - no idea who.
' And Indiepath Production by Tim Fisher (c)2005 Indiepath LTd
DebugLog "MOD_SFX_Engine.bmx"
Const CH_ANY = -1
Const CH_1 = 1 'Brick Sounds
Const CH_2 = 2 'Score Sounds
Const CH_3 = 3 'Powerup Sounds
Const CH_4 = 4 'Incidential Sounds
Const CH_5 = 5
Const CH_6 = 6 ' Diamond Sounds
Const CH_7 = 7 ' Chords
Const CH_8 = 8 ' Vox
Const CH_9 = 9 ' GUI Sounds
Const CH_10 = 10 ' BG Music
Const CH_11 = 11 ' Score Sounds
' ---------------------------------------------------------------------
Global ChannelTList:TList = New TList
Type ActiveChannel
Field SampleID :Int
Field Address :TChannel
Field FadeTime :Double
Field FadeStart :Double
Field CreateTime:Int
Field Volume :Double
Field VolumeS :Double
Field Queue :TSound[8]
Field VolQ :Double[8]
Field Qcount :Double
Method New ()
If ChannelTList = Null Then ChannelTList = New TList
ChannelTList.AddLast Self
End Method
'----------------------------------------------------------------
Function Destroy (a:ActiveChannel)
Local b:Int
a.Address = Null
For b = 0 To 7
a.Queue[b] = Null
Next
ChannelTList.Remove a
a = Null
FlushMem
End Function
'----------------------------------------------------------------
Function MusicQueueState(ID:Int)
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
If c.SampleID = ID Then Return Int(c.QCount)
Next
End Function
'----------------------------------------------------------------
Function PlaySample(add:TSound,ID:Int=-1,Vol:Double=1,Queue:Byte=False,overlap:Byte=False,rate:Double=1)
Local Channel:ActiveChannel
Local Simultaneous:Byte = False
Local Playing:Byte = False
If ID <0 Then Simultaneous = True
For Channel:ActiveChannel = EachIn ChannelTList
If Channel.SampleID = ID
If Queue = True
Channel.Qcount = Channel.Qcount + 1
If Channel.Qcount > 1 Then
Channel.QCount = 1
DebugLog "**SFX Queue Overload!"
Return
EndIf
Channel.Queue[Channel.Qcount] = add
Channel.VolQ[Channel.Qcount] = vol
Playing = True
Else
Playing = True
EndIf
If overlap And (MilliSecs() - Channel.Createtime > 100) Then Playing = False
EndIf
If Not ChannelPlaying(Channel.Address) Then
StopChannel(Channel.Address)
Destroy(Channel)
EndIf
Next
If Not (Simultaneous = False And Playing = True)
Channel:ActiveChannel = New ActiveChannel
Channel.SampleID = ID
Channel.Address = AllocChannel()
Channel.Volume = Vol
Channel.VolumeS = Vol
SetChannelVolume(Channel.Address,Channel.Volume)
PlaySound(Add,Channel.Address)
Channel.FadeTime = 0
Channel.CreateTime = MilliSecs()
SetChannelRate(Channel.Address,rate)
EndIf
End Function
'----------------------------------------------------------------
Method Update()
Local a:Int
If Not ChannelPlaying(self.Address)
If self.Qcount = 0
StopChannel(self.address)
Destroy(Self)
Return
Else
SetChannelVolume(self.address,self.volQ[1])
PlaySound(self.queue[1],self.address)
For a = 1 To self.qCount - 1
self.queue[a] = self.queue[a+1]
self.volQ[a] = self.volQ[a+1]
Next
self.Queue[self.Qcount] = Null
self.Qcount = self.Qcount - 1
EndIf
EndIf
If Self.FadeTime
If self.Volume <= 0 Then
If self.Qcount = 0
StopChannel(self.address)
Destroy(Self)
Else
Self.FadeTime = 0
Self.Volume = self.volQ[1]
SetChannelVolume(self.address,self.volQ[1])
PlaySound(self.queue[1],self.address)
For a = 1 To self.qCount - 1
self.queue[a] = self.queue[a+1]
self.volQ[a] = self.volQ[a+1]
Next
self.Queue[self.Qcount] = Null
self.Qcount = self.Qcount - 1
EndIf
Else
Self.Volume = self.VolumeS - Float(MilliSecs() - self.FadeStart) / self.fadetime
SetChannelVolume(self.address,self.volume)
EndIf
EndIf
End Method
'----------------------------------------------------------------
Function UpdateAll()
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
c.Update()
Next
End Function
'----------------------------------------------------------------
Function SoundOff()
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
StopChannel(c.address)
Destroy(c)
Next
End Function
'----------------------------------------------------------------
Function SetVolume(ID:Int,Vol:Double)
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
If c.SampleID = ID Then SetChannelVolume(c.address,vol)
Next
End Function
'----------------------------------------------------------------
Function Playing(ID:Int)
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
If c.SampleID = ID And ChannelPlaying(c.address) Then Return True
Next
Return False
End Function
'----------------------------------------------------------------
Function ReleaseSample(ID:Int,Timeout:Double)
Local c:ActiveChannel
For c:ActiveChannel = EachIn ChannelTList
If Not c.FadeTime
If c.SampleID = ID Then
If Timeout
c.FadeTime = Timeout
c.FadeStart = MilliSecs()
Else
StopChannel(c.Address)
destroy(c)
EndIf
EndIf
EndIf
Next
End Function