Dispose Audio Across Scenes

Followed Rob’s tut on creating a sound Module:

http://www.coronalabs.com/blog/2013/06/04/tutorial-handling-cross-scene-audio/

We have a module called vars.

Each 30 scenes requires vars.lua. - local vars = require(“vars”)

vars.lua contains separate functions to audio.loadSound particular to each scene e.g. scene 2 calls vars.pg02() - right up to scene 30 calls vars.pg30()

But how to dispose of the audio?

This isn’t working at all…

            for k, v in pairs(vars) do
                print(k,v)
                audio.dispose(vars[k])
                vars[k]=nil
            end  

Thought about putting elements into another table so that we have access to the audioHandle to use in audio.dispose.

This is how it’s set up.

vars.lua

    vars = {}

    vars.pg02 = function()
    
    local audioTags = {
        {audioHandle = “vars.Eng01”,             audioFile = “02eng01.mp3”}, – ch1
        {audioHandle = “vars.Musicpg02”,         audioFile = “02music.mp3”}, – ch2
        {audioHandle = “vars.PekoWahey01”,     audioFile = “pekowahey01.mp3”}, – ch3
        {audioHandle = “vars.tractorBeat”,     audioFile = “tractorbeat.mp3”}, – ch4
        }
    
    for i = 1, #audioTags do
        audioTags[i].audioHandle = audio.loadSound(audioDir…audioTags[i].audioFile)
    end

Then from within other scenes we go:

local vars = require (“vars”)

vars.pg02()

Running this does not result in an error but the audio does not play.

I’m guessing you can’t assign audioHandle to loadSound in this way?

The main point is that the audioHandle has to be in the format of these explicit vars.Name (it can’t be dynamically assigned names)

Hi @kilopop,

I do something similar to this (reading in level-specific sounds from a text file), and it works fine. But, I add the named handles to a holding table, as dictionary keys. I just pasted my code, but you can see the basic workings…

[lua]

local soundData = st_match( contents, “SOUNDS…\n(.*)\n…SOUNDS” )

for sound, file in st_gmatch( soundData, “(%a+)=%s([%w%d%p]+)\n” ) do

   local handle = “sfx_lev_”…sound ; soundTable[handle] = audio.loadSound( audLoc[1]…file…audLoc[2] ) ; handle = nil

end

[/lua]

Notice that I put the handles into a table called “soundTable”. Then, when I play a sound, I just reference it by the dictionary key name within that table. Works fine, and on dispose (end of level) I just loop through by pairs and dispose them.

Brent

Thanks a lot Brent, that did it. Specifically line 4 which turned the audiohandle into parts of the original vars table so that the for i loop is adjusted to:

    for i = 1, #audioTags do       
        local handle = audioTags[i].audioHandle
        vars[handle] = audio.loadSound(audioDir…audioTags[i].audioFile)
    end

Love your work!

Sorry, vars[handle] works brilliantly to load audio but in this case, the normal dispose code of loop by pairs through vars doesn’t work:

            for k, v in pairs(vars) do
                audio.dispose(vars[k])
                vars[k]=nil
            end

This doesn’t work because as well as the audio, vars.lua also contains 30+ functions which hold each of the groups of audio related to each scene. So if you loop through vars, all the functions are niled out. This is a problem in Director when the current scene calls a function in vars.lua after the prior scene has niled it out (there is a short cross over period in Director where both scenes are in memory for 50 mili-seconds).

What we specifically need to do is loop audio.dispose etc through vars[handle] not vars generally.  But what we’ve tried so far isn’t working, any ideas??

This appears to solve the issue where we check the key type before disposing and niling. We only want to dispose of key type “userdata”.

            local k,v
                 
            for k, v in pairs(vars) do
                if type(vars[k])== “userdata” then
                    audio.dispose(vars[k])
                    vars[k]=nil
                end
            end

Is this a robust solution?

Hi @kilopop,

That should be fine, since only the audio handles in that table should be of type “userdata”. But, if you want to be safe, you could just create a new table (or a sub-table of the main one) to put the handles in, and loop through that to nail all items for disposal.

Brent

Thought about putting elements into another table so that we have access to the audioHandle to use in audio.dispose.

This is how it’s set up.

vars.lua

    vars = {}

    vars.pg02 = function()
    
    local audioTags = {
        {audioHandle = “vars.Eng01”,             audioFile = “02eng01.mp3”}, – ch1
        {audioHandle = “vars.Musicpg02”,         audioFile = “02music.mp3”}, – ch2
        {audioHandle = “vars.PekoWahey01”,     audioFile = “pekowahey01.mp3”}, – ch3
        {audioHandle = “vars.tractorBeat”,     audioFile = “tractorbeat.mp3”}, – ch4
        }
    
    for i = 1, #audioTags do
        audioTags[i].audioHandle = audio.loadSound(audioDir…audioTags[i].audioFile)
    end

Then from within other scenes we go:

local vars = require (“vars”)

vars.pg02()

Running this does not result in an error but the audio does not play.

I’m guessing you can’t assign audioHandle to loadSound in this way?

The main point is that the audioHandle has to be in the format of these explicit vars.Name (it can’t be dynamically assigned names)

Hi @kilopop,

I do something similar to this (reading in level-specific sounds from a text file), and it works fine. But, I add the named handles to a holding table, as dictionary keys. I just pasted my code, but you can see the basic workings…

[lua]

local soundData = st_match( contents, “SOUNDS…\n(.*)\n…SOUNDS” )

for sound, file in st_gmatch( soundData, “(%a+)=%s([%w%d%p]+)\n” ) do

   local handle = “sfx_lev_”…sound ; soundTable[handle] = audio.loadSound( audLoc[1]…file…audLoc[2] ) ; handle = nil

end

[/lua]

Notice that I put the handles into a table called “soundTable”. Then, when I play a sound, I just reference it by the dictionary key name within that table. Works fine, and on dispose (end of level) I just loop through by pairs and dispose them.

Brent

Thanks a lot Brent, that did it. Specifically line 4 which turned the audiohandle into parts of the original vars table so that the for i loop is adjusted to:

    for i = 1, #audioTags do       
        local handle = audioTags[i].audioHandle
        vars[handle] = audio.loadSound(audioDir…audioTags[i].audioFile)
    end

Love your work!

Sorry, vars[handle] works brilliantly to load audio but in this case, the normal dispose code of loop by pairs through vars doesn’t work:

            for k, v in pairs(vars) do
                audio.dispose(vars[k])
                vars[k]=nil
            end

This doesn’t work because as well as the audio, vars.lua also contains 30+ functions which hold each of the groups of audio related to each scene. So if you loop through vars, all the functions are niled out. This is a problem in Director when the current scene calls a function in vars.lua after the prior scene has niled it out (there is a short cross over period in Director where both scenes are in memory for 50 mili-seconds).

What we specifically need to do is loop audio.dispose etc through vars[handle] not vars generally.  But what we’ve tried so far isn’t working, any ideas??

This appears to solve the issue where we check the key type before disposing and niling. We only want to dispose of key type “userdata”.

            local k,v
                 
            for k, v in pairs(vars) do
                if type(vars[k])== “userdata” then
                    audio.dispose(vars[k])
                    vars[k]=nil
                end
            end

Is this a robust solution?

Hi @kilopop,

That should be fine, since only the audio handles in that table should be of type “userdata”. But, if you want to be safe, you could just create a new table (or a sub-table of the main one) to put the handles in, and loop through that to nail all items for disposal.

Brent