libdragon
Data Structures | Macros | Typedefs | Functions | Variables
mixer.c File Reference

RSP Audio mixer. More...

Data Structures

struct  mixer_channel_t
 Mixer channel state - CPU side. More...
 
struct  rsp_mixer_channel_t
 Mixer channel state - RSP side. More...
 
struct  rsp_mixer_settings_t
 Mixer ucode settings. More...
 
struct  channel_limit_t
 Configured limits of a mixer channel. More...
 
struct  mixer_event_t
 A mixer event (synchronized with sample playback) More...
 

Macros

#define MIXER_TRACE   0
 Set to 1 to activate debug logs.
 
#define tracef(fmt, ...)   ({ })
 like debugf(), but writes only if MIXER_TRACE is not 0
 
#define MAX_EVENTS   32
 Maximum number of mixer events.
 
#define MIXER_POLL_PER_SECOND   8
 Number of expected mixer_poll calls per second. More...
 
#define MIXER_STATE_SIZE   128
 Size of the ucode state that is automatically persisted by rspq.
 
#define CH_FLAGS_BPS_SHIFT   (3<<0)
 BPS shift value.
 
#define CH_FLAGS_16BIT   (1<<2)
 Set if the channel is 16 bit.
 
#define CH_FLAGS_STEREO   (1<<3)
 Set if the channel is stereo (left)
 
#define CH_FLAGS_STEREO_SUB   (1<<4)
 The channel is the second half of a stereo (right)
 
#define MIXER_FX64_FRAC   12
 Number of fractional bits in mixer_fx64_t.
 
#define MIXER_FX64(f)   (int64_t)((f) * (1<<MIXER_FX64_FRAC))
 Convert a floating point value to mixer_fx64_t.
 
#define MIXER_FX15_FRAC   15
 Number of fractional bits in mixer_fx15_t.
 
#define MIXER_FX15(f)   (int16_t)((f) * ((1<<MIXER_FX15_FRAC)-1))
 Convert a floating point value to mixer_fx15_t.
 
#define MIXER_FX16_FRAC   16
 Number of fractional bits for a fixed 16.16 value.
 
#define MIXER_FX16(f)   (int16_t)((f) * ((1<<MIXER_FX16_FRAC)-1))
 Convert a floating point value to a fixed 16.16 value.
 
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.
 

Typedefs

typedef uint64_t mixer_fx64_t
 Fixed point value used in waveform position calculations. This is a signed 64-bit integer with the fractional part using MIXER_FX64_FRAC bits. You can use MIXER_FX64 to convert from float.
 
typedef int16_t mixer_fx15_t
 Fixed point value used for volume and panning calculations. You can use MIXER_FX15 to convert from float.
 

Functions

 DEFINE_RSP_UCODE (rsp_mixer)
 
void mixer_init (int num_channels)
 Initialize the mixer. More...
 
void mixer_set_vol (float vol)
 Set master volume. More...
 
void mixer_close (void)
 Deinitialize the mixer.
 
void mixer_ch_set_freq (int ch, float frequency)
 Change the frequency for the specified channel. More...
 
void mixer_ch_set_vol (int ch, float lvol, float rvol)
 Set channel volume (as left/right). More...
 
void mixer_ch_set_vol_pan (int ch, float vol, float pan)
 Set channel volume (as volume and panning). More...
 
void mixer_ch_set_vol_dolby (int ch, float fl, float fr, float c, float sl, float sr)
 Set channel volume with Dolby Pro Logic II encoding. More...
 
void mixer_ch_play (int ch, waveform_t *wave)
 Start playing the specified waveform on the specified channel. More...
 
void mixer_ch_set_pos (int ch, float pos)
 Change the current playback position within a waveform. More...
 
float mixer_ch_get_pos (int ch)
 
void mixer_ch_stop (int ch)
 Stop playing samples on the specified channel.
 
bool mixer_ch_playing (int ch)
 Return true if the channel is currently playing samples.
 
