Playback from the Controller Speakers

Introduction
Libraries
Sample programs
Sending data for Controller speaker
Playing sound effects using AX
Playing sound effects using SP
Using SEQ to play MIDI
Controlling the Controller speaker

Introduction

This document explains how to play sounds from the speaker of the Wii Remote, which is the Standard Controller for the Wii. For the rest of this document, the speaker will be refererred to as the Controller speaker.

The RevolutionSDK AX library has been expanded with features to synthesize sounds for the Controller speaker. By using this new AX library, you can play sounds from the Controller speaker in the same way normal sounds are played.

Libraries

The following libraries are required to play sounds from the Controller speaker:

AX This library synthesizes audio data for the Controller speaker.
WENC This library encodes the PCM data output by the AX library into data for the Controller speaker.
WPAD This library controls the Controller speaker. It also sends audio data to the Controller speaker.

In addition to the above libraries, there are also AX application libraries corresponding to each type of audio data played through the Controller speaker.

Sample programs

The Revolution SDK has several sample programs that use the Controller speaker. These are listed below.

wpad_axdemo.c This sample program uses AX to play sound effects through the Controller speaker.
wpad_spdemo.c This sample program uses SP (+AX, MIX) to play sound effects through the Controller speaker.
wpad_seqdemo.c This sample program uses SEQ (+AX, MIX, SYN) to play MIDI data through the Controller speaker.

The sample programs are all located in build/demos/wpaddemo/.

Sending data for Controller speaker

The sample programs all use the same code to send audio data synthesized by AX to the Controller speaker. That code is shown below.


#define SAMPLES_PER_AUDIO_PACKET    40
#define AUDIO_PACKET_MAX_LEN        20

static void UpdateSpeaker(OSAlarm *alarm, OSContext *context)
{
#pragma unused(alarm, context)

    u8 data[24];
    u32 flag;
    s32 chan;
    BOOL adv = FALSE;

    for(chan=0; chan<WPAD_MAX_CONTROLLERS; chan++)
    {
        if (SAMPLES_PER_AUDIO_PACKET == AXRmtGetSamples(chan, AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET))
        {
            adv = TRUE;
        
            if (info[chan].Speakers.active)
            {
                flag = (info[chan].Speakers.first) ? (u32)WENC_FLAG_FIRST : (u32)WENC_FLAG_CONT;
                if (info[chan].Speakers.first)
                {
                    info[chan].Speakers.first = FALSE;
                }
                WENCGetEncodeData(&info[chan].Speakers.encInfo, flag, (const s16*)AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET, data);

                WPADSendStreamData(chan, data, AUDIO_PACKET_MAX_LEN);
            }
        }
    }

    if (adv)
    {
        AXRmtAdvancePtr(SAMPLES_PER_AUDIO_PACKET);
    }
}

The UpdateSpeaker function performs the following processes on each Controller:

  1. Using the AXRmtGetSamples function, it gets 40 samples of audio data synthesized by AX for the Controller speaker (6 KHz, 16-bit monaural PCM data) and puts it in the local AudioBuffer[].
  2. Using the WENCGetEncodeData function, it takes the data in AudioBuffer[], encodes it for use by the Controller speaker and outputs it to data[].WENCGetEncodeData compresses the 16-bit PCM data into 4 bits, so the 40 samples fetched from AX are encoded into 20 bytes.
  3. Using the WPADSendStreamData, it sends the data in data[] to the Controller speaker.

After these three functions have been processed, the pointer of the Controller speaker audio buffer managed by AX is moved 40 samples forward by the AXRmtAdvancePtr function.

The size (in bytes) of audio data sent to the Controller speaker can be specified in the argument of the WPADSendStreamData function. However, the chance of generating a transfer error increases if the size of a single transfer is reduced. The size of a single transfer should use the maximum size (=20 bytes) that can be specified using the WPADSendStreamData function.

The UpdateSpeaker function is registered to an alarm and called once every 6.6666...msec (= 40 samples/6KHz).

Playing sound effects using AX

