This program decodes audio from an MP3 file and plays it via the default audio output device.
We begin by creating a new file Main.dn and opening it in a text editor. In this file we declare the component that this source file will describe, declaring the interfaces that the component provides and requires. All behaviour in Dana is described using interfaces.
component provides App requires io.Output out, io.File, io.audio.AudioOut, io.audio.AudioTrack, media.audio.Decoder:mp3 {
}
We populate the component logic as below:
component provides App requires io.Output out, io.File, io.audio.AudioOut, io.audio.AudioTrack, media.audio.Decoder:mp3 {
Thread thread
AudioOut device
eventsink TrackEvents(EventData ed)
{
if (ed.type == AudioOut.[trackFinished] && ed.source === device)
{
thread.signal()
}
}
int4[] decodeAll(Decoder decoder, int sampleRate, int seconds)
{
int count = sampleRate * seconds
int4 samples[] = decoder.decode(count)
int4 result[] = samples
while ((samples = decoder.decode(count)) != null)
result = new int4[](result, samples)
return result
}
int App:main(AppParam params[])
{
//initialise audio output format and device
AudioFormat format = new AudioFormat(44100, 2)
device = new AudioOut(format)
sinkevent TrackEvents(device)
//read encoded file data
File fd = new File(params[0].string, File.READ)
byte content[] = fd.read(fd.getSize())
fd.close()
//decode audio data into raw frames; format must match output format
Decoder decoder = new Decoder:mp3(format, content)
int4 frames[] = decodeAll(decoder, format.sampleRate, 1000)
thread = this.thread
//play audio
AudioTrack track = new AudioTrack(format, frames)
device.play(track)
this.thread.wait()
return 0
}
}
This program initialises an audio output device, decodes an MP3 file, and plays the decoded audio. It then waits for playback to complete before exiting the program.
To run this program we first need to compile it:
dnc Main.dn
And press enter. This will compile your program.
We run the program via the Dana runtime, passing in a single command-line parameter indicating the MP3 file to play:
dana Main somefile.mp3
And press enter. As long as the MP3 file has a matching audio format (two-channel audio encoded at 44100) you should hear the audio. The full list of standard interfaces that you can use in requires directives can be viewed at the Dana API pages.
It's worth noting that we would normally decode audio incrementally in chunks for playback, rather than decoding it all in one go, since decoded audio takes a lot of memory. You can see more details of the range of API calls available in the io.audio package.