Corona Reference: Audio
Loading Audio
When we need to include a short sound file in our app, we can import it using the
loadSound
method, and give it a variable name as follows:
local sound_name = audio.loadSound( "PATH\FILE.EXTENSION" )
Files loaded in this manner can be played simultaneously. For example, if your game plays a chime when the user gets a point, the same chime can be played twice and overlap.
For longer files, we can use the
loadStream
method:
local sound_name = audio.loadStream( "PATH\FILE.EXTENSION" )
With this method, only small pieces of the sound file is loaded at a particular time. This makes no difference to the user, except that it helps free up available memory. This is generally the method you'd use if you have a soundtrack for a game. Note that files loaded in this manner cannot be played in multiple instances simultaneously. If you need the file to overlap, you'll need to load it twice, and create two variable names.
It's generally best to use 16-bit uncompressed .wav files, as these will work with any device and simulator. Otherwise, the file type you use would depend on the platform you're developing for, and the computer you're using to create your app:
- Android: Supports .wav, .mp3, and .ogg
- iOS: Supports .wav, .mp3, .caf, and .acc
- Windows Simulator: Supports .wav and .mp3
- Mac Simulator: Supports .wav, .mp3, .caf, and .acc
To retrieve the length (in milliseconds) of a sound you have already loaded, use
audio.getDuration( mySound )
This will return -1 if the length of the file cannot be determined.
Playing Audio
After you've imported the audio file and assigned a (unique) variable name to it, you can start using it in your app.
Playback
After defining the variable for the sound, use the
play
method to play it back:
local sound_name = audio.loadSound( "PATH\FILE.EXTENSION" )
audio.play( sound_name )
We'll now create a rectangle that plays a chime when tapped. Download the following sound file to use in the example. Right click the link and save the file in your project folder, along with your main.lua file. If you choose to keep your sound files in another folder, you'll need to change the path to the file in the code.
Doorbell Sound (right click, save linked file)
local door, doorbellChime, playSound
function playSound( event )
audio.play( doorbellChime )
end
doorbellChime = audio.loadSound( "doorbell.wav" )
door = display.newRect( 100, 200, 60, 60 )
door:addEventListener( "tap", playSound )
Playback Options
Aside from simply playing the tone, we can create a table of options to pass to the
play
function. The following outline of such a table shows the available options:
{
channel = channel_index, -- specify a particular channel between 1 and 32, or leave out to have a channel automatically selected
loops = num_value, -- number of times to loop after original playback
duration = time_value, -- time (in milliseconds) to play; if shorter than length of file, will terminate sound before completion
fadeIn = num_value, -- time (in milliseconds) to increase from minimal channel volume to normal volume
onComplete = function_name -- function to be called when sound is complete
}
For instance, we can now make the doorbell ring twice, with a brief fade in at the beginning of the tone.
local door, doorbellChime, playSound
function playSound( event )
audio.play( doorbellChime, { loops = 1, fadeIn = 200 } )
end
doorbellChime = audio.loadSound( "doorbell.wav" )
door = display.newRect( 100, 200, 60, 60 )
door:addEventListener( "tap", playSound )
Channels
The Corona audio system (currently) gives you access to 32 channels on which to play sounds. This means that you are currently limited to playing 32 sounds simultaneously - you can have many more audio files in your app, but only 32 can be playing at any particular time. Most of the time, Corona will handle channels for you. Sounds will play on any available track, as long as there is one. In some cases, though, you may want a little more control over how your audio is played back.
Channel Information
You can retrieve information about the available channels at any time. To determine the total number of channels (available or otherwise), use
audio.totalChannels
This will return 32, unless Corona makes a change to the channel limit in the future. The value
audio.freeChannels
will return the total number of free channels, while
audio.usedChannels
returns the number of channels currently in use.
To determine if a specific channel is currently playing a sound, use
audio.isChannelPlaying( i )
where
i is the channel index between 1 and 32. This will return true if the channel is playing a sound, and false otherwise. Similarly,
audio.isChannelPaused( i )
returns true if the channel is in use, but the playback is paused. Finally,
audio.isChannelActive( i )
returns true if the channel is either playing a sound or is paused.
To find the first available channel (one that is neither in use nor reserved), use
audio.findFreeChannel()
which returns the first channel that can be used, or 0 if no channels are available.
Reserving Channels
You can also assign a sound to a particular channel. For instance, if you have background music in a game, you might want to play it on channel 1, and set the volume for the music independently of the other sounds in the game. To reserve particular channels, use
audio.reserveChannels( num_value )
where
num_value is the number of channels you'd like reserved. Set to 0 to unreserve all channels. To play a sound on a particular channel, you can specify one by index in the playback option menu.
The value
audio.unreservedFreeChannels
returns the number of channels which are free and unreserved, while
audio.unreservedUsedChannels
returns the number of channels that are reserved, but either currently playing a sound or storing a paused sound.
Pause, Stop, and Resume
To pause playback temporarily, use
audio.pause( channel_name )
where
channel_name is the channel on which the sound is playing. This could be the number of the channel, or a variable name assigned to the channel. Unless you have specifically requested a channel for your sound, you probably wouldn't know which channel it's playing on. To resolve this, when playing a sound, you can assign a name to the channel as follows:
local channel_name = audio.play( sound_name )
audio.pause( channel_name )
where
var_name is the name of your sound. If no channel is passed to the
pause
function, all sounds will be paused.
To resume the sound again, use
audio.resume( channel_name )
Note that pausing a sound will not free the channel on which it is playing. To stop playback and free the channel used by the sound, use
audio.stop( channel_name )
Again, if no name is passed to this method, all sounds will be stopped. If the sound was loaded using
loadSound
, then it will be reset at the beginning for the next playback after it has been stopped. If you load the sound with
loadStream
, then it will resume where it was stopped, similar to pausing. The difference is that the channel is still freed for other sounds, as opposed to pausing.
You can also instruct Corona to stop playback on a particular channel after a set amount of time, using
audio.stopWithDelay( time_value, { channel = channel_name } )
where
num_value is the amount of time, in milliseconds, after which you'd like playback to stop.
To completely remove a sound, use
audio.dispose( sound_name )
where
sound_name is the name of your sound.
Seek and Rewind
If you'd like to skip to a particular point in a song, you can use the
seek
function. If you have loaded the sound using
loadSound
, then you'll have to define this time by the particular channel the sound is playing on:
audio.seek( time_value, channel_name )
On the other hand, sounds loaded using
loadStream
can be searched using their name or by channel:
audio.seek( time_value, sound_name )
or
audio.seek( time_value, { channel = channel_index } )
To start a sound from the beginning, use
audio.rewind( channel_name )
If you loaded the sound using
loadStream
, you can pass either the name of the channel or the name of the sound itself to the
rewind
function. If you want to start all playing sound from the beginning, do not pass anything to the
rewind
function.
Volume
To change the master volume of all sounds, use
audio.setVolume( volume_value )
The
volume_value can be any value between 0 and 1, where 1 is the maximum volume and 0 is muted.
The volume of channel playback can be controlled independently. This allows you to have background music playing at a different level than sound effects, for instance. To set the volume for a particular channel (by index), use
audio.setVolume( volume_value, { channel = channel_index })
You can also set a minimum master volume (for all sounds) or for a particular channel using either
audio.setMinVolume( volume_value )
or
audio.setMinVolume( volume_value, { channel = channel_index })
respectively. You can set a maximum volume for a particular channel using
audio.setMinVolume( volume_value, { channel = channel_index })
There is no maximum master volume.
To get the current volume of a particular channel, use
audio.getVolume({ channel = channel_index })
or set the
channel_index to 0 to obtain the average volume across all channels. Note that the value returned is scaled by the ringer volume of the device. So, if the volume was set to 0.8 but the user has the device volume at 50%, then the value returned will be 0.4.
To get the maximum volume of a particular channel, use
audio.getMaxVolume({ channel = channel_index })
Similarly,
audio.getMinVolume({ channel = channel_index })
returns the minimum volume of a channel. Using channel index 0 returns the average minimum volume of all channels.
To fade the volume of a channel up or down, use
audio.fade({ channel = channel_index, time = time_value, volume = num_value })
where the time is in milliseconds, and volume is a value between 0 and 1 that you'd like the volume to change to. Note that this will become the new volume for this channel. For instance, fading a sound to 0 will result in all subsequent sounds on that channel being played at volume 0 (which is not audible). You'll need to adjust it back to its original volume if desired.