The sample program wpad_axdemo.c uses only AX to play sound effects through the Controller speaker. It is based on the AX sample program axsimple.c(build/demos/axdemo/) and has been modified for playback through the Controller speaker.

The excerpts of code shown below are the places where changes have been made to accommodate the Controller speaker.


static AXVPB* AquireVoiceADPCM(s32 chan, void *pDSPADPCMData)
{
    DSPADPCM            *ps = (DSPADPCM*)pDSPADPCMData;
    AXPBADDR            addr;
    AXPBADPCM           adpcm;
    AXPBSRC             src;
    AXPBADPCMLOOP       adpcmLoop;
    AXVPB*              voice;
    u32                 srcBits;
    u32                 mramAddress;
    u32                 pMRAMStart;

    // Allocate a voice for use
    voice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);

         :
        Omitted
         :
    
    // Set simple volumes
    AXSetVoiceMix(voice, &g_mix);
    AXSetVoiceVe(voice, &g_ve);

    // Set controller speaker
    AXSetVoiceRmtOn(voice, AX_PB_REMOTE_ON);
    memset(&g_rmix, 0, sizeof(AXPBRMTMIX));
    switch(chan)
    {
        case WPAD_CHAN0:
            g_rmix.vMain0 = 0x8000;      // chan0 main
            g_rmix.vAux0  = 0x8000;      // chan0 aux
            break;
        case WPAD_CHAN1:
            g_rmix.vMain1 = 0x8000;      // chan1 main
            g_rmix.vAux1  = 0x8000;      // chan1 aux
            break;
        case WPAD_CHAN2:
            g_rmix.vMain2 = 0x8000;      // chan2 main
            g_rmix.vAux2  = 0x8000;      // chan2 aux
            break;
        case WPAD_CHAN3:
            g_rmix.vMain3 = 0x8000;      // chan3 main
            g_rmix.vAux3  = 0x8000;      // chan3 aux
            break;
    }   
    AXSetVoiceRmtMix(voice, &g_rmix);

    // Set sample rate
    AXSetVoiceSrcType(voice, AX_SRC_TYPE_LINEAR);
    AXSetVoiceSrc(voice, &src);

    return voice;
}

The code between AXAcquireVoice() and AXSetVoiceVe() is the same as for normal sound playback.

After the settings for normal sound playback are configured, the AX settings for Controller speaker playback are configured.

  1. The AXSetVoiceRmtOn function enables the process for synthesizing the configured voices for the Controller speaker.
  2. The AXSetVoiceRmtMix function specifies the mixing parameters of the buses for the Controller speaker. AX has two buses for each Controller speaker: a Main bus and an Aux bus. Note: The Aux bus for the Controller speaker is not yet implemented.

The above settings enable sound effects to be played from the Controller speaker.

Because wpad_axdemo.c has specifications for playing sound effects only from the Controller speaker, the mixing parameters for normal playback (AXPBMIX g_mix) all take 0. By entering an appropriate value for g_mix you can play the same sound effect from the Controller speaker and from the TV.

You do not need to be concerned with the playback frequency, 6 KHz, of the Controller speaker. Set the SRC parameters to be the same as they are for normal playback.

Playing sound effects using SP

The sample program wpad_spdemo.c uses SP to play sound effects through the Controller speaker. It is based on the SP sample program spdemo.c(build/demos/spdemo/) and has been modified for playback through the Controller speaker.

The excerpts of code shown below are the places where changes have been made to accommodate the Controller speaker.