void mixer_ch_set_limits (int ch, int max_bits, float max_frequency, int max_buf_sz)
 Configure the limits of a channel with respect to sample bit size, and frequency. More...
 
void mixer_add_event (int64_t delay, MixerEvent cb, void *ctx)
 Register a time-based event into the mixer. More...
 
void mixer_remove_event (MixerEvent cb, void *ctx)
 Deregister a time-based event from the mixer. More...
 
void mixer_poll (int16_t *out16, int num_samples)
 Run the mixer to produce output samples. More...
 

Variables

int64_t __mixer_profile_rsp = 0
 Count of ticks spent in mixer RSP, used for debugging purposes.
 
uint32_t __mixer_overlay_id
 RSPQ overlay ID assigned to the mixer ucode.
 

Detailed Description

RSP Audio mixer.


Data Structure Documentation

◆ mixer_channel_t

struct mixer_channel_t

Mixer channel state - CPU side.

Data Fields
mixer_fx64_t pos Current position within the waveform (in bytes)
mixer_fx64_t step Step between samples (in bytes) to playback at the correct frequency.
mixer_fx64_t len Length of the waveform (in bytes)
mixer_fx64_t loop_len Length of the loop in the waveform (in bytes)
void * ptr Pointer to the waveform.
uint32_t flags Misc flags (see CH_FLAGS_*)

◆ rsp_mixer_channel_t

struct rsp_mixer_channel_t

Mixer channel state - RSP side.

This structure represents the state of a mixer channel as stored in RSP DMEM. Structure-wise, it is similar to mixer_channel_t, but waveform-related offsets are 32-bit wide rather than 64-bit, since RSP cannot easily work with 64-bit integers. Check mixer_poll to see how this difference is handled.

Data Fields
uint32_t pos Current position within the waveform (in bytes)
uint32_t step Step between samples (in bytes) to playback at the correct frequency.
uint32_t len Length of the waveform (in bytes)
uint32_t loop_len Length of the loop in the waveform (in bytes)
void * ptr Pointer to the waveform.
uint32_t flags Misc flags (see CH_FLAGS_*)

◆ rsp_mixer_settings_t

struct rsp_mixer_settings_t

Mixer ucode settings.

This struct reflects the settings defined in rsp_mixer.S.

Data Fields
uint32_t lvol[MIXER_MAX_CHANNELS/2]
uint32_t rvol[MIXER_MAX_CHANNELS/2]
rsp_mixer_channel_t channels[MIXER_MAX_CHANNELS]

◆ channel_limit_t

struct channel_limit_t

Configured limits of a mixer channel.

This structure describes the playback limits for a mixer channel. The limits are used to avoid over-allocating memory via sample buffers.

Data Fields
int max_bits Maximum number of bits per channel.
float max_frequency Maximum frequency.
int max_buf_sz Maximum sample buffer size (bytes)

◆ mixer_event_t

struct mixer_event_t

A mixer event (synchronized with sample playback)

Data Fields
int64_t ticks Absolute time at which the event will trigger (ticks = output samples)
MixerEvent cb Callback for the event.
void * ctx Opaque context pointer to pass to the callback.

Macro Definition Documentation

◆ MIXER_POLL_PER_SECOND

#define MIXER_POLL_PER_SECOND   8

Number of expected mixer_poll calls per second.

This is used to allocate memory for the sample buffers according to the expected number of samples that must be calculated and held in memory.

Function Documentation

◆ DEFINE_RSP_UCODE()

DEFINE_RSP_UCODE ( rsp_mixer  )

RSP mixer ucode (rsp_mixer.S)

◆ mixer_init()

void mixer_init ( int  num_channels)

Initialize the mixer.

The mixer must be initialized after the audio subsystem (audio_init). The number of channels specified is the maximum number of channels used by the application. Specifying a higher number means using more memory as the mixer will allocate one sample buffer per channel, but it does not affect performance (which correlates to the actual number of simultaneously playing channels).

