libdragon
|
Interface to the N64 audio hardware. More...
Files | |
file | audio.c |
Audio Subsystem. | |
file | audio.h |
Audio Subsystem. | |
Defines | |
#define | TV_TYPE_LOC 0x80000300 |
Memory location to read which determines the TV type. | |
#define | NUM_BUFFERS 4 |
Number of buffers the audio subsytem allocates and manages. | |
#define | CALC_BUFFER(x) ( ( ( ( x ) / 25 ) >> 3 ) << 3 ) |
Macro that calculates the size of a buffer based on frequency. | |
Functions | |
static volatile int | __busy () |
Return whether the AI is currently busy. | |
static volatile int | __full () |
Return whether the AI is currently full. | |
static void | audio_callback () |
Send next available chunks of audio data to the AI. | |
void | audio_init (const int frequency, int numbuffers) |
Initialize the audio subsystem. | |
void | audio_init_ex (const int frequency, int numbuffers, int maxsamples, void(*cb)()) |
Initialize the audio subsystem (extended) | |
void | audio_close () |
Close the audio subsystem. | |
void | audio_write (const short *const buffer) |
Write a chunk of audio data. | |
void | audio_write_silence () |
Write a chunk of silence. | |
volatile int | audio_can_write () |
Return whether there is an empty buffer to write to. | |
int | audio_get_frequency () |
Return actual frequency of audio playback. | |
int | audio_get_buffer_length () |
Get the number of stereo samples that fit into an allocated buffer. | |
void | audio_set_num_samples (int numsamples) |
Change the number of stereo samples to write to each buffer. | |
short * | audio_get_next_buffer (int *lastbuf) |
Return the address of the next buffer to fill. | |
volatile int | audio_send_buffer (int lastbuf) |
Start audio DMA on buffer. | |
Variables | |
static void(* | _callback )() = NULL |
The actual frequency the AI will run at. | |
static int | _frequency = 0 |
The actual frequency the AI will run at. | |
static int | _num_buf = NUM_BUFFERS |
The number of buffers currently allocated. | |
static int | _num_samp = 0 |
The number of samples to write into each buffer. | |
static int | _buf_size = 0 |
The buffer size in bytes for each buffer allocated. | |
static short ** | buffers = NULL |
Array of pointers to the allocated buffers. | |
static volatile int | now_playing = 0 |
Index of the current playing buffer. | |
static volatile int | now_writing = 0 |
Index pf the currently being written buffer. | |
static volatile int | buf_full = 0 |
Bitmask of buffers indicating which buffers are full. | |
static struct AI_regs_s *const | AI_regs = (struct AI_regs_s *)0xa4500000 |
Structure used to interact with the AI registers. | |
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. |
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 master clock of the N64, the audio subsystem needs to know what region the N64 is from. This is due to the fact that the master 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.
#define CALC_BUFFER | ( | x | ) | ( ( ( ( x ) / 25 ) >> 3 ) << 3 ) |
Macro that calculates the size of a buffer based on frequency.
[in] | x | Frequency the AI is running at |
#define TV_TYPE_LOC 0x80000300 |
Memory location to read which determines the TV type.
Values read include 0 for PAL, 1 for NTSC and 2 for MPAL
static volatile int __busy | ( | ) | [inline, static] |
Return whether the AI is currently busy.
static volatile int __full | ( | ) | [inline, static] |
Return whether the AI is currently full.
static void audio_callback | ( | ) | [static] |
Send next available chunks of audio data to the AI.
This function is called whenever internal buffers are running low. It will send as many buffers as possible to the AI until the AI is full.
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.
void audio_close | ( | ) |
Close the audio subsystem.
This function closes the audio system and cleans up any internal memory allocated by audio_init.
int audio_get_buffer_length | ( | ) |
Get the number of stereo samples that fit into an allocated buffer.
int audio_get_frequency | ( | ) |
Return actual frequency of audio playback.
short* audio_get_next_buffer | ( | int * | lastbuf | ) |
Return the address of the next buffer to fill.
This function returns a pointer to the next buffer to fill with stereo 16-bit samples. The number of stereo samples to write may be found by calling audio_get_buffer_length. Pointer is uncached.
[in] | lastbuf | pointer to previous buffer index |
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.
[in] | frequency | The frequency in Hz to play back samples at |
[in] | numbuffers | The number of buffers to allocate internally |
void audio_init_ex | ( | const int | frequency, |
int | numbuffers, | ||
int | maxsamples, | ||
void(*)() | cb | ||
) |
Initialize the audio subsystem (extended)
This function will set up the AI to play at a given frequency, allocate a number of back buffers to write data to using the specified max number of stereo samples, and set the provided callback function. Max samples must be even, and if the callback is NULL, the built-in callback is used.
[in] | frequency | The frequency in Hz to play back samples at |
[in] | numbuffers | The number of buffers to allocate internally |
[in] | maxsamples | The max number of stereo 16-bit samples each buffer will hold |
[in] | cb | The callback function for audio interrupts |
volatile int audio_send_buffer | ( | int | lastbuf | ) |
Start audio DMA on buffer.
This function sets the audio DMA for the indexed buffer (should be the same as set by audio_get_next_buffer), and starts the DMA.
[in] | lastbuf | last buffer index returned by audio_get_next_buffer |
void audio_set_num_samples | ( | int | numsamples | ) |
Change the number of stereo samples to write to each buffer.
This function sets how many stereo samples to write to the audio buffers. It should be even so that the buffer length is divisible by eight bytes for DMA restrictions. It MUST be smaller than the max number of samples passed to audio_init_ex, but is not checked.
[in] | numsamples | number of stereo samples to write to each buffer |
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.
[in] | buffer | Buffer containing stereo samples to be played |
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.