libdragon
Modules | Files | Macros | Functions
Audio Subsystem

Interface to the N64 audio hardware. More...

Modules

 Audio mixer
 Flexible, composable, fast, RSP-based audio mixer.
 

Files

file  audio.c
 Audio Subsystem.
 
file  audio.h
 Audio Subsystem.
 

Macros

#define NUM_BUFFERS   4
 Number of buffers the audio subsytem allocates and manages.
 
#define BUFFERS_PER_SECOND   25
 How many different audio buffers we want to schedule in one second.
 
#define CALC_BUFFER(x)   ( ( ( ( x ) / BUFFERS_PER_SECOND ) >> 3 ) << 3 )
 Macro that calculates the size of a buffer based on frequency. More...
 

Functions

void audio_init (const int frequency, int numbuffers)
 Initialize the audio subsystem. More...
 
void audio_set_buffer_callback (audio_fill_buffer_callback fill_buffer_callback)
 Install a audio callback to fill the audio buffer when required. More...
 
void audio_close ()
 Close the audio subsystem. More...
 
void audio_pause (bool pause)
 Pause or resume audio playback. More...
 
void audio_write (const short *const buffer)
 Write a chunk of audio data. More...
 
short * audio_write_begin (void)
 Start writing to the first free internal buffer. More...
 
void audio_write_end (void)
 Complete writing to an internal buffer. More...
 
void audio_write_silence ()
 Write a chunk of silence. More...
 
volatile int audio_can_write ()
 Return whether there is an empty buffer to write to. More...
 
int audio_push (const short *buffer, int nsamples, bool blocking)
 Push a chunk of audio data (high-level function) More...
 
int audio_get_frequency ()
 Return actual frequency of audio playback. More...
 
int audio_get_buffer_length ()
 Get the number of stereo samples that fit into an allocated buffer. More...
 

DAC rates for different regions

#define AI_NTSC_DACRATE   48681812
 NTSC DAC rate.
 
#define AI_PAL_DACRATE   49656530
 PAL DAC rate.
 
#define AI_MPAL_DACRATE   48628316
 MPAL DAC rate.
 

AI Status Register Values

#define AI_STATUS_BUSY   ( 1 << 30 )
 Bit representing that the AI is busy.
 
#define AI_STATUS_FULL   ( 1 << 31 )
 Bit representing that the AI is full.
 

Detailed Description

Interface to the N64 audio hardware.

The audio subsystem handles queueing up chunks of audio data for playback using the N64 audio DAC. The audio subsystem handles DMAing chunks of data to the audio DAC as well as audio callbacks when there is room for another chunk to be written. Buffer size is calculated automatically based on the requested audio frequency. The audio subsystem accomplishes this by interfacing with the audio interface (AI) registers.

Because the audio DAC is timed off of the system clock of the N64, the audio subsystem needs to know what region the N64 is from. This is due to the fact that the system clock is timed differently for PAL, NTSC and MPAL regions. This is handled automatically by the audio subsystem based on settings left by the bootloader.

Code attempting to output audio on the N64 should initialize the audio subsystem at the desired frequency and with the desired number of buffers using audio_init. More audio buffers allows for smaller chances of audio glitches but means that there will be more latency in sound output. When new data is available to be output, code should check to see if there is room in the output buffers using audio_can_write. Code can probe the current frequency and buffer size using audio_get_frequency and audio_get_buffer_length respectively. When there is additional room, code can add new data to the output buffers using audio_write. Be careful as this is a blocking operation, so if code doesn't check for adequate room first, this function will not return until there is room and the samples have been written. When all audio has been written, code should call audio_close to shut down the audio subsystem cleanly.

Macro Definition Documentation

◆ CALC_BUFFER

#define CALC_BUFFER (   x)    ( ( ( ( x ) / BUFFERS_PER_SECOND ) >> 3 ) << 3 )

Macro that calculates the size of a buffer based on frequency.

Parameters
[in]xFrequency the AI is running at
Returns
The size of the buffer in bytes rounded to an 8 byte boundary

Function Documentation

◆ audio_init()

void audio_init ( const int  frequency,
int  numbuffers 
)

Initialize the audio subsystem.

This function will set up the AI to play at a given frequency and allocate a number of back buffers to write data to.

Note
Before re-initializing the audio subsystem to a new playback frequency, remember to call audio_close.
Parameters
[in]frequencyThe frequency in Hz to play back samples at
[in]numbuffersThe number of buffers to allocate internally