Parameters
[in]num_channelsNumber of channels to initialize.

◆ mixer_set_vol()

void mixer_set_vol ( float  vol)

Set master volume.

This is a global attenuation factor (range [0..1]) that will be applied to all channels and simplify implementing a global volume control.

Parameters
[in]volMaster volume (range [0..1])

◆ mixer_ch_set_freq()

void mixer_ch_set_freq ( int  ch,
float  frequency 
)

Change the frequency for the specified channel.

By default, the frequency is the one required by the waveform associated to the channel, but this function allows to override.

This function must be called after mixer_ch_play, as otherwise the frequency is reset to the default of the waveform.

Parameters
[in]chChannel index
[in]frequencyPlayback frequency (in Hz / samples per second)

◆ mixer_ch_set_vol()

void mixer_ch_set_vol ( int  ch,
float  lvol,
float  rvol 
)

Set channel volume (as left/right).

Configure channel volume for the specified channel, specifying two values: one for the left output and one for the right output.

The volume is an attenuation (no amplification is performed). Valid volume range in [0..1], where 0 is silence and 1 is original channel sample volume (no attenuation performed).

Notice that it's perfectly valid to set left/right volumes even if the channel itself will play a mono waveforms, as it allows to balance a mono sample between the two final output channels.

Parameters
[in]chChannel index
[in]lvolLeft volume (range [0..1])
[in]rvolRight volume (range [0..1])

◆ mixer_ch_set_vol_pan()

void mixer_ch_set_vol_pan ( int  ch,
float  vol,
float  pan 
)

Set channel volume (as volume and panning).

Configure the left and right channel volumes for the specified channel, Using a central volume value and a panning value to specify left/right balance.

Valid volume range in [0..1], where 0 is silence and 1 is maximum volume (no attenuation).

Valid panning range is [0..1] where 0 is 100% left, and 1 is 100% right.

Notice that panning 0.5 balance the sound but causes an attenuation of 50%.

Parameters
[in]chChannel index
[in]volCentral volume (range [0..1])
[in]panPanning (range [0..1], center is 0.5)

◆ mixer_ch_set_vol_dolby()

void mixer_ch_set_vol_dolby ( int  ch,
float  fl,
float  fr,
float  c,
float  sl,
float  sr 
)

Set channel volume with Dolby Pro Logic II encoding.

Configure the volumes of the specified channel according to the Dolby Pro Logic II matrix encoding. This allows to encode samples with a virtual surround system, that can be decoded with a Dolby 5.1 compatible equipment.

The function accepts the volumes configured for the 5 channels: front left, front right, center, surround left, surround right. These values can be calculated from a 3D scene

Parameters
[in]chChannel index
[in]flFront left volume (range [0..1])
[in]frFront right volume (range [0..1])
[in]cCentral volume (range [0..1])
[in]slSurround left volume (range [0..1])
[in]srSurround right volume (range [0..1])

◆ mixer_ch_play()

void mixer_ch_play ( int  ch,
waveform_t wave 
)

Start playing the specified waveform on the specified channel.

This function immediately begins playing the waveform, interrupting any other waveform that might have been reproduced on this channel.

Waveform settings are applied to the mixer channel; for instance, the frequency of the channel is modified to adapt to the frequency requested for correct playback of the waveform.

If the waveform is marked as stereo (channels == 2), the mixer will need two channels to play it back. "ch" will be used for the left samples, while "ch+1" will be used for the right samples. After this, it is forbidden to call mixer functions on "ch+1" until the stereo waveform is stopped.

If the same waveform (same pointer) was already being played or was the last one that was played on this channel, the channel sample buffer is retained, so that any cached samples might be reused.

Parameters
[in]chChannel index
[in]waveWaveform to playback

◆ mixer_ch_set_pos()

void mixer_ch_set_pos ( int  ch,
float  pos 
)

Change the current playback position within a waveform.

This function can be useful to seek to a specific point of the waveform. The position must be specified in number of samples (not bytes). Fractional values account for accurate resampling position.

