The following changes have been made to past audio libraries, for n_audio. Please refer to the N64 Function Reference Manual (man pages), for a complete description of the n_audio functions. All functions that the former audio library supports are supported in the n_audio library.
The n_audio library is a separate product (naudio.dev) from the N64 development environment (ultra.dev). Please be sure to install n_audio prior to using the OS.
Table 29-2 lists the functions in the n_audio library whose names are different from before.
Audio Library Functions | n_audio Library Functions |
---|---|
alInit() | n_alInit() |
alClose() | n_alClose() |
alAudioFrame() | n_alAudioFrame() |
alSeqNextEvent() | n_alSeqNextEvent() |
alSeqNewMarker() | n_alSeqNewMarker() |
alCSeqNew() | n_alCSeqNew() |
alCSeqNextEvent() | n_alCSeqNextEvent() |
alCSeqNewMarker() | n_alCSeqNewMarker() |
alSeqpNew() | n_alSeqpNew() |
alSeqpPlay() | n_alSeqpPlay() |
alSeqpStop() | n_alSeqpStop() |
alSeqpDelete() | n_alSeqpDelete() |
alSeqpLoop() | n_alSeqpLoop() |
alSeqpSendMidi() | n_alSeqpSendMidi() |
alSeqpGetSeq() | n_alSeqpGetSeq() |
alSeqpGetTempo() | n_alSeqpGetTempo() |
alSeqpGetVol() | n_alSeqpGetVol() |
alSeqpGetState() | n_alSeqpGetState() |
alSeqpSetSeq() | n_alSeqpSetSeq() |
alSeqpSetTempo() | n_alSeqpSetTempo() |
alSeqpSetVol() | n_alSeqpSetVol() |
alSeqpSetBank() | n_alSeqpSetBank() |
alSeqpGetChlVol() | n_alSeqpGetChlVol() |
alSeqpGetChlFXMix() | n_alSeqpGetChlFXMix() |
alSeqpGetChlPan() | n_alSeqpGetChlPan() |
alSeqpGetChlPriority() | n_alSeqpGetChlPriority() |
alSeqpGetChlProgram() | n_alSeqpGetChlProgram() |
alSeqpSetChlVol() | n_alSeqpSetChlVol() |
alSeqpSetChlFXMix() | n_alSeqpSetChlFXMix() |
alSeqpSetChlPan() | n_alSeqpSetChlPan() |
alSeqpSetChlPriority() | n_alSeqpSetChlPriority() |
alSeqpSetChlProgram() | n_alSeqpSetChlProgram() |
alCSPNew() | n_alCSPNew() |
alCSPPlay() | n_alCSPPlay() |
alCSPStop() | n_alCSPStop() |
alCSPDelete() | n_alCSPDelete() |
alCSPSendMidi() | n_alCSPSendMidi() |
alCSPGetSeq() | n_alCSPGetSeq() |
alCSPGetTempo() | n_alCSPGetTempo() |
alCSPGetVol() | n_alCSPGetVol() |
alCSPGetState() | n_alCSPGetState() |
alCSPSetSeq() | n_alCSPSetSeq() |
alCSPSetTempo() | n_alCSPSetTempo() |
alCSPSetVol() | n_alCSPSetVol() |
alCSPSetBank() | n_alCSPSetBank() |
alCSPGetChlVol() | n_alCSPGetChlVol() |
alCSPGetChlFXMix() | n_alCSPGetChlFXMix() |
alCSPGetChlPan() | n_alCSPGetChlPan() |
alCSPGetChlPriority() | n_alCSPGetChlPriority() |
alCSPGetChlProgram() | n_alCSPGetChlProgram() |
alCSPSetChlVol() | n_alCSPSetChlVol() |
alCSPSetChlFXMix() | n_alCSPSetChlFXMix() |
alCSPSetChlPan() | n_alCSPSetChlPan() |
alCSPSetChlPriority() | n_alCSPSetChlPriority() |
alCSPSetChlProgram() | n_alCSPSetChlProgram() |
In the table above, only the function names have changed. Function arguments and specifications remain the same as in past audio libraries.
With regard to the functions listed below, in (Table 29-3), both the function names and arguments have changed.
Audio Library Functions | n_audio Library Functions |
---|---|
alSynNew(ALSynth *, ALSynConfig *) | n_alSynNew(ALSynConfig *) |
alSynNew(ALSynth *, ALSynConfig *) | n_alSynDelete() |
alSynDelete(ALSynth *) | n_alSynAddPlayer(ALPlayer *) |
alSynAddPlayer(ALSynth *, ALPlayer *) | n_alSynRemovePlayer(ALPlayer *) |
alSynRemovePlayer(ALSynth *, ALPlayer *) | n_alSynAllocVoice(N_ALVoice *, ALVoiceConfig *) |
alSynAllocVoice(ALSynth *, ALVoice *, ALVoiceConfig *) | n_alSynFreeVoice(N_ALVoice *) |
alSynFreeVoice(ALSynth *, ALVoice *) | n_alSynAllocFX(s16, ALSynConfig *, ALHeap *) |
alSynAllocFX(ALSynth *, s16, ALSynConfig *, ALHeap *) | n_alSynFreeFX(ALFxRef *) |
alSynFreeFX(ALSynth *, ALFxRef *) | n_alSynSetVol(N_ALVoice *, s16, ALMicroTime) |
alSynSetVol(ALSynth *, ALVoice *, s16, ALMicroTime) | n_alSynSetPan(N_ALVoice *, u8) |
alSynSetPan(ALSynth *, ALVoice *, ALPan) | n_alSynSetPitch(N_ALVoice *, f32) |
alSynSetPitch(ALSynth *, ALVoice *, f32) | n_alSynSetPriority(N_ALVoice *, s16) |
alSynSetFXMix(ALSynth *, ALVoice *, u8) | n_alSynSetFXMix(N_ALVoice *, u8) |
alSynSetFXParam(ALSynth *, ALFxRef, s16, void *) | n_alSynSetFXParam(ALFxRef, s16, void *) |
alSynGetPriority(ALSynth *, ALVoice *) | n_alSynGetPriority(N_ALVoice *) |
alSynGetFXRef(ALSynth *, s16, s16) | n_alSynGetFXRef(s16, s16) |
alSynStartVoice(ALSynth *, ALVoice *, ALWaveTable *) | n_alSynStartVoice(N_ALVoice *, ALWaveTable *) |
alSynStartVoiceParams(ALSynth *, ALVoice *, ALWaveTable *, f32, s16, ALPan, u8, ALMicroTime) | n_alSynStartVoiceParams(N_ALVoice *, ALWaveTable *, f32, s16, ALPan, u8, ALMicroTime) |
alSynStopVoice(ALSynth *, ALVoice *) | n_alSynStopVoice(N_ALVoice *) |
alSndpNew(ALSndPlayer *, ALSndpConfig *) | n_alSndpNew(N_ALSndPlayer *, ALSndpConfig *) |
alSndpDelete(ALSndPlayer *) | n_alSndpDelete() |
alSndpAllocate(ALSndPlayer *, ALSound *) | n_alSndpAllocate(ALSound *) |
alSndpDeallocate(ALSndPlayer *, ALSndId) | n_alSndpDeallocate(ALSndId) |
alSndpGetState(ALSndPlayer *) | n_alSndpGetState() |
alSndpPlay(ALSndPlayer *) | n_alSndpPlay() |
alSndpPlayAt(ALSndPlayer *, ALMicroTime) | n_alSndpPlayAt(ALMicroTime) |
alSndpStop(ALSndPlayer *) | n_alSndpStop() |
alSndpSetVol(ALSndPlayer *, s16) | n_alSndpSetVol(s16) |
alSndpSetPan(ALSndPlayer *, ALPan) | n_alSndpSetPan(ALPan) |
alSndpSetPitch(ALSndPlayer *, f32) | n_alSndpSetPitch(f32) |
alSndpSetPriority(ALSndPlayer *, ALSndId, u8) | n_alSndpSetPriority(ALSndId, u8) |
alSndpSetFXMix(ALSndPlayer *, u8) | n_alSndpSetFXMix(u8) |
alSndpSetSound(ALSndPlayer *, ALSndId) | n_alSndpSetSound(ALSndId) |
alSndpGetSound(ALSndPlayer *) | n_alSndpGetSound() |
There is no functional change from the old audio library in the functions listed above.
Additional functions are listed in Table 29-4.
Function Name | Function |
---|---|
n_alSynAddSeqPlayer(ALPlayer *) | Allocate sequence player in synthesis driver |
n_alSynAddSndPlayer(ALPlayer *) | Allocate sound player |
The above functions are differentiated by the type of player that is allocated. Functionally, they are the same as alSynAddPlayer(), and n_alSynAddPlayer(). Please see the explanation for alSynAddPlayer for details.
Structures in which the names have changed are shown in Table 29-5.
Audio Library Functions | n_audio Library Functions |
---|---|
ALVoice | N_ALVoice |
ALSynth | N_ALSynth |
ALGlobals | N_ALGlobals |
ALVoiceState | N_ALVoiceState |
ALSeqPlayer | N_ALSeqPlayer |
ALCSPlayer | N_ALCSPlayer |
ALSoundState | N_ALSoundState |
ALSndPlayer | N_ALSndPlayer |
ALSndpEvent | N_ALSndpEvent |
Usually the program does not handle structure members directly. Therefore, it is necessary for the programmer to be aware of the above changes in defining the variable. When handling these structure members directly, refer to the header file in the n_audio library, n_libaudio.h.
When using the n_audio library, please include the following header files when recompiling applications that were originally created using the old audio library.
n_libaudio.h : The header file for the n_audio library n_libaudio_s_to_n.h : A macro group for converting the old audio library function to the n_audio library function
The header files above are usually installed in the "/usr/include/PR" directory.
Also, link in the following libraries:
libn_audio.a : The n_audio library n_aspMain.o : The microcode for the n_audio library
The "libn_audio.a" library will be installed in the "/usr/lib," directory, and the microcode, "n_aspMain.o" will be installed in the "/usr/lib/PR" directory.
Please refer to "Makefile" in the "playseq.naudio" sample program for the directory specification of the header file library, and the method of linking the library.
Note: If you regularly use the n_audio library, please rewrite the (former) audio library function to the n_audio library function directly; do not use the header file "n_libaudio_s_to_n.h."
To illustrate using the n_audio library, the following example shows the changes and additions needed to modify the sample program (playseq.c) so that it uses the n_audio library (playseq.naudio). The following shows places that need to be changed in the program.
################ Start of sample program ################## * * ##### Changes(1) begin ##### #include "n_libaudio.h" Include this header file for n_audio. You must include it first before including "n_libaudio_s_to_n.h." #include "n_libaudio_s_to_n.h" Include this header file for n_audio. This file contains a series of macros for converting the former audio library functions to library functions compatible with n_audio. If you regularly use the n_audio library, please rewrite each audio library function to the n_audio library function; don't include this file. #define SAMPLES 184 Set the sound processing unit to 184 samples. #define EXTRA_SAMPLES 0 If sound skipping is obvious, set this value appropriately to adjust for the number surplus audio samples. ##### Changes(1) end ##### * * * * static void gameproc(u8 *argv) { * * s16 *audioOp; u8 ##### Changes(2) begin ##### min_only_one = 1, When replay frequency is 32 KHz, 1 frame in every 10 is needed to adjust for the excess audio samples. ##### Changes(2) end ##### *ptr, *seqPtr, *midiBankPtr; OSMesgQueue seqMessageQ; * * * /* * Initialize DAC output rate */ c.outputRate = osAiSetFrequency(OUTPUT_RATE); fsize = (f32) NUM_FIELDS * c.outputRate / (f32) 60; frameSize = (s32) fsize; Get the required number of audio samples per frame if (frameSize < fsize) frameSize++; ##### Changes(3) begin ##### frameSize = ((frameSize / SAMPLES) + 1) * SAMPLES; Recalculate the required number of samples per frame, which was just found above,to be a multiple of 184. minFrameSize = frameSize - SAMPLES; frameSize is a multiple of 184 and results in more than the actual required number of samples per frame. Therefore excess sample data is generated for each frame. Set minFrameSize to adjust this number of excess samples. ##### Changes(3) end ##### /* * Audio synthesizer initialization */ c.maxVVoices = MAX_VOICES; c.maxPVoices = MAX_VOICES; * * * /* * Note that this must be a do-while in order for seqp's state * to get updated during the alAudioFrame processing. */ do { frame++; /* * Where the task list goes in DRAM */ tlistp = tlist[curBuf]; cmdlp = cmdList[curBuf]; /* * Where the audio goes in DRAM */ buf = curAudioBuf % 3; audioOp = (s16 *) osVirtualToPhysical(audioBuffer[buf]); ##### Changes(4) begin ##### if((samplesLeft > (SAMPLES + EXTRA_SAMPLES)) & min_only_one) If the number of excess samples at the time of retrace is more than 184, you make this frame the "adjustment frame" to adjust for the excess. In the adjustment frame, the number of samples equal to minFrameSize is generated. Use min_only_one to ensure that the adjustment frame is done only once. When sound break-up is severe, the number of excess samples may be zero. If that is the case, set EXTRA_SAMPLES to an appropriate value to adjust the excess sample data. Audio replay cannot be done properly if the value of EXTRA_SAMPLES is too large. The appropriate value depends on the application. { audioSamples[buf] = minFrameSize; min_only_one = 0; } else if(samplesLeft > (SAMPLES + EXTRA_SAMPLES)) Normal frames are processed here. In the case of this sample program, it is possible for the frame to appear consecutively putting in a normal frame under the conditions stated above. In that case, the value of samplesLeft becomes zero and the sound breaks up. By adding this conditional decision, this sample program prevents sound from breaking up. audioSamples[buf] = frameSize; else Normal frames are here. { audioSamples[buf] = frameSize; min_only_one = 1; } ##### Changes(4) end ##### /* * Call the frame handler */ cmdlp=n_alAudioFrame(cmdlp,&clcount,audioOp, audioSamples[buf]); /* * Build the audio task */ tlistp->t.type = M_AUDTASK; tlistp->t.flags = 0x0; tlistp->t.ucode_boot = (u64 *) rspbootTextStart; tlistp->t.ucode_boot_size = ((s32)rspbootTextEnd - (s32)rspbootTextStart); ##### Changes(5) begin ##### tlistp->t.ucode = (u64 *) n_aspMainTextStart; tlistp->t.ucode_data = (u64 *) n_aspMainDataStart; To use the N_Audio microcode, these two lines must be rewritten to n_aspMain. ##### Changes(5) end ##### tlistp->t.ucode_size = 4096; tlistp->t.ucode_data_size = SP_UCODE_DATA_SIZE; tlistp->t.data_ptr = (u64 *) cmdList[curBuf]; tlistp->t.data_size = (cmdlp - cmdList[curBuf]) * sizeof(Acmd); * * } while (seqp->state != AL_STOPPED); * * * } ################## End of sample program ##################