static void PlaySfx(s32 chan)
{
    VoiceInfo *v;
    BOOL       old;

    old = OSDisableInterrupts();

    v = GetVoice();
    if (v)
    {
        v->voice = AXAcquireVoice(15, DropVoiceCallback, 0);
        if (v->voice)
        {
            v->entry = SPGetSoundEntry(SpTable, (u32)(chan + 1));
            v->chan  = chan;
            
            SPPrepareSound(v->entry, v->voice, (v->entry)->sampleRate);
            
            MIXInitChannel(v->voice, 0, 0, -960, -960, -960, 64, 127, -960);
            switch(chan)
            {
                case 0:
                    MIXRmtSetVolumes(v->voice, 0, 0, -960, -960, -960, -960, -960, -960, -960);
                    break;
                case 1:
                    MIXRmtSetVolumes(v->voice, 0, -960, 0, -960, -960, -960, -960, -960, -960);
                    break;
                case 2:
                    MIXRmtSetVolumes(v->voice, 0, -960, -960, 0, -960, -960, -960, -960, -960);
                    break;
                default:
                    MIXRmtSetVolumes(v->voice, 0, -960, -960, -960, 0, -960, -960, -960, -960);
                    break;
            }
            
            AXSetVoiceRmtOn(v->voice, AX_PB_REMOTE_ON);
            AXSetVoiceState(v->voice, AX_PB_STATE_RUN);

            info[chan].play = 1;
        }
    }
    
    OSRestoreInterrupts(old);
}

For spdemo.c/wpad_spdemo.c the mixing parameters are set with the MIX API and not the AX API.

In addition to the settings for normal sound playback, wpad_spdemo.c also has the following settings for the Controller speaker:

  1. The MIXRmtSetVolumes function specifies the mixing parameters of the buses for each Controller speaker.
  2. The AXSetVoiceRmtOn function enables the process for synthesizing the configured voices for the Controller speaker.

By using the MIXInitChannels and MIXRmtSetVolumes functions to set the appropriate mixing parameters for normal playback and for the Controller speakers you can choose from a variety of combinations of playback routes.

Playing MIDI using SEQ

The sample program wpad_seqdemo.c uses SEQ to play MIDI data through the Controller speaker. It is based on the AX sample program seqdemo.c(build/demos/axdemo/) and has been modified for playback through the Controller speaker.

The excerpts of code shown below are the places where changes have been made to accommodate the Controller speaker.


void main(void)
{
    s32          i;
    
         :
         :
    
    // Prepare Sequence for Remotes
    for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
    {
        SEQAddSequence(&info[i].Sequence,
                        MidiFileRemote,
                        Wavetable,
                        Pcm,
                        ZeroBuffer,
                        16,
                        15,
                        1
                       );
        SYNSetMasterVolume(  &info[i].Sequence.synth, -960);
        SYNSetInitCallback(  &info[i].Sequence.synth, VoiceInitCallback);
        SYNSetUpdateCallback(&info[i].Sequence.synth, VoiceUpdateCallback);
    }
    
         :
         :

}

static void VoiceInitCallback(AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel)
{
#pragma unused(midiChannel)

    s32 i;

    for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
    {
        if (synth == &info[i].Sequence.synth)
        {
            break;
        }
    }

    switch(i)
    {
        case 0:
            MIXRmtSetVolumes(axvpb, 0, 0, -960, -960, -960, -960, -960, -960, -960);
            break;
        case 1:
            MIXRmtSetVolumes(axvpb, 0, -960, 0, -960, -960, -960, -960, -960, -960);
            break;
        case 2:
            MIXRmtSetVolumes(axvpb, 0, -960, -960, 0, -960, -960, -960, -960, -960);
            break;
        default:
            MIXRmtSetVolumes(axvpb, 0, -960, -960, -960, 0, -960, -960, -960, -960);
            break;
    }
    
    AXSetVoiceRmtOn(axvpb, AX_PB_REMOTE_ON);
}

static void VoiceUpdateCallback(AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel)
{
#pragma unused(axvpb)
#pragma unused(synth)
#pragma unused(midiChannel)
}

In wpad_seqdemo.c, each Controller speaker plays MIDI data independently. For this purpose, a sequence structure is prepared for each separate Controller speaker.

In order to use the Controller speakers, the following processes are performed inside the main function for each Controller speaker.

  1. The SEQAddSequence function registers the sequence structure for each Controller speaker in the sequence list.
  2. This SYNSetMasterVolume function sets the master volume for MIDI playback. The master volume is set to -960 because wpad_seqdemo.c does not have a specification for playing on a TV the MIDI data that gets played through each Controller speakers.
  3. The SYNSetInitCallback function registers the callback function that is called during MIDI data playback when the synthesizer status is Note On.
  4. The SYNSetUpdateCallback function registers the callback function called when the synthesizer starts each audio frame during MIDI data playback.