◆ audio_set_buffer_callback()

void audio_set_buffer_callback ( audio_fill_buffer_callback  fill_buffer_callback)

Install a audio callback to fill the audio buffer when required.

This function allows to implement a pull-based audio system. It registers a callback which will be invoked under interrupt whenever the AI is ready to have more samples enqueued. The callback can fill the provided audio data with samples that will be enqueued for DMA to AI.

Parameters
[in]fill_buffer_callbackCallback to fill an empty audio buffer

◆ audio_close()

void audio_close ( )

Close the audio subsystem.

This function closes the audio system and cleans up any internal memory allocated by audio_init.

◆ audio_pause()

void audio_pause ( bool  pause)

Pause or resume audio playback.

Should only be used when a fill_buffer_callback has been set in audio_init. Silence will be generated while playback is paused.

◆ audio_write()

void audio_write ( const short *const  buffer)

Write a chunk of audio data.

This function takes a chunk of audio data and writes it to an internal buffer which will be played back by the audio system as soon as room becomes available in the AI. The buffer should contain stereo interleaved samples and be exactly audio_get_buffer_length stereo samples long.

To improve performance and avoid the memory copy, use audio_write_begin and audio_write_end instead.

Note
This function will block until there is room to write an audio sample. If you do not want to block, check to see if there is room by calling audio_can_write.
Parameters
[in]bufferBuffer containing stereo samples to be played

◆ audio_write_begin()

short * audio_write_begin ( void  )

Start writing to the first free internal buffer.

This function is similar to audio_write but instead of taking samples and copying them to an internal buffer, it returns the pointer to the internal buffer. This allows generating the samples directly in the buffer that will be sent via DMA to AI, without any subsequent memory copy.

The buffer should be filled with stereo interleaved samples, and exactly audio_get_buffer_length samples should be written.

After you have written the samples, call audio_write_end() to notify the library that the buffer is ready to be sent to AI.

Note
This function will block until there is room to write an audio sample. If you do not want to block, check to see if there is room by calling audio_can_write.
Returns
Pointer to the internal memory buffer where to write samples.

◆ audio_write_end()

void audio_write_end ( void  )

Complete writing to an internal buffer.

This function is meant to be used in pair with audio_write_begin(). Call this once you have generated the samples, so that the audio system knows the buffer has been filled and can be played back.

◆ audio_write_silence()

void audio_write_silence ( )

Write a chunk of silence.

This function will write silence to be played back by the audio system. It writes exactly audio_get_buffer_length stereo samples.

Note
This function will block until there is room to write an audio sample. If you do not want to block, check to see if there is room by calling audio_can_write.

◆ audio_can_write()

volatile int audio_can_write ( )

Return whether there is an empty buffer to write to.

This function will check to see if there are any buffers that are not full to write data to. If all buffers are full, wait until the AI has played back the next buffer in its queue and try writing again.

◆ audio_push()

int audio_push ( const short *  buffer,
int  nsamples,
bool  blocking 
)

Push a chunk of audio data (high-level function)

This function is an easy-to-use, higher level alternative to all the audio_write* functions. It pushes audio samples into output hiding the complexity required to match the fixed-size audio buffers.

The function accepts a buffer of stereo interleaved audio samples; nsamples is the number of samples in the buffer. The function will push the samples into output as much as possible.

If blocking is true, it will stop and wait until all samples have been pushed into output. If blocking is false, it will stop as soon as there are no more free buffers to push samples into, and will return the number of pushed samples. It is up to the caller to then take care of this and later try to call audio_push again with the remaining samples.

Note
You CANNOT mixmatch this function with the other audio_write* functions, and viceversa. If you decide to use audio_push, use it exclusively to push the audio.
Parameters
bufferBuffer containing stereo samples to be played
nsamplesNumber of stereo samples in the buffer
blockingIf true, wait until all samples have been pushed
Returns
int Number of samples pushed into output

◆ audio_get_frequency()

int audio_get_frequency ( )

Return actual frequency of audio playback.

Returns
Frequency in Hz of the audio playback

◆ audio_get_buffer_length()

int audio_get_buffer_length ( )

Get the number of stereo samples that fit into an allocated buffer.

Note
To get the number of bytes to allocate, multiply the return by 2 * sizeof( short )
Returns
The number of stereo samples in an allocated buffer