HomeForumSourceResearchGuide
<< back to How To home

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.