This function must be called after mixer_ch_play, as otherwise the position is reset to the beginning of the waveform.

Parameters
[in]chChannel index
[in]posPlayback position (in number of samples)

◆ mixer_ch_get_pos()

float mixer_ch_get_pos ( int  ch)

Read the current playback position of the waveform in the channel.

The position is returned as number of samples. Fractional values account for accurate resampling position.

Parameters
[in]chChannel index
Returns
Playback position (in number of samples)

◆ mixer_ch_set_limits()

void mixer_ch_set_limits ( int  ch,
int  max_bits,
float  max_frequency,
int  max_buf_sz 
)

Configure the limits of a channel with respect to sample bit size, and frequency.

This is an advanced function that should be used with caution, only in situations in which it is paramount to control the memory usage of the mixer.

By default, each channel in the mixer is capable of doing 16-bit playback with a frequency up to the mixer output sample rate (eg: 44100hz). This means that the mixer will allocate sample buffers required for this kind of capability.

If it is known that certain channels will use only 8-bit waveforms and/or a lower frequency, it is possible to call this function to inform the mixer of these limits. This will cause the mixer to reallocate the samplebuffers lowering its memory usage (note: multiple calls to this function for different channels will of course be batched to cause only one reallocation).

Note also that this function can be used to increase the maximum frequency over the mixer sample rate, in case this is required. This works correctly but since it causes downsampling, it is generally a waste of memory bandwidth and processing power.

"max_buf_sz" can be used to limit the maximum buffer size that will be allocated for this channel (in bytes). This is a hard cap, applied on top of the optimal buffer size that will be calculated by "max_bits" and "max_frequency", and can be used in situations where there are very strong memory constraints that must be respected. Use 0 if you don't want to impose a limit.

Parameters
[in]chChannel index
[in]max_bitsMaximum number of bits per sample (or 0 to reset this to default, which is currently 16).
[in]max_frequencyMaximum playback frequency for this channel in Hz / samples per seconds (or 0 to reset this to default, which is the output sample rate as specified in audio_init).
[in]max_buf_szMaximum buffer size in bytes (or 0 to reset this default, which is calculated using the other limits, the playback output rate, and the number of audio buffers specified in audio_init).

◆ mixer_add_event()

void mixer_add_event ( int64_t  delay,
MixerEvent  cb,
void *  ctx 
)

Register a time-based event into the mixer.

Register a new event into the mixer. "delay" is the number of samples to wait before calling the event callback. "cb" is the event callback. "ctx" is an opaque pointer that will be passed to the callback when invoked.

Parameters
[in]delayNumber of samples to wait before invoking the event.
[in]cbEvent callback to invoke
[in]ctxContext opaque pointer to pass to the callback

◆ mixer_remove_event()

void mixer_remove_event ( MixerEvent  cb,
void *  ctx 
)

Deregister a time-based event from the mixer.

Deregister an event from the mixer. "cb" is the event callback, and "ctx" is the opaque context pointer. Notice that an event can also deregister itself by returning 0 when called.

Parameters
[in]cbCallback that was registered via mixer_add_event
[in]ctxOpaque pointer that was registered with the callback.

◆ mixer_poll()

void mixer_poll ( int16_t *  out,
int  nsamples 
)

Run the mixer to produce output samples.

This function will fetch the required samples from all the channels and mix them together according to each channel's settings. The output will be written into the specified buffer (out). nsamples is the number of samples that should be produced.

A common pattern would be to call audio_write_begin to obtain an audio buffer's pointer, and pass it to mixer_poll.

mixer_poll performs mixing using RSP. If RSP is busy, mixer_poll will spin-wait until the RSP is free, to perform audio processing.

Since the N64 AI can only be fed with an even number of samples, mixer_poll does not accept odd numbers.

Parameters
[in]outOutput buffer were samples will be written.
[in]nsamplesNumber of stereo samples to generate.