I am fairly new to Lua. Raised on 65C02 Assembly, Pascal and C, this project I’ve been working on now for about 4 months is my first step into Lua-land.
I came across an issue with the Audio API that cost me several hours and much research in the forums, and I was compelled to share this information with people based on my findings. I don’t know if others will think I’m mistaken, that’s also part of reason that motivates this thread.
audio.stop() is a function that you use to kill audio (SFX or Music) that has been triggered by audio.play() and audio.play() allows many different parameters to be passed. Ultimately, you can assign volume and channels (in case you’ve reserved or assigned special channels for things like music) and then assign the channel that the sound was triggered on to a handle for later use/tracking.
handle=audio.play(mediaFile, {channel=MUSIC\_CH,onComplete=songOver}}
songOver()
handle=nil
end
Imagine the music is playing along and it’s a 30 second ditty. But imagine before the song finishes, you need to stop the music because of a screen transition or a myriad of other reasons. So you use audio.stop()
audio.stop(handle)
Now it should be noted that in this case, because we put the music on a designated channel, we could use the MUSIC_CH
audio.stop(MUSIC\_CH)
so imagine we used the handle instead - because the two should be equivalent.
If you think about it, there are circumstances you can run into where handle may be NIL. Maybe your code tries to kill a SFX or Music that hasn’t been triggered yet, so the handle is still NIL. Or maybe the SFX or Music has finished, and the onComplete has made the handle NIL. Ultimately, here’s what happens and here is the rub:
audio.stop() kills all 32 channels.
audio.stop(0) kills all 32 channels.
audio.stop(nil) kills all 32 channels.
Now in Lua, NIL is by definition a different type. So it’s not equivalent. And in the context of this discussion, if a programmer meant to pass a handle/channel to audio.stop(handle) and handle became NIL, that programmer most likely certainly didn’t expect or want to kill ALL 32 channels of sound. Yet that’s the result. This isn’t mentioned in the API documentation (currently). This potentially will drive people “crazy” and they’ll think the API is flakey when in fact, it’s just - in my eyes - unexpected behavior. Most likely the C code, which treats NIL as NULL as (void *)0 is all equivalent. That’s just a guess. Regardless, you should use a wrapper on any audio.stop(channel) calls.
if handle ~= nil then
audio.stop(handle)
handle=nil
end
This wrapper will help prevent you from having SFX trigger, but not play because say for instance as you transition from your end of level to the next screen you trigger a SFX that indicates level is over, immediately followed by killing the music, but the handle is nil, and so the SFX you just triggered gets killed before you can hear it. That’s what lead me down this path and finding out my SFX was in fact being triggered, being assigned a handle, and also calling the onComplete function… but the trick was my sound was SO short (less than a second) that I couldn’t tell in my terminal window that the SFX was being killed before it could be heard by the audio.stop(nil) call. D’oh!!! I thought maybe the volume had somehow been set to 0, so I just didn’t hear it. I thought the channel assignment didn’t happen. But all error checking and code analysis indicated the sound triggered, was playing - but onComplete actually passes back an event parameter; a boolean called “completed” and this will tell you if audio.stop() killed your sound, or if it just didn’t finish playing for some reason.
completed
boolean: This value will be true if the audio stopped because it finished playing normally (played to the end of the sound). This value will be false if the audio was stopped because of other reasons.
Hopefully this will help someone out there and prevent HOURS of debugging.
[import]uid: 74844 topic_id: 16908 reply_id: 316908[/import]