The Note-On callback function VoiceInitCallback is called immediately after the synthesizer performs the Note-On process for normal playback. The synthesizer will pass these arguments to the callback:

axvpb The pointer to the voice allocated by the synthesizer at the time of Note-On.
synth The pointer to the synthesizer instance to which the voice belongs.
midiChannel The MIDI channel of the voice.

Using these arguments, the settings are configured for playing MIDI data through Controller speakers. The wpad_seqdemo.c callback function VoiceInitCallback performs these processes:

  1. Using the synth argument it checks which synthesizer instance for Controller speakers the voice belongs to.
  2. The MIXRmtSetVolumes function specifies the mixing parameters of the buses for each Controller speaker.
  3. The AXSetVoiceRmtOn function enables the process for synthesizing the configured voices for the Controller speaker.

The VoiceUpdateCallback function, which is the callback at the start of the audio frame, is called immediately after the synthesizer performs the normal playback process, just like the VoiceInitCallback function. The same arguments are also passed from the synthesizer.

In the wpad_seqdemo.c sample program, no processes are conducted inside the VoiceUpdateCallback function. However, you could utilize functions like MIXRmtSetFader to control output from Controller speakers during playback.

Controlling the Controller speaker

The WPADControlSpeaker function controls the Controller speaker. It can specify the following commands:


#define WPAD_SPEAKER_OFF              0
#define WPAD_SPEAKER_ON               1
#define WPAD_SPEAKER_MUTE             2
#define WPAD_SPEAKER_MUTE_OFF         3
#define WPAD_SPEAKER_PLAY             4

Each command is explained in greater detail below.

  1. SPEAKER_ON

    This command powers on and initializes the Sound Module on the Wii Remote.

    When the initialization is complete, the decoder that decompresses audio data transmitted from the Wii console is in the halted state. The PLAY command (explained below) must be used to launch the decoder and play sounds through the Controller speaker.

    Since the decoder state will be initialized, you must specify FIRST for the flag argument of the WENCGetEncodeData function the first time data is encoded after the SPEAKER_ON command is specified.

    If the SPEAKER_ON command is issued again while the Sound Module is running, the decoder state will be initialized also.

  2. SPEAKER_OFF

    This command stops the Sound Module.

  3. PLAY

    This command starts the decoder.

    If there are data in Wii Remote audio buffer, the decoder will decompress that data and plays it through the Controller speaker.

    If there are not any data in the Wii Remote audio buffer (or if the buffer has been emptied of data), the decoder will pause (i.e., stop but maintain its state). While paused, the last sample decompressed by the decoder will continue being output to the Controller speaker, and this keeps a lid on the level of noise caused by the shortage of data.

    When the Wii console transmits valid data to the audio buffer while the decoder is in the paused state, the decoder will resume its task of decompressing data.

    You may turn the Controller speaker ON and OFF using the SPEAKER_ON and SPEAKER_OFF commands. However, you can control the speaker more effectively and with better response if you retain the PLAY command and control the data transmission to the Controller speaker.


    Note:You should quickly stop data transmissions to the Controller speaker when it is no longer necessary to play sound through the Controller speaker (i.e., when there is silence).

  4. MUTE

    This command mutes the output of the Controller speaker.

    When MUTE is specified, the output from the Controller speaker is gradually throttled down.

    This command affects the amplifier of the Controller speaker, and not the operations of the decoder. The decoder will continue to consume any valid data in the audio buffer even after the Controller speaker output has been throttled down by the MUTE command. For this reason, there will be times when playback does not begin from where it left off when the MUTE_OFF command releases the mute on the Controller speaker.

  5. MUTE_OFF

    This command releases the mute on the output of the Controller speaker.

Revision History

08/10/2006 Initial version.


CONFIDENTIAL