#ifndef ULTRA64_ABI_H #define ULTRA64_ABI_H /* Audio commands: */ #define A_SPNOOP 0 #define A_ADPCM 1 #define A_CLEARBUFF 2 #define A_UNK3 3 #define A_ADDMIXER 4 #define A_RESAMPLE 5 #define A_RESAMPLE_ZOH 6 #define A_FILTER 7 #define A_SETBUFF 8 #define A_DUPLICATE 9 #define A_DMEMMOVE 10 #define A_LOADADPCM 11 #define A_MIXER 12 #define A_INTERLEAVE 13 #define A_HILOGAIN 14 #define A_SETLOOP 15 #define A_INTERL 17 #define A_ENVSETUP1 18 #define A_ENVMIXER 19 #define A_LOADBUFF 20 #define A_SAVEBUFF 21 #define A_ENVSETUP2 22 #define A_S8DEC 23 #define A_UNK19 25 #define ACMD_SIZE 32 /* * Audio flags */ #define A_INIT 0x01 #define A_CONTINUE 0x00 #define A_LOOP 0x02 #define A_OUT 0x02 #define A_LEFT 0x02 #define A_RIGHT 0x00 #define A_VOL 0x04 #define A_RATE 0x00 #define A_AUX 0x08 #define A_NOAUX 0x00 #define A_MAIN 0x00 #define A_MIX 0x10 /* * Data Structures. */ typedef struct Aadpcm { u32 cmd : 8; u32 flags : 8; u32 gain : 16; u32 addr; } Aadpcm; typedef struct Apolef { u32 cmd : 8; u32 flags : 8; u32 gain : 16; u32 addr; } Apolef; typedef struct Aenvelope { u32 cmd : 8; u32 flags : 8; u32 pad1 : 16; u32 addr; } Aenvelope; typedef struct Aclearbuff { u32 cmd : 8; u32 pad1 : 8; u32 dmem : 16; u32 pad2 : 16; u32 count : 16; } Aclearbuff; typedef struct Ainterleave { u32 cmd : 8; u32 pad1 : 8; u32 pad2 : 16; u32 inL : 16; u32 inR : 16; } Ainterleave; typedef struct Aloadbuff { u32 cmd : 8; u32 pad1 : 24; u32 addr; } Aloadbuff; typedef struct Aenvmixer { u32 cmd : 8; u32 flags : 8; u32 pad1 : 16; u32 addr; } Aenvmixer; typedef struct Amixer { u32 cmd : 8; u32 flags : 8; u32 gain : 16; u32 dmemi : 16; u32 dmemo : 16; } Amixer; typedef struct Apan { u32 cmd : 8; u32 flags : 8; u32 dmem2 : 16; u32 addr; } Apan; typedef struct Aresample { u32 cmd : 8; u32 flags : 8; u32 pitch : 16; u32 addr; } Aresample; typedef struct Areverb { u32 cmd : 8; u32 flags : 8; u32 pad1 : 16; u32 addr; } Areverb; typedef struct Asavebuff { u32 cmd : 8; u32 pad1 : 24; u32 addr; } Asavebuff; typedef struct Asegment { u32 cmd : 8; u32 pad1 : 24; u32 pad2 : 2; u32 number : 4; u32 base : 24; } Asegment; typedef struct Asetbuff { u32 cmd : 8; u32 flags : 8; u32 dmemin : 16; u32 dmemout : 16; u32 count : 16; } Asetbuff; typedef struct Asetvol { u32 cmd : 8; u32 flags : 8; u32 vol : 16; u32 voltgt : 16; u32 volrate : 16; } Asetvol; typedef struct Admemmove { u32 cmd : 8; u32 pad1 : 8; u32 dmemin : 16; u32 dmemout : 16; u32 count : 16; } Admemmove; typedef struct Aloadadpcm { u32 cmd : 8; u32 pad1 : 8; u32 count : 16; u32 addr; } Aloadadpcm; typedef struct Asetloop { u32 cmd : 8; u32 pad1 : 8; u32 pad2 : 16; u32 addr; } Asetloop; /* * Generic Acmd Packet */ typedef struct Awords { u32 w0; u32 w1; } Awords; typedef union Acmd { Awords words; Aadpcm adpcm; Apolef polef; Aclearbuff clearbuff; Aenvelope envelope; Ainterleave interleave; Aloadbuff loadbuff; Aenvmixer envmixer; Aresample resample; Areverb reverb; Asavebuff savebuff; Asegment segment; Asetbuff setbuff; Asetvol setvol; Admemmove dmemmove; Aloadadpcm loadadpcm; Amixer mixer; Asetloop setloop; long long int force_union_align; /* dummy, force alignment */ } Acmd; /* * ADPCM State */ #define ADPCMVSIZE 8 #define ADPCMFSIZE 16 typedef short ADPCM_STATE[ADPCMFSIZE]; /* * Pole filter state */ typedef short POLEF_STATE[4]; /* * Resampler state */ typedef short RESAMPLE_STATE[16]; /* * Resampler constants */ #define UNITY_PITCH 0x8000 #define MAX_RATIO 1.99996 /* within .03 cents of +1 octave */ /* * Enveloper/Mixer state */ typedef short ENVMIX_STATE[40]; /* * Macros to assemble the audio command list */ #define aADPCMdec(pkt, f, s) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_ADPCM, 24, 8) | _SHIFTL(f, 16, 8); \ _a->words.w1 = (u32)(s); \ } #define aPoleFilter(pkt, f, g, s) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_POLEF, 24, 8) | _SHIFTL(f, 16, 8) | \ _SHIFTL(g, 0, 16)); \ _a->words.w1 = (u32)(s); \ } #define aHiLoGain(pkt, gain, count, dmem, a4) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_HILOGAIN, 24, 8) | \ _SHIFTL(gain, 16, 8) | _SHIFTL(count, 0, 16)); \ _a->words.w1 = _SHIFTL(dmem, 16, 16) | _SHIFTL(a4, 0, 16); \ } #define aUnkCmd3(pkt, a1, a2, a3) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_UNK3, 24, 8) | _SHIFTL(a3, 0, 16); \ _a->words.w1 = _SHIFTL(a1, 16, 16) | _SHIFTL(a2, 0, 16); \ } #define aUnkCmd19(pkt, a1, a2, a3, a4) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_UNK19, 24, 8) | _SHIFTL(a1, 16, 8) | \ _SHIFTL(a2, 0, 16)); \ _a->words.w1 = _SHIFTL(a3, 16, 16) | _SHIFTL(a4, 0, 16); \ } #define aS8Dec(pkt, a1, a2) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_S8DEC, 24, 8) | _SHIFTL(a1, 16, 8); \ _a->words.w1 = (u32)(a2); \ } /* * Clears DMEM by writing zeros. * * @param pkt pointer to an Acmd buffer * @param dmem DMEM address to clear * @param size number of bytes to clear (rounded up to the next multiple of 16) */ #define aClearBuffer(pkt, dmem, size) \ { \ Acmd* _a = (Acmd*)pkt; \ \ _a->words.w0 = _SHIFTL(A_CLEARBUFF, 24, 8) | _SHIFTL(dmem, 0, 24); \ _a->words.w1 = (uintptr_t)(size); \ } #define aEnvMixer(pkt, dmemi, count, swapLR, x0, x1, x2, x3, m, bits) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (bits | _SHIFTL(dmemi >> 4, 16, 8) | \ _SHIFTL(count, 8, 8) | _SHIFTL(swapLR, 4, 1) | \ _SHIFTL(x0, 3, 1) | _SHIFTL(x1, 2, 1) | \ _SHIFTL(x2, 1, 1) | _SHIFTL(x3, 0, 1)); \ _a->words.w1 = (u32)(m); \ } #define aInterleave(pkt, o, l, r, c) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_INTERLEAVE, 24, 8) | \ _SHIFTL(c >> 4, 16, 8) | _SHIFTL(o, 0, 16)); \ _a->words.w1 = _SHIFTL(l, 16, 16) | _SHIFTL(r, 0, 16); \ } #define aInterl(pkt, dmemi, dmemo, count) \ { \ Acmd *_a = (Acmd*)pkt; \ \ _a->words.w0 = (_SHIFTL(A_INTERL, 24, 8) | _SHIFTL(count, 0, 16)); \ _a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \ } /* * Loads a buffer to DMEM from any physical source address, KSEG0, or KSEG1 * * @param pkt pointer to an Acmd buffer * @param addrSrc Any physical source address, KSEG0, or KSEG1 * @param dmemDest DMEM destination address * @param size number of bytes to copy (rounded down to the next multiple of 16) */ #define aLoadBuffer(pkt, addrSrc, dmemDest, size) \ { \ Acmd* _a = (Acmd*)pkt; \ \ _a->words.w0 = (_SHIFTL(A_LOADBUFF, 24, 8) | _SHIFTL((size) >> 4, 16, 8) | _SHIFTL(dmemDest, 0, 16)); \ _a->words.w1 = (uintptr_t)(addrSrc); \ } #define aMix(pkt, f, g, i, o) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_MIXER, 24, 8) | _SHIFTL(f, 16, 8) | \ _SHIFTL(g, 0, 16)); \ _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ } #define aPan(pkt, f, d, s) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_PAN, 24, 8) | _SHIFTL(f, 16, 8) | \ _SHIFTL(d, 0, 16)); \ _a->words.w1 = (u32)(s); \ } #define aResample(pkt, f, p, s) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_RESAMPLE, 24, 8) | \ _SHIFTL(f, 16, 8) | _SHIFTL(p, 0, 16)); \ _a->words.w1 = (u32)(s); \ } /* * Stores a buffer from DMEM to any physical source address, KSEG0, or KSEG1 * * @param pkt pointer to an Acmd buffer * @param dmemSrc DMEM source address * @param addrDest Any physical source address, KSEG0, or KSEG1 * @param size number of bytes to copy (rounded down to the next multiple of 16) */ #define aSaveBuffer(pkt, dmemSrc, addrDest, size) \ { \ Acmd* _a = (Acmd*)pkt; \ \ _a->words.w0 = (_SHIFTL(A_SAVEBUFF, 24, 8) | _SHIFTL((size) >> 4, 16, 8) | _SHIFTL(dmemSrc, 0, 16)); \ _a->words.w1 = (uintptr_t)(addrDest); \ } #define aSegment(pkt, s, b) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_SEGMENT, 24, 8); \ _a->words.w1 = _SHIFTL(s, 24, 8) | _SHIFTL(b, 0, 24); \ } #define aSetBuffer(pkt, f, i, o, c) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_SETBUFF, 24, 8) | _SHIFTL(f, 16, 8) | \ _SHIFTL(i, 0, 16)); \ _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ } #define aSetVolume(pkt, f, v, t, r) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_SETVOL, 24, 8) | _SHIFTL(f, 16, 16) | \ _SHIFTL(v, 0, 16)); \ _a->words.w1 = _SHIFTL(r, 0, 16) | _SHIFTL(t, 16, 16); \ } #define aSetVolume32(pkt, f, v, tr) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_SETVOL, 24, 8) | _SHIFTL(f, 16, 16) | \ _SHIFTL(v, 0, 16)); \ _a->words.w1 = (u32)(tr); \ } #define aSetLoop(pkt, a) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_SETLOOP, 24, 8); \ _a->words.w1 = (u32)(a); \ } #define aDMEMMove(pkt, i, o, c) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(i, 0, 24); \ _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ } #define aLoadADPCM(pkt, c, d) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_LOADADPCM, 24, 8) | _SHIFTL(c, 0, 24); \ _a->words.w1 = (u32)d; \ } #define aEnvSetup1(pkt, a, b, c, d) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ENVSETUP1, 24, 8) | \ _SHIFTL(a, 16, 8) | _SHIFTL(b, 0, 16)); \ _a->words.w1 = _SHIFTL(c, 16, 16) | _SHIFTL(d, 0, 16); \ } #define aEnvSetup2(pkt, volLeft, volRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8); \ _a->words.w1 = (_SHIFTL(volLeft, 16, 16) | \ _SHIFTL(volRight, 0, 16)); \ } #define aFilter(pkt, f, countOrBuf, addr) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_FILTER, 24, 8) | _SHIFTL(f, 16, 8) | \ _SHIFTL(countOrBuf, 0, 16)); \ _a->words.w1 = (u32)(addr); \ } /* * Duplicates 128 bytes of data a specified number of times. * * @param pkt pointer to an Acmd buffer * @param numCopies number of times to duplicate 128 bytes from src * @param dmemSrc DMEM source address * @param dmemDest DMEM destination address for the duplicates, size 128 * numCopies */ #define aDuplicate(pkt, numCopies, dmemSrc, dmemDest) \ { \ Acmd* _a = (Acmd*)pkt; \ \ _a->words.w0 = (_SHIFTL(A_DUPLICATE, 24, 8) | _SHIFTL(numCopies, 16, 8) | _SHIFTL(dmemSrc, 0, 16)); \ _a->words.w1 = _SHIFTL(dmemDest, 16, 16) | _SHIFTL(0x80, 0, 16); \ } #define aAddMixer(pkt, count, dmemi, dmemo, a4) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ADDMIXER, 24, 8) | \ _SHIFTL(count >> 4, 16, 8) | _SHIFTL(a4, 0, 16)); \ _a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \ } #define aResampleZoh(pkt, pitch, pitchAccu) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_RESAMPLE_ZOH, 24, 8) | \ _SHIFTL(pitch, 0, 16)); \ _a->words.w1 = _SHIFTL(pitchAccu, 0, 16); \ } #endif /* ULTRA64_ABI_H */