diff --git a/include/PR/abi.h b/include/PR/abi.h index 49d5397628..15ae5d9115 100644 --- a/include/PR/abi.h +++ b/include/PR/abi.h @@ -53,6 +53,7 @@ #define A_INIT 0x01 #define A_CONTINUE 0x00 #define A_LOOP 0x02 +#define A_ADPCM_SHORT 0x04 #define A_OUT 0x02 #define A_LEFT 0x02 #define A_RIGHT 0x00 @@ -331,13 +332,20 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (unsigned int)(a2); \ } -#define aClearBuffer(pkt, d, c) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = _SHIFTL(A_CLEARBUFF, 24, 8) | _SHIFTL(d, 0, 24); \ - _a->words.w1 = (unsigned int)(c); \ -} +/* + * 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) \ { \ @@ -368,14 +376,21 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \ } -#define aLoadBuffer(pkt, s, d, c) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = _SHIFTL(A_LOADBUFF, 24, 8) | \ - _SHIFTL((c) >> 4, 16, 8) | _SHIFTL(d, 0, 16); \ - _a->words.w1 = (unsigned int)(s); \ -} +/* + * 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) \ { \ @@ -404,14 +419,21 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (unsigned int)(s); \ } -#define aSaveBuffer(pkt, s, d, c) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = _SHIFTL(A_SAVEBUFF, 24, 8) | \ - _SHIFTL((c) >> 4, 16, 8) | _SHIFTL(s, 0, 16); \ - _a->words.w1 = (unsigned int)(d); \ -} +/* + * 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) \ { \ @@ -501,14 +523,21 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (unsigned int)(addr); \ } -#define aDuplicate(pkt, count, dmemi, dmemo, a4) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = (_SHIFTL(A_DUPLICATE, 24, 8) | \ - _SHIFTL(count, 16, 8) | _SHIFTL(dmemi, 0, 16)); \ - _a->words.w1 = _SHIFTL(dmemo, 16, 16) | _SHIFTL(a4, 0, 16); \ -} +/* + * 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) \ { \ diff --git a/include/functions.h b/include/functions.h index 9d21eca01c..d42733a145 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2897,48 +2897,7 @@ s32 osFlashWriteBuffer(OSIoMesg* mb, s32 priority, void* dramAddr, OSMesgQueue* s32 osFlashWriteArray(u32 pageNum); s32 osFlashReadArray(OSIoMesg* mb, s32 priority, u32 pageNum, void* dramAddr, u32 pageCount, OSMesgQueue* mq); -// void func_801877D0(void); -// void func_80187B64(void); -// void func_80187BEC(void); -// void func_80187DE8(void); -// void func_80187E58(void); -// void func_80187F00(void); -// void func_80187FB0(void); -// void func_80187FE8(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188034(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188078(void); -// void func_801880C4(void); -// void func_801880E8(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188124(void); -// void func_8018814C(void); -// void func_80188174(void); -// void func_801881A8(void); -// void func_801881C4(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_801881F8(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188264(void); -// void func_80188288(void); -// void func_801882A0(void); -// void func_80188304(void); -// void func_801884A0(void); -// void func_80188698(void); -// void func_8018883C(void); -// void func_801888E4(void); -// void func_801889A4(void); -// void func_80188A50(void); -// void func_80188AFC(void); -// void func_80188C48(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188CB4(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); -// void func_80188D28(void); -// void func_80188D68(void); -// void func_80188DDC(void); -// void func_80188FBC(void); -// void func_80189064(void); -// void func_80189620(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7); -// void func_8018A4B4(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6); -// void func_8018A768(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5, UNK_TYPE4 param_6); -// void func_8018A808(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5, UNK_TYPE4 param_6); -// void func_8018ACC4(void); -// void func_8018AE34(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6); +Acmd* AudioSynth_Update(Acmd* cmdStart, s32* numAbiCmds, s16* aiStart, s32 aiBufLen); void AudioHeap_DiscardFont(s32 fontId); void* AudioHeap_WritebackDCache(void* addr, size_t size); diff --git a/include/variables.h b/include/variables.h index ae97a6c51e..a4914a4413 100644 --- a/include/variables.h +++ b/include/variables.h @@ -1557,11 +1557,11 @@ extern f32 gPitchFrequencies[]; extern u8 gDefaultShortNoteVelocityTable[]; extern u8 gDefaultShortNoteGateTimeTable[]; extern EnvelopePoint gDefaultEnvelope[]; -extern NoteSubEu gZeroNoteSub; -extern NoteSubEu gDefaultNoteSub; -extern u16 gHeadsetPanQuantization[]; -extern u16 gHeadsetPanQuantization[]; -extern s16 D_801D58A8[]; +extern NoteSampleState gZeroedSampleState; +extern NoteSampleState gDefaultSampleState; +extern u16 gHaasEffectDelaySize[]; +extern u16 gHaasEffectDelaySize[]; +extern s16 gInvalidAdpcmCodeBook[]; extern f32 gHeadsetPanVolume[]; extern f32 gStereoPanVolume[]; extern f32 gDefaultPanVolume[]; @@ -1721,21 +1721,7 @@ extern s8 gSfxDefaultReverb; extern u8 gAudioSpecId; // extern UNK_TYPE1 D_801DB4D8; // extern UNK_TYPE4 D_801DB4DC; -// extern UNK_TYPE1 D_801DB4E0; -// extern UNK_TYPE1 D_801DB528; -// extern UNK_TYPE1 D_801DB570; -// extern UNK_TYPE1 D_801DB5B8; -// extern UNK_TYPE1 D_801DB600; -// extern UNK_TYPE1 D_801DB648; -// extern UNK_TYPE1 D_801DB690; -// extern UNK_TYPE1 D_801DB6D8; -// extern UNK_TYPE1 D_801DB720; -// extern UNK_TYPE1 D_801DB750; -// extern UNK_TYPE1 D_801DB798; -// extern UNK_TYPE1 D_801DB870; -// extern UNK_TYPE1 D_801DB8B8; -// extern UNK_TYPE1 D_801DB900; -extern UNK_PTR D_801DB930; +extern ReverbSettings* gReverbSettingsTable[]; extern AudioSpec gAudioSpecs[21]; // rodata @@ -3483,10 +3469,10 @@ extern ActiveSequence gActiveSeqs[]; // extern UNK_TYPE1 D_80200BCE; // extern UNK_TYPE1 D_80200BD0; extern AudioContext gAudioContext; // at 0x80200C70 -extern void (*D_80208E68)(void); -extern u32 (*D_80208E6C)(s8 value, SequenceChannel* channel); -extern s32 (*D_80208E70)(Sample*, s32, s8, s32); -extern Acmd* (*D_80208E74)(Acmd*, s32, s32); +extern void (*gCustomAudioUpdateFunction)(void); +extern u32 (*gCustomAudioSeqFunction)(s8 value, SequenceChannel* channel); +extern s32 (*gCustomAudioReverbFunction)(Sample*, s32, s8, s32); +extern Acmd* (*gCustomAudioSynthFunction)(Acmd*, s32, s32); // post-code buffers extern u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; diff --git a/include/z64audio.h b/include/z64audio.h index c5045e34ff..264e8d9e3b 100644 --- a/include/z64audio.h +++ b/include/z64audio.h @@ -1,7 +1,7 @@ #ifndef Z64_AUDIO_H #define Z64_AUDIO_H -#define MK_AUDIO_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0)) +#define AUDIO_MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0)) #define NO_LAYER ((SequenceLayer*)(-1)) @@ -32,13 +32,45 @@ typedef enum { #define ADSR_GOTO -2 #define ADSR_RESTART -3 -#define AIBUF_LEN 0x580 +// size of a single sample point +#define SAMPLE_SIZE sizeof(s16) + +// Samples are processed in groups of 16 called a "frame" +#define SAMPLES_PER_FRAME ADPCMFSIZE + +// The length of one left/right channel is 13 frames +#define DMEM_1CH_SIZE (13 * SAMPLES_PER_FRAME * SAMPLE_SIZE) +// Both left and right channels +#define DMEM_2CH_SIZE (2 * DMEM_1CH_SIZE) + +#define AIBUF_LEN (88 * SAMPLES_PER_FRAME) // number of samples +#define AIBUF_SIZE (AIBUF_LEN * SAMPLE_SIZE) // number of bytes + +// Filter sizes +#define FILTER_SIZE (8 * SAMPLE_SIZE) +#define FILTER_BUF_PART1 (8 * SAMPLE_SIZE) +#define FILTER_BUF_PART2 (8 * SAMPLE_SIZE) // Must be the same amount of samples as copied by aDuplicate() (audio microcode) #define WAVE_SAMPLE_COUNT 64 #define AUDIO_RELOCATED_ADDRESS_START K0BASE +#define REVERB_INDEX_NONE -1 + +typedef enum { + /* 0 */ REVERB_DATA_TYPE_SETTINGS, // Reverb Settings (Init) + /* 1 */ REVERB_DATA_TYPE_DELAY, // Reverb Delay (numSamples) + /* 2 */ REVERB_DATA_TYPE_DECAY, // Reverb Decay Ratio + /* 3 */ REVERB_DATA_TYPE_SUB_VOLUME, // Reverb Sub-Volume + /* 4 */ REVERB_DATA_TYPE_VOLUME, // Reverb Volume + /* 5 */ REVERB_DATA_TYPE_LEAK_RIGHT, // Reverb Leak Right Channel + /* 6 */ REVERB_DATA_TYPE_LEAK_LEFT, // Reverb Leak Left Channel + /* 7 */ REVERB_DATA_TYPE_FILTER_LEFT, // Reverb Left Filter + /* 8 */ REVERB_DATA_TYPE_FILTER_RIGHT, // Reverb Right Filter + /* 9 */ REVERB_DATA_TYPE_9 // Reverb Unk +} ReverbDataType; + typedef enum { /* 0x1 */ AUDIO_ERROR_NO_INST = 1, /* 0x3 */ AUDIO_ERROR_INVALID_INST_ID = 3, @@ -78,12 +110,14 @@ typedef enum { } SampleMedium; typedef enum { - /* 0 */ CODEC_ADPCM, - /* 1 */ CODEC_S8, + /* 0 */ CODEC_ADPCM, // 16 2-byte samples (32 bytes) compressed into 4-bit samples (8 bytes) + 1 header byte + /* 1 */ CODEC_S8, // 16 2-byte samples (32 bytes) compressed into 8-bit samples (16 bytes) /* 2 */ CODEC_S16_INMEMORY, - /* 3 */ CODEC_SMALL_ADPCM, + /* 3 */ CODEC_SMALL_ADPCM, // 16 2-byte samples (32 bytes) compressed into 2-bit samples (4 bytes) + 1 header byte /* 4 */ CODEC_REVERB, - /* 5 */ CODEC_S16 + /* 5 */ CODEC_S16, + /* 6 */ CODEC_UNK6, + /* 7 */ CODEC_UNK7 // processed as uncompressed samples } SampleCodec; typedef enum { @@ -165,24 +199,28 @@ typedef struct { typedef struct { /* 0x00 */ u32 start; - /* 0x04 */ u32 end; + /* 0x04 */ u32 loopEnd; // numSamples into the sample where the loop ends /* 0x08 */ u32 count; - /* 0x0C */ u32 unk_0C; - /* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned + /* 0x0C */ u32 sampleEnd; // total number of s16-samples in the + /* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned } AdpcmLoop; // size = 0x30 (or 0x10) +/** + * The procedure used to design the codeBook is based on an adaptive clustering algorithm. + * The size of the codeBook is (8 * order * numPredictors) and is 8-byte aligned + */ typedef struct { /* 0x00 */ s32 order; - /* 0x04 */ s32 npredictors; - /* 0x08 */ s16 book[1]; // size 8 * order * npredictors. 8-byte aligned + /* 0x04 */ s32 numPredictors; + /* 0x08 */ s16 codeBook[1]; // a table of prediction coefficients that the coder selects from to optimize sound quality. } AdpcmBook; // size >= 0x8 typedef struct { /* 0x00 */ u32 unk_0 : 1; /* 0x00 */ u32 codec : 3; // The state of compression or decompression /* 0x00 */ u32 medium : 2; // Medium where sample is currently stored - /* 0x00 */ u32 unk_bit26 : 1; // Has the sample header been relocated (offsets to pointers) - /* 0x00 */ u32 isRelocated : 1; // Size of the sample + /* 0x00 */ u32 unk_bit26 : 1; + /* 0x00 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers) /* 0x01 */ u32 size : 24; // Size of the sample /* 0x04 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either rom or ram /* 0x08 */ AdpcmLoop* loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram @@ -194,18 +232,23 @@ typedef struct { /* 0x04 */ f32 tuning; // frequency scale factor } TunedSample; // size = 0x8 +/** + * Stores an entry of decompressed samples in a reverb ring buffer. + * By storing the sample in a ring buffer, the time it takes to loop + * around back to the same sample acts as a delay, leading to an echo effect. + */ typedef struct { /* 0x00 */ s16 numSamplesAfterDownsampling; // never read - /* 0x02 */ s16 chunkLen; // never read + /* 0x02 */ s16 numSamples; // never read /* 0x04 */ s16* toDownsampleLeft; /* 0x08 */ s16* toDownsampleRight; // data pointed to by left and right are adjacent in memory /* 0x0C */ s32 startPos; // start pos in ring buffer - /* 0x10 */ s16 lengthA; // first length in ring buffer (from startPos, at most until end) - /* 0x12 */ s16 lengthB; // second length in ring buffer (from pos 0) - /* 0x14 */ u16 unk_14; - /* 0x16 */ u16 unk_16; - /* 0x18 */ u16 unk_18; -} ReverbRingBufferItem; // size = 0x1C + /* 0x10 */ s16 size; // first length in ring buffer (from startPos, at most until end) + /* 0x12 */ s16 wrappedSize; // second length in ring buffer (from pos 0) + /* 0x14 */ u16 loadResamplePitch; + /* 0x16 */ u16 saveResamplePitch; + /* 0x18 */ u16 saveResampleNumSamples; +} ReverbBufferEntry; // size = 0x1C typedef struct { /* 0x000 */ u8 resampleFlags; @@ -213,35 +256,35 @@ typedef struct { /* 0x002 */ u8 framesToIgnore; /* 0x003 */ u8 curFrame; /* 0x004 */ u8 downsampleRate; - /* 0x005 */ s8 unk_05; - /* 0x006 */ u16 windowSize; - /* 0x008 */ s16 unk_08; - /* 0x00A */ s16 unk_0A; - /* 0x00C */ u16 unk_0C; - /* 0x00E */ u16 unk_0E; + /* 0x005 */ s8 mixReverbIndex; // mix in reverb from this index. set to 0xFF to not mix any + /* 0x006 */ u16 delayNumSamples; // number of samples between echos + /* 0x008 */ s16 mixReverbStrength; // the gain/amount to mix in reverb from mixReverbIndex + /* 0x00A */ s16 volume; + /* 0x00C */ u16 decayRatio; // determines how fast reverb dissipate + /* 0x00E */ u16 downsamplePitch; /* 0x010 */ s16 leakRtl; /* 0x012 */ s16 leakLtr; - /* 0x014 */ u16 unk_14; - /* 0x016 */ s16 unk_16; - /* 0x018 */ u8 unk_18; - /* 0x019 */ s8 unk_19; - /* 0x01A */ u16 unk_1A; - /* 0x01C */ u16 unk_1C; - /* 0x01E */ u8 unk_1E; - /* 0x020 */ s32 nextRingBufPos; - /* 0x024 */ s32 unk_24; // May be bufSizePerChan - /* 0x028 */ s16* leftRingBuf; - /* 0x02C */ s16* rightRingBuf; - /* 0x030 */ void* unk_30; - /* 0x034 */ void* unk_34; - /* 0x038 */ void* unk_38; - /* 0x03C */ void* unk_3C; - /* 0x040 */ ReverbRingBufferItem items[2][5]; - /* 0x158 */ ReverbRingBufferItem items2[2][5]; + /* 0x014 */ u16 subDelay; // number of samples between sub echos + /* 0x016 */ s16 subVolume; // strength of the sub echos + /* 0x018 */ u8 resampleEffectOn; + /* 0x019 */ s8 resampleEffectExtraSamples; + /* 0x01A */ u16 resampleEffectLoadUnk; + /* 0x01C */ u16 resampleEffectSaveUnk; + /* 0x01E */ u8 delayNumSamplesAfterDownsampling; + /* 0x020 */ s32 nextReverbBufPos; + /* 0x024 */ s32 delayNumSamplesUnk; // May be bufSizePerChan + /* 0x028 */ s16* leftReverbBuf; + /* 0x02C */ s16* rightReverbBuf; + /* 0x030 */ s16* leftLoadResampleBuf; + /* 0x034 */ s16* rightLoadResampleBuf; + /* 0x038 */ s16* leftSaveResampleBuf; + /* 0x03C */ s16* rightSaveResampleBuf; + /* 0x040 */ ReverbBufferEntry bufEntry[2][5]; + /* 0x158 */ ReverbBufferEntry subBufEntry[2][5]; /* 0x270 */ s16* filterLeft; /* 0x274 */ s16* filterRight; - /* 0x278 */ s16* unk_278; - /* 0x27C */ s16* unk_27C; + /* 0x278 */ s16* filterLeftInit; + /* 0x27C */ s16* filterRightInit; /* 0x280 */ s16* filterLeftState; /* 0x284 */ s16* filterRightState; /* 0x288 */ TunedSample tunedSample; @@ -363,28 +406,26 @@ typedef struct { /* 0x1C */ EnvelopePoint* envelope; } AdsrState; // size = 0x20 -typedef struct { - /* 0x0 */ u8 unused : 2; - /* 0x0 */ u8 bit2 : 2; - /* 0x0 */ u8 strongRight : 1; - /* 0x0 */ u8 strongLeft : 1; - /* 0x0 */ u8 stereoHeadsetEffects : 1; - /* 0x0 */ u8 usesHeadsetPanEffects : 1; +typedef union { + struct { + /* 0x0 */ u8 unused : 2; + /* 0x0 */ u8 type : 2; + /* 0x0 */ u8 strongRight : 1; + /* 0x0 */ u8 strongLeft : 1; + /* 0x0 */ u8 strongReverbRight : 1; + /* 0x0 */ u8 strongReverbLeft : 1; + }; + /* 0x0 */ u8 asByte; } StereoData; // size = 0x1 -typedef union { - /* 0x0 */ StereoData s; - /* 0x0 */ u8 asByte; -} Stereo; // size = 0x1 - typedef struct { - /* 0x00 */ u8 reverb; + /* 0x00 */ u8 targetReverbVol; /* 0x01 */ u8 gain; // Increases volume by a multiplicative scaling factor. Represented as a UQ4.4 number /* 0x02 */ u8 pan; - /* 0x03 */ u8 unk_3; // Possibly part of stereo? - /* 0x04 */ Stereo stereo; - /* 0x05 */ u8 unk_4; - /* 0x06 */ u16 unk_6; + /* 0x03 */ u8 surroundEffectIndex; + /* 0x04 */ StereoData stereoData; + /* 0x05 */ u8 combFilterSize; + /* 0x06 */ u16 combFilterGain; /* 0x08 */ f32 freqScale; /* 0x0C */ f32 velocity; /* 0x10 */ s16* filter; @@ -421,7 +462,7 @@ typedef struct SequenceChannel { } changes; /* 0x02 */ u8 noteAllocPolicy; /* 0x03 */ u8 muteFlags; - /* 0x04 */ u8 reverb; // or dry/wet mix + /* 0x04 */ u8 targetReverbVol; // or dry/wet mix /* 0x05 */ u8 notePriority; // 0-3 /* 0x06 */ u8 someOtherPriority; /* 0x07 */ u8 fontId; @@ -432,12 +473,12 @@ typedef struct SequenceChannel { /* 0x0C */ u8 gain; // Increases volume by a multiplicative scaling factor. Represented as a UQ4.4 number /* 0x0D */ u8 velocityRandomVariance; /* 0x0E */ u8 gateTimeRandomVariance; - /* 0x0F */ u8 unk_0F; - /* 0x10 */ u8 unk_10; + /* 0x0F */ u8 combFilterSize; + /* 0x10 */ u8 surroundEffectIndex; /* 0x11 */ u8 unk_11; /* 0x12 */ VibratoSubStruct vibrato; /* 0x20 */ u16 delay; - /* 0x22 */ u16 unk_20; + /* 0x22 */ u16 combFilterGain; /* 0x24 */ u16 unk_22; // Used for indexing data /* 0x26 */ s16 instOrWave; // either 0 (none), instrument index + 1, or // 0x80..0x83 for sawtooth/triangle/sine/square waves. @@ -459,7 +500,7 @@ typedef struct SequenceChannel { /* 0xC8 */ s8 soundScriptIO[8]; // bridge between sound script and audio lib, "io ports" /* 0xD0 */ u8* sfxState; // SfxChannelState /* 0xD4 */ s16* filter; - /* 0xD8 */ Stereo stereo; + /* 0xD8 */ StereoData stereoData; /* 0xDC */ s32 startSamplePos; /* 0xE0 */ s32 unk_E0; } SequenceChannel; // size = 0xE4 @@ -474,15 +515,15 @@ typedef struct SequenceLayer { /* 0x00 */ u8 ignoreDrumPan : 1; /* 0x00 */ u8 bit1 : 1; // "has initialized continuous notes"? /* 0x00 */ u8 notePropertiesNeedInit : 1; - /* 0x01 */ Stereo stereo; + /* 0x01 */ StereoData stereoData; /* 0x02 */ u8 instOrWave; /* 0x03 */ u8 gateTime; /* 0x04 */ u8 semitone; /* 0x05 */ u8 portamentoTargetNote; /* 0x06 */ u8 pan; // 0..128 /* 0x07 */ u8 notePan; - /* 0x08 */ u8 unk_08; - /* 0x09 */ u8 unk_09; + /* 0x08 */ u8 surroundEffectIndex; + /* 0x09 */ u8 targetReverbVol; union { struct { /* 0x0A */ u16 bit_0 : 1; @@ -531,45 +572,37 @@ typedef struct SequenceLayer { } SequenceLayer; // size = 0x90 typedef struct { - /* 0x00 */ s16 adpcmdecState[0x10]; - /* 0x20 */ s16 finalResampleState[0x10]; - /* 0x40 */ s16 mixEnvelopeState[0x28]; - /* 0x90 */ s16 panResampleState[0x10]; - /* 0xB0 */ s16 panSamplesBuffer[0x20]; - /* 0xF0 */ s16 dummyResampleState[0x10]; -} NoteSynthesisBuffers; // size = 0x110 + /* 0x000 */ s16 adpcmState[16]; + /* 0x020 */ s16 finalResampleState[16]; + /* 0x040 */ s16 filterState[32]; + /* 0x080 */ s16 unusedState[16]; + /* 0x0A0 */ s16 haasEffectDelayState[32]; + /* 0x0E0 */ s16 combFilterState[128]; + /* 0x1E0 */ s16 surroundEffectState[128]; +} NoteSynthesisBuffers; // size = 0x2E0 typedef struct { - /* 0x00 */ u8 restart_bit0 : 1; - /* 0x00 */ u8 restart_bit1 : 1; - /* 0x00 */ u8 restart_bit2 : 1; - /* 0x00 */ u8 restart_bit3 : 1; - /* 0x00 */ u8 restart_bit4 : 1; - /* 0x00 */ u8 restart_bit5 : 1; - /* 0x00 */ u8 restart_bit6 : 1; - /* 0x00 */ u8 restart_bit7 : 1; + /* 0x00 */ u8 atLoopPoint : 1; + /* 0x00 */ u8 stopLoop : 1; /* 0x01 */ u8 sampleDmaIndex; - /* 0x02 */ u8 prevHeadsetPanRight; - /* 0x03 */ u8 prevHeadsetPanLeft; - /* 0x04 */ u8 reverbVol; + /* 0x02 */ u8 prevHaasEffectLeftDelaySize; + /* 0x03 */ u8 prevHaasEffectRightDelaySize; + /* 0x04 */ u8 curReverbVol; /* 0x05 */ u8 numParts; - /* 0x06 */ u16 samplePosFrac; - /* 0x08 */ u16 unk_08; - /* 0x0C */ s32 samplePosInt; + /* 0x06 */ u16 samplePosFrac; // Fractional part of the sample position + /* 0x08 */ u16 surroundEffectGain; + /* 0x0C */ s32 samplePosInt; // Integer part of the sample position /* 0x10 */ NoteSynthesisBuffers* synthesisBuffers; /* 0x14 */ s16 curVolLeft; /* 0x16 */ s16 curVolRight; - /* 0x18 */ u16 unk_14; - /* 0x1A */ u16 unk_16; - /* 0x1C */ u16 unk_18; - /* 0x1E */ u8 unk_1A; + /* 0x18 */ UNK_TYPE1 unk_14[0x6]; + /* 0x1E */ u8 combFilterNeedsInit; /* 0x1F */ u8 unk_1F; - /* 0x20 */ u16 unk_1C; - /* 0x22 */ u16 unk_1E; + /* 0x20 */ UNK_TYPE1 unk_20[0x4]; } NoteSynthesisState; // size = 0x24 typedef struct { - /* 0x00 */ struct VibratoSubStruct* vibSubStruct; // MM Something else? + /* 0x00 */ struct VibratoSubStruct* vibSubStruct; // Something else? /* 0x04 */ u32 time; /* 0x08 */ s16* curve; /* 0x0C */ f32 extent; @@ -603,67 +636,68 @@ typedef struct { /* 0x34 */ AdsrState adsr; /* 0x54 */ Portamento portamento; /* 0x60 */ VibratoState vibratoState; - /* 0x7C */ char unk_7C[0x8]; + /* 0x7C */ UNK_TYPE1 pad7C[0x4]; + /* 0x80 */ u8 unk_80; /* 0x84 */ u32 startSamplePos; -} NotePlaybackState; // size = 0x88 + /* 0x88 */ UNK_TYPE1 unk_BC[0x1C]; +} NotePlaybackState; // size = 0xA4 typedef struct { struct { /* 0x00 */ volatile u8 enabled : 1; /* 0x00 */ u8 needsInit : 1; - /* 0x00 */ u8 finished : 1; // ? + /* 0x00 */ u8 finished : 1; /* 0x00 */ u8 unused : 1; - /* 0x00 */ u8 stereoStrongRight : 1; - /* 0x00 */ u8 stereoStrongLeft : 1; - /* 0x00 */ u8 stereoHeadsetEffects : 1; - /* 0x00 */ u8 usesHeadsetPanEffects : 1; // ? + /* 0x00 */ u8 strongRight : 1; + /* 0x00 */ u8 strongLeft : 1; + /* 0x00 */ u8 strongReverbRight : 1; + /* 0x00 */ u8 strongReverbLeft : 1; } bitField0; struct { /* 0x01 */ u8 reverbIndex : 3; /* 0x01 */ u8 bookOffset : 2; /* 0x01 */ u8 isSyntheticWave : 1; /* 0x01 */ u8 hasTwoParts : 1; - /* 0x01 */ u8 usesHeadsetPanEffects2 : 1; + /* 0x01 */ u8 useHaasEffect : 1; } bitField1; /* 0x02 */ u8 gain; // Increases volume by a multiplicative scaling factor. Represented as a UQ4.4 number - /* 0x03 */ u8 headsetPanRight; - /* 0x04 */ u8 headsetPanLeft; - /* 0x05 */ u8 reverbVol; + /* 0x03 */ u8 haasEffectLeftDelaySize; + /* 0x04 */ u8 haasEffectRightDelaySize; + /* 0x05 */ u8 targetReverbVol; /* 0x06 */ u8 harmonicIndexCurAndPrev; // bits 3..2 store curHarmonicIndex, bits 1..0 store prevHarmonicIndex - /* 0x07 */ u8 unk_07; + /* 0x07 */ u8 combFilterSize; /* 0x08 */ u16 targetVolLeft; /* 0x0A */ u16 targetVolRight; - /* 0x0C */ u16 resamplingRateFixedPoint; - /* 0x0E */ u16 unk_0E; + /* 0x0C */ u16 frequencyFixedPoint; + /* 0x0E */ u16 combFilterGain; union { /* 0x10 */ TunedSample* tunedSample; /* 0x10 */ s16* waveSampleAddr; // used for synthetic waves }; /* 0x14 */ s16* filter; - /* 0x18 */ u8 unk_18; - /* 0x19 */ u8 unk_19; - /* 0x1A */ UNK_TYPE1 pad_1A[0x6]; -} NoteSubEu; // size = 0x20 + /* 0x18 */ UNK_TYPE1 unk_18; + /* 0x19 */ u8 surroundEffectIndex; + /* 0x1A */ UNK_TYPE1 unk_1A[0x6]; +} NoteSampleState; // size = 0x20 typedef struct Note { /* 0x00 */ AudioListItem listItem; /* 0x10 */ NoteSynthesisState synthesisState; /* 0x34 */ NotePlaybackState playbackState; - /* 0xBC */ char unk_BC[0x1C]; - /* 0xD8 */ NoteSubEu noteSubEu; + /* 0xD8 */ NoteSampleState sampleState; } Note; // size = 0xF8 typedef struct { /* 0x00 */ u8 downsampleRate; - /* 0x02 */ u16 windowSize; - /* 0x04 */ u16 unk_4; - /* 0x06 */ u16 unk_6; - /* 0x08 */ u16 unk_8; - /* 0x0A */ u16 unk_A; + /* 0x02 */ u16 delayNumSamples; + /* 0x04 */ u16 decayRatio; // determines how fast reverb dissipates + /* 0x06 */ u16 subDelay; + /* 0x08 */ u16 subVolume; + /* 0x0A */ u16 volume; /* 0x0C */ u16 leakRtl; /* 0x0E */ u16 leakLtr; - /* 0x10 */ s8 unk_10; - /* 0x12 */ u16 unk_12; + /* 0x10 */ s8 mixReverbIndex; + /* 0x12 */ u16 mixReverbStrength; /* 0x14 */ s16 lowPassFilterCutoffLeft; /* 0x16 */ s16 lowPassFilterCutoffRight; } ReverbSettings; // size = 0x18 @@ -704,13 +738,13 @@ typedef struct { /* 0x00 */ s16 specUnk4; /* 0x02 */ u16 samplingFreq; // Target sampling rate in Hz /* 0x04 */ u16 aiSamplingFreq; // True sampling rate set to the audio interface (AI) for the audio digital-analog converter (DAC) - /* 0x06 */ s16 samplesPerFrameTarget; - /* 0x08 */ s16 maxAiBufNumSamples; - /* 0x0A */ s16 minAiBufNumSamples; + /* 0x06 */ s16 numSamplesPerFrameTarget; + /* 0x08 */ s16 numSamplesPerFrameMax; + /* 0x0A */ s16 numSamplesPerFrameMin; /* 0x0C */ s16 updatesPerFrame; // for each frame of the audio thread (default 60 fps), number of updates to process audio - /* 0x0E */ s16 samplesPerUpdate; - /* 0x10 */ s16 samplesPerUpdateMax; - /* 0x12 */ s16 samplesPerUpdateMin; + /* 0x0E */ s16 numSamplesPerUpdate; + /* 0x10 */ s16 numSamplesPerUpdateMax; + /* 0x12 */ s16 numSamplesPerUpdateMin; /* 0x14 */ s16 numSequencePlayers; /* 0x18 */ f32 resampleRate; /* 0x1C */ f32 updatesPerFrameInv; // inverse (reciprocal) of updatesPerFrame @@ -899,8 +933,8 @@ typedef struct { /* 0x0002 */ u16 unk_2; // reads from audio spec unk_14, never used, always set to 0x7FFF /* 0x0004 */ u16 unk_4; /* 0x0006 */ char unk_0006[0xA]; - /* 0x0010 */ s16* curLoadedBook; - /* 0x0014 */ NoteSubEu* noteSubsEu; + /* 0x0010 */ s16* adpcmCodeBook; + /* 0x0014 */ NoteSampleState* sampleStateList; /* 0x0018 */ SynthesisReverb synthesisReverbs[4]; /* 0x0B58 */ char unk_0B58[0x30]; /* 0x0B88 */ Sample* usedSamples[128]; @@ -1002,7 +1036,7 @@ typedef struct { /* 0x4460 */ SequencePlayer seqPlayers[5]; /* 0x4B40 */ SequenceLayer sequenceLayers[80]; /* 0x7840 */ SequenceChannel sequenceChannelNone; - /* 0x7924 */ s32 noteSubEuOffset; + /* 0x7924 */ s32 sampleStateOffset; // Start of the list of sample states for this update. Resets after each audio frame. /* 0x7928 */ AudioListItem layerFreeList; /* 0x7938 */ NotePool noteFreeLists; /* 0x7978 */ u8 cmdWritePos; @@ -1023,17 +1057,17 @@ typedef struct { } AudioContext; // size = 0x81F8 typedef struct { - /* 0x00 */ u8 reverbVol; + /* 0x00 */ u8 targetReverbVol; /* 0x01 */ u8 gain; // Increases volume by a multiplicative scaling factor. Represented as a UQ4.4 number /* 0x02 */ u8 pan; - /* 0x03 */ u8 unk_3; - /* 0x04 */ Stereo stereo; + /* 0x03 */ u8 surroundEffectIndex; + /* 0x04 */ StereoData stereoData; /* 0x08 */ f32 frequency; /* 0x0C */ f32 velocity; /* 0x10 */ char unk_0C[0x4]; /* 0x14 */ s16* filter; - /* 0x18 */ u8 unk_14; - /* 0x1A */ u16 unk_16; + /* 0x18 */ u8 combFilterSize; + /* 0x1A */ u16 combFilterGain; } NoteSubAttributes; // size = 0x1A typedef struct { diff --git a/spec b/spec index 4dec1f2289..100e615cf1 100644 --- a/spec +++ b/spec @@ -608,7 +608,6 @@ beginseg pad_text include "build/src/code/audio/audio_data.o" include "build/src/code/audio/audio_synthesis.o" - include "build/data/code/audio_synthesis.data.o" include "build/src/code/audio/audio_heap.o" include "build/data/code/audio_heap.bss.o" include "build/src/code/audio/audio_load.o" diff --git a/src/code/audio/audio_data.c b/src/code/audio/audio_data.c index 7238a4bfa6..eb931262b0 100644 --- a/src/code/audio/audio_data.c +++ b/src/code/audio/audio_data.c @@ -857,22 +857,99 @@ EnvelopePoint gDefaultEnvelope[] = { { ADSR_DISABLE, 0 }, }; -NoteSubEu gZeroNoteSub = { 0 }; +NoteSampleState gZeroedSampleState = { 0 }; -NoteSubEu gDefaultNoteSub = { - { 1, 1, 0, 0, 0, 0, 0, 0 }, { 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +NoteSampleState gDefaultSampleState = { + { true, true, false, false, false, false, false, false }, + { 0 }, + 0, // gain + 0, // haasEffectLeftDelaySize + 0, // haasEffectRightDelaySize + 0, // targetReverbVol + 0, // harmonicIndexCurAndPrev + 0, // combFilterSize + 0, // targetVolLeft + 0, // targetVolRight + 0, // frequencyFixedPoint + 0, // combFilterGain + NULL, // tunedSample + NULL, // filter + 0, // unk_18 + 0, // surroundEffectIndex + 0, // unk_1A }; -u16 gHeadsetPanQuantization[64] = { - 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, - 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +u16 gHaasEffectDelaySize[64] = { + 30 * SAMPLE_SIZE, + 29 * SAMPLE_SIZE, + 28 * SAMPLE_SIZE, + 27 * SAMPLE_SIZE, + 26 * SAMPLE_SIZE, + 25 * SAMPLE_SIZE, + 24 * SAMPLE_SIZE, + 23 * SAMPLE_SIZE, + 22 * SAMPLE_SIZE, + 21 * SAMPLE_SIZE, + 20 * SAMPLE_SIZE, + 19 * SAMPLE_SIZE, + 18 * SAMPLE_SIZE, + 17 * SAMPLE_SIZE, + 16 * SAMPLE_SIZE, + 15 * SAMPLE_SIZE, + 14 * SAMPLE_SIZE, + 13 * SAMPLE_SIZE, + 12 * SAMPLE_SIZE, + 11 * SAMPLE_SIZE, + 10 * SAMPLE_SIZE, + 9 * SAMPLE_SIZE, + 8 * SAMPLE_SIZE, + 7 * SAMPLE_SIZE, + 6 * SAMPLE_SIZE, + 5 * SAMPLE_SIZE, + 4 * SAMPLE_SIZE, + 3 * SAMPLE_SIZE, + 2 * SAMPLE_SIZE, + 1 * SAMPLE_SIZE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, }; s32 D_801D58A4 = 0; // clang-format off -s16 D_801D58A8[] = { +s16 gInvalidAdpcmCodeBook[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/src/code/audio/audio_heap.c b/src/code/audio/audio_heap.c index 667cd1c400..8412220a34 100644 --- a/src/code/audio/audio_heap.c +++ b/src/code/audio/audio_heap.c @@ -10,7 +10,7 @@ void AudioHeap_DiscardSampleCaches(void); void AudioHeap_DiscardSampleBank(s32 sampleBankId); void AudioHeap_ApplySampleBankCacheInternal(s32 apply, s32 sampleBankId); void AudioHeap_DiscardSampleBanks(void); -void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 flags); +void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 isFirstInit); #define gTatumsPerBeat (gAudioTatumInit[1]) @@ -421,7 +421,7 @@ void* AudioHeap_AllocCached(s32 tableType, size_t size, s32 cache, s32 id) { if (loadStatusEntry0 == LOAD_STATUS_MAYBE_DISCARDABLE) { for (i = 0; i < gAudioContext.numNotes; i++) { if ((gAudioContext.notes[i].playbackState.fontId == temporaryCache->entries[0].id) && - gAudioContext.notes[i].noteSubEu.bitField0.enabled) { + gAudioContext.notes[i].sampleState.bitField0.enabled) { break; } } @@ -435,7 +435,7 @@ void* AudioHeap_AllocCached(s32 tableType, size_t size, s32 cache, s32 id) { if (loadStatusEntry1 == LOAD_STATUS_MAYBE_DISCARDABLE) { for (i = 0; i < gAudioContext.numNotes; i++) { if ((gAudioContext.notes[i].playbackState.fontId == temporaryCache->entries[1].id) && - gAudioContext.notes[i].noteSubEu.bitField0.enabled) { + gAudioContext.notes[i].sampleState.bitField0.enabled) { break; } } @@ -491,7 +491,7 @@ void* AudioHeap_AllocCached(s32 tableType, size_t size, s32 cache, s32 id) { if (loadStatusEntry0 == LOAD_STATUS_COMPLETE) { for (i = 0; i < gAudioContext.numNotes; i++) { if ((gAudioContext.notes[i].playbackState.fontId == temporaryCache->entries[0].id) && - gAudioContext.notes[i].noteSubEu.bitField0.enabled) { + gAudioContext.notes[i].sampleState.bitField0.enabled) { break; } } @@ -504,7 +504,7 @@ void* AudioHeap_AllocCached(s32 tableType, size_t size, s32 cache, s32 id) { if (loadStatusEntry1 == LOAD_STATUS_COMPLETE) { for (i = 0; i < gAudioContext.numNotes; i++) { if ((gAudioContext.notes[i].playbackState.fontId == temporaryCache->entries[1].id) && - gAudioContext.notes[i].noteSubEu.bitField0.enabled) { + gAudioContext.notes[i].sampleState.bitField0.enabled) { break; } } @@ -814,7 +814,7 @@ void AudioHeap_UpdateReverb(SynthesisReverb* reverb) { void AudioHeap_UpdateReverbs(void) { s32 count; - s32 i; + s32 reverbIndex; s32 j; if (gAudioContext.audioBufferParameters.specUnk4 == 2) { @@ -823,9 +823,9 @@ void AudioHeap_UpdateReverbs(void) { count = 1; } - for (i = 0; i < gAudioContext.numSynthesisReverbs; i++) { + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { for (j = 0; j < count; j++) { - AudioHeap_UpdateReverb(&gAudioContext.synthesisReverbs[i]); + AudioHeap_UpdateReverb(&gAudioContext.synthesisReverbs[reverbIndex]); } } } @@ -837,7 +837,7 @@ void AudioHeap_ClearAiBuffers(void) { s32 curAiBufferIndex = gAudioContext.curAiBufferIndex; s32 i; - gAudioContext.aiBufNumSamples[curAiBufferIndex] = gAudioContext.audioBufferParameters.minAiBufNumSamples; + gAudioContext.aiBufNumSamples[curAiBufferIndex] = gAudioContext.audioBufferParameters.numSamplesPerFrameMin; for (i = 0; i < AIBUF_LEN; i++) { gAudioContext.aiBuffers[curAiBufferIndex][i] = 0; @@ -870,7 +870,7 @@ s32 AudioHeap_ResetStep(void) { AudioHeap_UpdateReverbs(); } else { for (i = 0; i < gAudioContext.numNotes; i++) { - if (gAudioContext.notes[i].noteSubEu.bitField0.enabled && + if (gAudioContext.notes[i].sampleState.bitField0.enabled && gAudioContext.notes[i].playbackState.adsr.action.s.state != ADSR_STATE_DISABLED) { gAudioContext.notes[i].playbackState.adsr.fadeOutVel = gAudioContext.audioBufferParameters.updatesPerFrameInv; @@ -907,7 +907,7 @@ s32 AudioHeap_ResetStep(void) { AudioHeap_Init(); gAudioContext.resetStatus = 0; for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufNumSamples); i++) { - gAudioContext.aiBufNumSamples[i] = gAudioContext.audioBufferParameters.maxAiBufNumSamples; + gAudioContext.aiBufNumSamples[i] = gAudioContext.audioBufferParameters.numSamplesPerFrameMax; for (j = 0; j < AIBUF_LEN; j++) { gAudioContext.aiBuffers[i][j] = 0; } @@ -930,8 +930,8 @@ void AudioHeap_Init(void) { size_t cachePoolSize; size_t miscPoolSize; u32 intMask; + s32 reverbIndex; s32 i; - s32 j; s32 pad2; AudioSpec* spec = &gAudioSpecs[gAudioContext.audioResetSpecIdToLoad]; // Audio Specifications @@ -942,19 +942,22 @@ void AudioHeap_Init(void) { gAudioContext.audioBufferParameters.aiSamplingFreq = osAiSetFrequency(gAudioContext.audioBufferParameters.samplingFreq); - gAudioContext.audioBufferParameters.samplesPerFrameTarget = + gAudioContext.audioBufferParameters.numSamplesPerFrameTarget = ALIGN16(gAudioContext.audioBufferParameters.samplingFreq / gAudioContext.refreshRate); - gAudioContext.audioBufferParameters.minAiBufNumSamples = - gAudioContext.audioBufferParameters.samplesPerFrameTarget - 0x10; - gAudioContext.audioBufferParameters.maxAiBufNumSamples = - gAudioContext.audioBufferParameters.samplesPerFrameTarget + 0x10; + gAudioContext.audioBufferParameters.numSamplesPerFrameMin = + gAudioContext.audioBufferParameters.numSamplesPerFrameTarget - 0x10; + gAudioContext.audioBufferParameters.numSamplesPerFrameMax = + gAudioContext.audioBufferParameters.numSamplesPerFrameTarget + 0x10; gAudioContext.audioBufferParameters.updatesPerFrame = - ((gAudioContext.audioBufferParameters.samplesPerFrameTarget + 0x10) / 0xD0) + 1; - gAudioContext.audioBufferParameters.samplesPerUpdate = (gAudioContext.audioBufferParameters.samplesPerFrameTarget / - gAudioContext.audioBufferParameters.updatesPerFrame) & - ~7; - gAudioContext.audioBufferParameters.samplesPerUpdateMax = gAudioContext.audioBufferParameters.samplesPerUpdate + 8; - gAudioContext.audioBufferParameters.samplesPerUpdateMin = gAudioContext.audioBufferParameters.samplesPerUpdate - 8; + ((gAudioContext.audioBufferParameters.numSamplesPerFrameTarget + 0x10) / 0xD0) + 1; + gAudioContext.audioBufferParameters.numSamplesPerUpdate = + (gAudioContext.audioBufferParameters.numSamplesPerFrameTarget / + gAudioContext.audioBufferParameters.updatesPerFrame) & + ~7; + gAudioContext.audioBufferParameters.numSamplesPerUpdateMax = + gAudioContext.audioBufferParameters.numSamplesPerUpdate + 8; + gAudioContext.audioBufferParameters.numSamplesPerUpdateMin = + gAudioContext.audioBufferParameters.numSamplesPerUpdate - 8; gAudioContext.audioBufferParameters.resampleRate = 32000.0f / (s32)gAudioContext.audioBufferParameters.samplingFreq; gAudioContext.audioBufferParameters.updatesPerFrameInvScaled = (1.0f / 256.0f) / gAudioContext.audioBufferParameters.updatesPerFrame; @@ -984,13 +987,13 @@ void AudioHeap_Init(void) { gAudioContext.unk_2870 /= gAudioContext.tempoInternalToExternal; gAudioContext.audioBufferParameters.specUnk4 = spec->unk_04; - gAudioContext.audioBufferParameters.samplesPerFrameTarget *= gAudioContext.audioBufferParameters.specUnk4; - gAudioContext.audioBufferParameters.maxAiBufNumSamples *= gAudioContext.audioBufferParameters.specUnk4; - gAudioContext.audioBufferParameters.minAiBufNumSamples *= gAudioContext.audioBufferParameters.specUnk4; + gAudioContext.audioBufferParameters.numSamplesPerFrameTarget *= gAudioContext.audioBufferParameters.specUnk4; + gAudioContext.audioBufferParameters.numSamplesPerFrameMax *= gAudioContext.audioBufferParameters.specUnk4; + gAudioContext.audioBufferParameters.numSamplesPerFrameMin *= gAudioContext.audioBufferParameters.specUnk4; gAudioContext.audioBufferParameters.updatesPerFrame *= gAudioContext.audioBufferParameters.specUnk4; if (gAudioContext.audioBufferParameters.specUnk4 >= 2) { - gAudioContext.audioBufferParameters.maxAiBufNumSamples -= 0x10; + gAudioContext.audioBufferParameters.numSamplesPerFrameMax -= 0x10; } // Determine the maximum allowable number of audio command list entries for the rsp microcode @@ -1037,13 +1040,13 @@ void AudioHeap_Init(void) { gAudioContext.notes = AudioHeap_AllocZeroed(&gAudioContext.miscPool, gAudioContext.numNotes * sizeof(Note)); AudioPlayback_NoteInitAll(); AudioPlayback_InitNoteFreeList(); - gAudioContext.noteSubsEu = + gAudioContext.sampleStateList = AudioHeap_AllocZeroed(&gAudioContext.miscPool, gAudioContext.audioBufferParameters.updatesPerFrame * - gAudioContext.numNotes * sizeof(NoteSubEu)); + gAudioContext.numNotes * sizeof(NoteSampleState)); // Initialize audio binary interface command list buffer - for (j = 0; j < ARRAY_COUNT(gAudioContext.abiCmdBufs); j++) { - gAudioContext.abiCmdBufs[j] = + for (i = 0; i < ARRAY_COUNT(gAudioContext.abiCmdBufs); i++) { + gAudioContext.abiCmdBufs[i] = AudioHeap_AllocDmaMemoryZeroed(&gAudioContext.miscPool, gAudioContext.maxAudioCmds * sizeof(Acmd)); } @@ -1052,20 +1055,20 @@ void AudioHeap_Init(void) { AudioHeap_InitAdsrDecayTable(); // Initialize reverbs - for (i = 0; i < ARRAY_COUNT(gAudioContext.synthesisReverbs); i++) { - gAudioContext.synthesisReverbs[i].useReverb = 0; + for (reverbIndex = 0; reverbIndex < ARRAY_COUNT(gAudioContext.synthesisReverbs); reverbIndex++) { + gAudioContext.synthesisReverbs[reverbIndex].useReverb = 0; } gAudioContext.numSynthesisReverbs = spec->numReverbs; - for (i = 0; i < gAudioContext.numSynthesisReverbs; i++) { - AudioHeap_InitReverb(i, &spec->reverbSettings[i], 1); + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { + AudioHeap_InitReverb(reverbIndex, &spec->reverbSettings[reverbIndex], true); } // Initialize sequence players AudioSeq_InitSequencePlayers(); - for (j = 0; j < gAudioContext.audioBufferParameters.numSequencePlayers; j++) { - AudioSeq_InitSequencePlayerChannels(j); - AudioSeq_ResetSequencePlayer(&gAudioContext.seqPlayers[j]); + for (i = 0; i < gAudioContext.audioBufferParameters.numSequencePlayers; i++) { + AudioSeq_InitSequencePlayerChannels(i); + AudioSeq_ResetSequencePlayer(&gAudioContext.seqPlayers[i]); } // Initialize two additional caches on the audio heap to store individual audio samples @@ -1529,149 +1532,165 @@ void AudioHeap_DiscardSampleBanks(void) { } } -void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, s32 data, s32 flags) { - s32 windowSize; +void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, s32 data, s32 isFirstInit) { + s32 delayNumSamples; SynthesisReverb* reverb = &gAudioContext.synthesisReverbs[reverbIndex]; switch (dataType) { - case 0: - AudioHeap_InitReverb(reverbIndex, (ReverbSettings*)data, 0); + case REVERB_DATA_TYPE_SETTINGS: + AudioHeap_InitReverb(reverbIndex, (ReverbSettings*)data, false); break; - case 1: + + case REVERB_DATA_TYPE_DELAY: if (data < 4) { data = 4; } - windowSize = data * 64; - if (windowSize < 0x100) { - windowSize = 0x100; + delayNumSamples = data * 64; + if (delayNumSamples < (16 * SAMPLES_PER_FRAME)) { + delayNumSamples = 16 * SAMPLES_PER_FRAME; } - windowSize /= reverb->downsampleRate; + delayNumSamples /= reverb->downsampleRate; - if (flags == 0) { - if (reverb->unk_1E >= (data / reverb->downsampleRate)) { - if ((reverb->nextRingBufPos >= windowSize) || (reverb->unk_24 >= windowSize)) { - reverb->nextRingBufPos = 0; - reverb->unk_24 = 0; - } - } else { + if (!isFirstInit) { + if (reverb->delayNumSamplesAfterDownsampling < (data / reverb->downsampleRate)) { break; } + if ((reverb->nextReverbBufPos >= delayNumSamples) || (reverb->delayNumSamplesUnk >= delayNumSamples)) { + reverb->nextReverbBufPos = 0; + reverb->delayNumSamplesUnk = 0; + } } - reverb->windowSize = windowSize; + reverb->delayNumSamples = delayNumSamples; - if ((reverb->downsampleRate != 1) || reverb->unk_18) { - reverb->unk_0E = 0x8000 / reverb->downsampleRate; - if (reverb->unk_30 == NULL) { - reverb->unk_30 = AudioHeap_AllocZeroed(&gAudioContext.miscPool, 0x20); - reverb->unk_34 = AudioHeap_AllocZeroed(&gAudioContext.miscPool, 0x20); - reverb->unk_38 = AudioHeap_AllocZeroed(&gAudioContext.miscPool, 0x20); - reverb->unk_3C = AudioHeap_AllocZeroed(&gAudioContext.miscPool, 0x20); - if (reverb->unk_3C == NULL) { + if ((reverb->downsampleRate != 1) || reverb->resampleEffectOn) { + reverb->downsamplePitch = 0x8000 / reverb->downsampleRate; + if (reverb->leftLoadResampleBuf == NULL) { + reverb->leftLoadResampleBuf = + AudioHeap_AllocZeroed(&gAudioContext.miscPool, sizeof(RESAMPLE_STATE)); + reverb->rightLoadResampleBuf = + AudioHeap_AllocZeroed(&gAudioContext.miscPool, sizeof(RESAMPLE_STATE)); + reverb->leftSaveResampleBuf = + AudioHeap_AllocZeroed(&gAudioContext.miscPool, sizeof(RESAMPLE_STATE)); + reverb->rightSaveResampleBuf = + AudioHeap_AllocZeroed(&gAudioContext.miscPool, sizeof(RESAMPLE_STATE)); + if (reverb->rightSaveResampleBuf == NULL) { reverb->downsampleRate = 1; } } } break; - case 2: - gAudioContext.synthesisReverbs[reverbIndex].unk_0C = data; + + case REVERB_DATA_TYPE_DECAY: + gAudioContext.synthesisReverbs[reverbIndex].decayRatio = data; break; - case 3: - gAudioContext.synthesisReverbs[reverbIndex].unk_16 = data; + + case REVERB_DATA_TYPE_SUB_VOLUME: + gAudioContext.synthesisReverbs[reverbIndex].subVolume = data; break; - case 4: - gAudioContext.synthesisReverbs[reverbIndex].unk_0A = data; + + case REVERB_DATA_TYPE_VOLUME: + gAudioContext.synthesisReverbs[reverbIndex].volume = data; break; - case 5: + + case REVERB_DATA_TYPE_LEAK_RIGHT: gAudioContext.synthesisReverbs[reverbIndex].leakRtl = data; break; - case 6: + + case REVERB_DATA_TYPE_LEAK_LEFT: gAudioContext.synthesisReverbs[reverbIndex].leakLtr = data; break; - case 7: + + case REVERB_DATA_TYPE_FILTER_LEFT: if (data != 0) { - if ((flags != 0) || (reverb->unk_278 == 0)) { - reverb->filterLeftState = AudioHeap_AllocDmaMemoryZeroed(&gAudioContext.miscPool, 0x40); - reverb->unk_278 = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, 0x10); + if (isFirstInit || (reverb->filterLeftInit == NULL)) { + reverb->filterLeftState = AudioHeap_AllocDmaMemoryZeroed(&gAudioContext.miscPool, + 2 * (FILTER_BUF_PART1 + FILTER_BUF_PART2)); + reverb->filterLeftInit = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, FILTER_SIZE); } - reverb->filterLeft = reverb->unk_278; - if (reverb->filterLeft != 0) { + reverb->filterLeft = reverb->filterLeftInit; + if (reverb->filterLeft != NULL) { AudioHeap_LoadLowPassFilter(reverb->filterLeft, data); } } else { - reverb->filterLeft = 0; + reverb->filterLeft = NULL; - if (flags != 0) { - reverb->unk_278 = 0; + if (isFirstInit) { + reverb->filterLeftInit = NULL; } } - break; - case 8: + + case REVERB_DATA_TYPE_FILTER_RIGHT: if (data != 0) { - if ((flags != 0) || (reverb->unk_27C == 0)) { - reverb->filterRightState = AudioHeap_AllocDmaMemoryZeroed(&gAudioContext.miscPool, 0x40); - reverb->unk_27C = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, 0x10); + if (isFirstInit || (reverb->filterRightInit == NULL)) { + reverb->filterRightState = AudioHeap_AllocDmaMemoryZeroed( + &gAudioContext.miscPool, 2 * (FILTER_BUF_PART1 + FILTER_BUF_PART2)); + reverb->filterRightInit = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, FILTER_SIZE); } - reverb->filterRight = reverb->unk_27C; - if (reverb->unk_27C != 0) { - AudioHeap_LoadLowPassFilter(reverb->unk_27C, data); + reverb->filterRight = reverb->filterRightInit; + if (reverb->filterRight != NULL) { + AudioHeap_LoadLowPassFilter(reverb->filterRight, data); } } else { - reverb->filterRight = 0; - if (flags != 0) { - reverb->unk_27C = 0; + reverb->filterRight = NULL; + if (isFirstInit) { + reverb->filterRightInit = NULL; } } break; - case 9: - reverb->unk_19 = data; + + case REVERB_DATA_TYPE_9: + reverb->resampleEffectExtraSamples = data; if (data == 0) { - reverb->unk_18 = false; + reverb->resampleEffectOn = false; } else { - reverb->unk_18 = true; + reverb->resampleEffectOn = true; } break; + default: break; } } -void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 flags) { +void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 isFirstInit) { SynthesisReverb* reverb = &gAudioContext.synthesisReverbs[reverbIndex]; - if (flags != 0) { - reverb->unk_1E = settings->windowSize / settings->downsampleRate; - reverb->unk_30 = 0; - } else if (reverb->unk_1E < (settings->windowSize / settings->downsampleRate)) { + if (isFirstInit) { + reverb->delayNumSamplesAfterDownsampling = settings->delayNumSamples / settings->downsampleRate; + reverb->leftLoadResampleBuf = NULL; + } else if (reverb->delayNumSamplesAfterDownsampling < (settings->delayNumSamples / settings->downsampleRate)) { return; } reverb->downsampleRate = settings->downsampleRate; - reverb->unk_18 = false; - reverb->unk_19 = 0; - reverb->unk_1A = 0; - reverb->unk_1C = 0; - AudioHeap_SetReverbData(reverbIndex, 1, settings->windowSize, flags); - reverb->unk_0C = settings->unk_4; - reverb->unk_0A = settings->unk_A; - reverb->unk_14 = settings->unk_6 << 6; - reverb->unk_16 = settings->unk_8; + reverb->resampleEffectOn = false; + reverb->resampleEffectExtraSamples = 0; + reverb->resampleEffectLoadUnk = 0; + reverb->resampleEffectSaveUnk = 0; + AudioHeap_SetReverbData(reverbIndex, REVERB_DATA_TYPE_DELAY, settings->delayNumSamples, isFirstInit); + reverb->decayRatio = settings->decayRatio; + reverb->volume = settings->volume; + reverb->subDelay = settings->subDelay * 64; + reverb->subVolume = settings->subVolume; reverb->leakRtl = settings->leakRtl; reverb->leakLtr = settings->leakLtr; - reverb->unk_05 = settings->unk_10; - reverb->unk_08 = settings->unk_12; - reverb->useReverb = 8; + reverb->mixReverbIndex = settings->mixReverbIndex; + reverb->mixReverbStrength = settings->mixReverbStrength; + reverb->useReverb = 8; // used as a boolean - if (flags != 0) { - reverb->leftRingBuf = AudioHeap_AllocZeroedAttemptExternal(&gAudioContext.miscPool, reverb->windowSize * 2); - reverb->rightRingBuf = AudioHeap_AllocZeroedAttemptExternal(&gAudioContext.miscPool, reverb->windowSize * 2); + if (isFirstInit) { + reverb->leftReverbBuf = + AudioHeap_AllocZeroedAttemptExternal(&gAudioContext.miscPool, reverb->delayNumSamples * 2); + reverb->rightReverbBuf = + AudioHeap_AllocZeroedAttemptExternal(&gAudioContext.miscPool, reverb->delayNumSamples * 2); reverb->resampleFlags = 1; - reverb->nextRingBufPos = 0; - reverb->unk_24 = 0; + reverb->nextReverbBufPos = 0; + reverb->delayNumSamplesUnk = 0; reverb->curFrame = 0; reverb->framesToIgnore = 2; } @@ -1681,12 +1700,13 @@ void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 flags) reverb->tunedSample.tuning = 1.0f; reverb->sample.codec = CODEC_REVERB; reverb->sample.medium = MEDIUM_RAM; - reverb->sample.size = reverb->windowSize * 2; - reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf; + reverb->sample.size = reverb->delayNumSamples * SAMPLE_SIZE; + reverb->sample.sampleAddr = (u8*)reverb->leftReverbBuf; reverb->loop.start = 0; reverb->loop.count = 1; - reverb->loop.end = reverb->windowSize; + reverb->loop.loopEnd = reverb->delayNumSamples; - AudioHeap_SetReverbData(reverbIndex, 7, settings->lowPassFilterCutoffLeft, flags); - AudioHeap_SetReverbData(reverbIndex, 8, settings->lowPassFilterCutoffRight, flags); + AudioHeap_SetReverbData(reverbIndex, REVERB_DATA_TYPE_FILTER_LEFT, settings->lowPassFilterCutoffLeft, isFirstInit); + AudioHeap_SetReverbData(reverbIndex, REVERB_DATA_TYPE_FILTER_RIGHT, settings->lowPassFilterCutoffRight, + isFirstInit); } diff --git a/src/code/audio/audio_init_params.c b/src/code/audio/audio_init_params.c index 81c49b30ca..59c6658ac3 100644 --- a/src/code/audio/audio_init_params.c +++ b/src/code/audio/audio_init_params.c @@ -1,12 +1,184 @@ #include "global.h" const s16 gAudioTatumInit[] = { - 0x1C00, // unused - 0x30, // gTatumsPerBeat + 0x1C00, // unused + TATUMS_PER_BEAT, // gTatumsPerBeat }; +// TODO: Extract from table? +#define NUM_SOUNDFONTS 41 +#define SFX_SEQ_SIZE 0xC6A0 +#define AMBIENCE_SEQ_SIZE 0xFC0 +#define SOUNDFONT_0_SIZE 0x81C0 +#define SOUNDFONT_1_SIZE 0x36D0 +#define SOUNDFONT_2_SIZE 0xCE0 + +// Sizes of everything on the init pool +#define AI_BUFFERS_SIZE (AIBUF_SIZE * ARRAY_COUNT(gAudioContext.aiBuffers)) +#define SOUNDFONT_LIST_SIZE (NUM_SOUNDFONTS * sizeof(SoundFont)) + +// 0x19BD0 +#define PERMANENT_POOL_SIZE \ + (SFX_SEQ_SIZE + AMBIENCE_SEQ_SIZE + SOUNDFONT_0_SIZE + SOUNDFONT_1_SIZE + SOUNDFONT_2_SIZE + 0x430) + const AudioHeapInitSizes gAudioHeapInitSizes = { - 0x137F00, // heapSize - 0x1C480, // initPoolSize - 0x1A000, // permanentPoolSize + ALIGN16(sizeof(gAudioHeap) - 0x100), // audio heap size + ALIGN16(PERMANENT_POOL_SIZE + AI_BUFFERS_SIZE + SOUNDFONT_LIST_SIZE + 0x40), // init pool size + ALIGN16(PERMANENT_POOL_SIZE), // permanent pool size +}; + +#define REVERB_INDEX_0_SETTINGS \ + { 1, 0x30, 0x3000, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x3000, 0, 0 } + +ReverbSettings reverbSettings0[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x20, 0x0800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 0, 0 }, +}; + +ReverbSettings reverbSettings1[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x1800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 11, 11 }, +}; + +ReverbSettings reverbSettings2[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x38, 0x2800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 7, 7 }, +}; + +ReverbSettings reverbSettings3[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x6800, 0, 0, 0x7FFF, 0x1400, 0x1400, REVERB_INDEX_NONE, 0x3000, 6, 6 }, + { 2, 0x50, 0x6000, 0, 0, 0x7FFF, 0xD000, 0x3000, REVERB_INDEX_NONE, 0x3000, 0, 0 }, +}; + +ReverbSettings reverbSettings4[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x40, 0x5000, 0, 0, 0x7FFF, 0x1800, 0x1800, REVERB_INDEX_NONE, 0x3000, 7, 7 }, +}; + +ReverbSettings reverbSettings5[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x40, 0x5C00, 0, 0, 0x7FFF, 0x2000, 0x2000, REVERB_INDEX_NONE, 0x3000, 4, 4 }, +}; + +ReverbSettings reverbSettings6[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x6000, 0, 0, 0x7FFF, 0x1000, 0x1000, REVERB_INDEX_NONE, 0x3000, 10, 10 }, +}; + +ReverbSettings reverbSettings7[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x6800, 0, 0, 0x7FFF, 0x1400, 0x1400, REVERB_INDEX_NONE, 0x3000, 6, 6 }, +}; + +ReverbSettings reverbSettings8[2] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x50, 0x5000, 0, 0, 0x7FFF, 0xD000, 0x3000, REVERB_INDEX_NONE, 0x3000, 0, 0 }, +}; + +ReverbSettings reverbSettings9[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x20, 0x0000, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 0, 0 }, +}; + +ReverbSettings reverbSettingsA[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x1800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 11, 11 }, +}; + +ReverbSettings reverbSettingsB[3] = { + REVERB_INDEX_0_SETTINGS, +}; + +ReverbSettings reverbSettingsC[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x40, 0x5000, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x3000, 0, 0 }, +}; + +ReverbSettings reverbSettingsD[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x6800, 0, 0, 0x7FFF, 0x1400, 0x1400, REVERB_INDEX_NONE, 0x3000, 6, 6 }, + { 2, 0x50, 0x6000, 0, 0, 0x7FFF, 0xD000, 0x3000, REVERB_INDEX_NONE, 0x3000, 0, 0 }, +}; + +ReverbSettings reverbSettingsE[3] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x30, 0x1800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 11, 11 }, + { 1, 0x40, 0x5000, 0, 0, 0x7FFF, 0x1800, 0x1800, REVERB_INDEX_NONE, 0x3000, 7, 7 }, +}; + +ReverbSettings reverbSettingsF[2] = { + REVERB_INDEX_0_SETTINGS, + { 1, 0x50, 0x1800, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x0000, 11, 11 }, +}; + +ReverbSettings* gReverbSettingsTable[] = { + reverbSettings0, reverbSettings1, reverbSettings2, reverbSettings4, reverbSettings5, + reverbSettings6, reverbSettings7, reverbSettings8, reverbSettings9, reverbSettings3, +}; + +AudioSpec gAudioSpecs[21] = { + /* 0x0 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x1 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x2 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x3 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x4 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x5 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x6 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x7 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x8 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x9 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0xA */ + { 32000, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x2800, 0x2D00, 0, 0, + 0xDC800 }, + /* 0xB */ + { 32000, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0xC */ + { 32000, 1, 28, 5, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xCC800 }, + /* 0xD */ + { 32000, 1, 24, 5, 0, 0, 3, reverbSettingsD, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0xE */ + { 32000, 1, 24, 5, 0, 0, 3, reverbSettingsE, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0xF */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4000, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x10 */ + { 32000, 1, 22, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x11 */ + { 32000, 1, 22, 5, 0, 0, 2, reverbSettings8, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x12 */ + { 32000, 1, 16, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x13 */ + { 22050, 1, 24, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0, + 0xDC800 }, + /* 0x14 */ + { 32000, 1, 24, 5, 0, 0, 2, reverbSettings2, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x3600, 0x2600, 0, 0, + 0xDC800 }, }; diff --git a/src/code/audio/audio_load.c b/src/code/audio/audio_load.c index c8e5ac5d1b..ccdc7488d5 100644 --- a/src/code/audio/audio_load.c +++ b/src/code/audio/audio_load.c @@ -1218,9 +1218,9 @@ void AudioLoad_Init(void* heap, size_t heapSize) { s32 i; s32 j; - D_80208E68 = NULL; - D_80208E70 = NULL; - D_80208E74 = NULL; + gCustomAudioUpdateFunction = NULL; + gCustomAudioReverbFunction = NULL; + gCustomAudioSynthFunction = NULL; for (i = 0; i < ARRAY_COUNT(gAudioContext.unk_29A8); i++) { gAudioContext.unk_29A8[i] = NULL; diff --git a/src/code/audio/audio_playback.c b/src/code/audio/audio_playback.c index e1a42b1eda..a7cc9a5880 100644 --- a/src/code/audio/audio_playback.c +++ b/src/code/audio/audio_playback.c @@ -1,10 +1,10 @@ #include "global.h" -void AudioPlayback_NoteSetResamplingRate(NoteSubEu* noteSubEu, f32 resamplingRateInput); +void AudioPlayback_NoteSetResamplingRate(NoteSampleState* sampleState, f32 resamplingRateInput); void AudioPlayback_AudioListPushFront(AudioListItem* list, AudioListItem* item); void AudioPlayback_NoteInitForLayer(Note* note, SequenceLayer* layer); -void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* noteSubEu, NoteSubAttributes* subAttrs) { +void AudioPlayback_InitSampleState(Note* note, NoteSampleState* sampleState, NoteSubAttributes* subAttrs) { f32 volLeft; f32 volRight; s32 halfPanIndex; @@ -13,45 +13,45 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* noteSubEu, NoteSubAttribut u8 strongRight; f32 vel; u8 pan; - u8 reverbVol; + u8 targetReverbVol; StereoData stereoData; s32 stereoHeadsetEffects = note->playbackState.stereoHeadsetEffects; vel = subAttrs->velocity; pan = subAttrs->pan; - reverbVol = subAttrs->reverbVol; - stereoData = subAttrs->stereo.s; + targetReverbVol = subAttrs->targetReverbVol; + stereoData = subAttrs->stereoData; - noteSubEu->bitField0 = note->noteSubEu.bitField0; - noteSubEu->bitField1 = note->noteSubEu.bitField1; - noteSubEu->waveSampleAddr = note->noteSubEu.waveSampleAddr; - noteSubEu->harmonicIndexCurAndPrev = note->noteSubEu.harmonicIndexCurAndPrev; + sampleState->bitField0 = note->sampleState.bitField0; + sampleState->bitField1 = note->sampleState.bitField1; + sampleState->waveSampleAddr = note->sampleState.waveSampleAddr; + sampleState->harmonicIndexCurAndPrev = note->sampleState.harmonicIndexCurAndPrev; - AudioPlayback_NoteSetResamplingRate(noteSubEu, subAttrs->frequency); + AudioPlayback_NoteSetResamplingRate(sampleState, subAttrs->frequency); pan &= 0x7F; - noteSubEu->bitField0.stereoStrongRight = false; - noteSubEu->bitField0.stereoStrongLeft = false; - noteSubEu->bitField0.stereoHeadsetEffects = stereoData.stereoHeadsetEffects; - noteSubEu->bitField0.usesHeadsetPanEffects = stereoData.usesHeadsetPanEffects; + sampleState->bitField0.strongRight = false; + sampleState->bitField0.strongLeft = false; + sampleState->bitField0.strongReverbRight = stereoData.strongReverbRight; + sampleState->bitField0.strongReverbLeft = stereoData.strongReverbLeft; if (stereoHeadsetEffects && (gAudioContext.soundMode == SOUNDMODE_HEADSET)) { halfPanIndex = pan >> 1; if (halfPanIndex > 0x3F) { halfPanIndex = 0x3F; } - noteSubEu->headsetPanLeft = gHeadsetPanQuantization[halfPanIndex]; - noteSubEu->headsetPanRight = gHeadsetPanQuantization[0x3F - halfPanIndex]; - noteSubEu->bitField1.usesHeadsetPanEffects2 = true; + sampleState->haasEffectRightDelaySize = gHaasEffectDelaySize[halfPanIndex]; + sampleState->haasEffectLeftDelaySize = gHaasEffectDelaySize[0x3F - halfPanIndex]; + sampleState->bitField1.useHaasEffect = true; volLeft = gHeadsetPanVolume[pan]; volRight = gHeadsetPanVolume[0x7F - pan]; } else if (stereoHeadsetEffects && (gAudioContext.soundMode == SOUNDMODE_STEREO)) { strongLeft = strongRight = false; - noteSubEu->headsetPanRight = 0; - noteSubEu->headsetPanLeft = 0; - noteSubEu->bitField1.usesHeadsetPanEffects2 = false; + sampleState->haasEffectLeftDelaySize = 0; + sampleState->haasEffectRightDelaySize = 0; + sampleState->bitField1.useHaasEffect = false; volLeft = gStereoPanVolume[pan]; volRight = gStereoPanVolume[0x7F - pan]; @@ -62,37 +62,37 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* noteSubEu, NoteSubAttribut } // case 0: - noteSubEu->bitField0.stereoStrongRight = strongRight; - noteSubEu->bitField0.stereoStrongLeft = strongLeft; + sampleState->bitField0.strongRight = strongRight; + sampleState->bitField0.strongLeft = strongLeft; - switch (stereoData.bit2) { + switch (stereoData.type) { case 0: break; case 1: - noteSubEu->bitField0.stereoStrongRight = stereoData.strongRight; - noteSubEu->bitField0.stereoStrongLeft = stereoData.strongLeft; + sampleState->bitField0.strongRight = stereoData.strongRight; + sampleState->bitField0.strongLeft = stereoData.strongLeft; break; case 2: - noteSubEu->bitField0.stereoStrongRight = stereoData.strongRight | strongRight; - noteSubEu->bitField0.stereoStrongLeft = stereoData.strongLeft | strongLeft; + sampleState->bitField0.strongRight = stereoData.strongRight | strongRight; + sampleState->bitField0.strongLeft = stereoData.strongLeft | strongLeft; break; case 3: - noteSubEu->bitField0.stereoStrongRight = stereoData.strongRight ^ strongRight; - noteSubEu->bitField0.stereoStrongLeft = stereoData.strongLeft ^ strongLeft; + sampleState->bitField0.strongRight = stereoData.strongRight ^ strongRight; + sampleState->bitField0.strongLeft = stereoData.strongLeft ^ strongLeft; break; } } else if (gAudioContext.soundMode == SOUNDMODE_MONO) { - noteSubEu->bitField0.stereoHeadsetEffects = false; - noteSubEu->bitField0.usesHeadsetPanEffects = false; + sampleState->bitField0.strongReverbRight = false; + sampleState->bitField0.strongReverbLeft = false; volLeft = 0.707f; // approx 1/sqrt(2) volRight = 0.707f; } else { - noteSubEu->bitField0.stereoStrongRight = stereoData.strongRight; - noteSubEu->bitField0.stereoStrongLeft = stereoData.strongLeft; + sampleState->bitField0.strongRight = stereoData.strongRight; + sampleState->bitField0.strongLeft = stereoData.strongLeft; volLeft = gDefaultPanVolume[pan]; volRight = gDefaultPanVolume[0x7F - pan]; } @@ -100,33 +100,33 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* noteSubEu, NoteSubAttribut vel = 0.0f > vel ? 0.0f : vel; vel = 1.0f < vel ? 1.0f : vel; - noteSubEu->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f)); - noteSubEu->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f)); + sampleState->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f)); + sampleState->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f)); - noteSubEu->gain = subAttrs->gain; - noteSubEu->filter = subAttrs->filter; - noteSubEu->unk_07 = subAttrs->unk_14; - noteSubEu->unk_0E = subAttrs->unk_16; - noteSubEu->reverbVol = reverbVol; - noteSubEu->unk_19 = subAttrs->unk_3; + sampleState->gain = subAttrs->gain; + sampleState->filter = subAttrs->filter; + sampleState->combFilterSize = subAttrs->combFilterSize; + sampleState->combFilterGain = subAttrs->combFilterGain; + sampleState->targetReverbVol = targetReverbVol; + sampleState->surroundEffectIndex = subAttrs->surroundEffectIndex; } -void AudioPlayback_NoteSetResamplingRate(NoteSubEu* noteSubEu, f32 resamplingRateInput) { +void AudioPlayback_NoteSetResamplingRate(NoteSampleState* sampleState, f32 resamplingRateInput) { f32 resamplingRate = 0.0f; if (resamplingRateInput < 2.0f) { - noteSubEu->bitField1.hasTwoParts = false; + sampleState->bitField1.hasTwoParts = false; resamplingRate = CLAMP_MAX(resamplingRateInput, 1.99998f); } else { - noteSubEu->bitField1.hasTwoParts = true; + sampleState->bitField1.hasTwoParts = true; if (resamplingRateInput > 3.99996f) { resamplingRate = 1.99998f; } else { resamplingRate = resamplingRateInput * 0.5f; } } - noteSubEu->resamplingRateFixedPoint = (s32)(resamplingRate * 32768.0f); + sampleState->frequencyFixedPoint = (s32)(resamplingRate * 32768.0f); } void AudioPlayback_NoteInit(Note* note) { @@ -140,17 +140,17 @@ void AudioPlayback_NoteInit(Note* note) { note->playbackState.status = PLAYBACK_STATUS_0; note->playbackState.adsr.action.s.state = ADSR_STATE_INITIAL; - note->noteSubEu = gDefaultNoteSub; + note->sampleState = gDefaultSampleState; } void AudioPlayback_NoteDisable(Note* note) { - if (note->noteSubEu.bitField0.needsInit == true) { - note->noteSubEu.bitField0.needsInit = false; + if (note->sampleState.bitField0.needsInit == true) { + note->sampleState.bitField0.needsInit = false; } note->playbackState.priority = 0; - note->noteSubEu.bitField0.enabled = false; + note->sampleState.bitField0.enabled = false; note->playbackState.status = PLAYBACK_STATUS_0; - note->noteSubEu.bitField0.finished = false; + note->sampleState.bitField0.finished = false; note->playbackState.parentLayer = NO_LAYER; note->playbackState.prevParentLayer = NO_LAYER; note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED; @@ -161,8 +161,8 @@ void AudioPlayback_ProcessNotes(void) { s32 pad; s32 playbackStatus; NoteAttributes* attrs; - NoteSubEu* noteSubEu2; - NoteSubEu* noteSubEu; + NoteSampleState* sampleState; + NoteSampleState* noteSampleState; Note* note; NotePlaybackState* playbackState; NoteSubAttributes subAttrs; @@ -172,7 +172,7 @@ void AudioPlayback_ProcessNotes(void) { for (i = 0; i < gAudioContext.numNotes; i++) { note = &gAudioContext.notes[i]; - noteSubEu2 = &gAudioContext.noteSubsEu[gAudioContext.noteSubEuOffset + i]; + sampleState = &gAudioContext.sampleStateList[gAudioContext.sampleStateOffset + i]; playbackState = ¬e->playbackState; if (playbackState->parentLayer != NO_LAYER) { if ((u32)playbackState->parentLayer < 0x7FFFFFFF) { @@ -211,10 +211,12 @@ void AudioPlayback_ProcessNotes(void) { out: if (playbackState->priority != 0) { + //! FAKE: if (1) {} - noteSubEu = ¬e->noteSubEu; - if ((playbackState->status >= 1) || noteSubEu->bitField0.finished) { - if ((playbackState->adsr.action.s.state == ADSR_STATE_DISABLED) || noteSubEu->bitField0.finished) { + noteSampleState = ¬e->sampleState; + if ((playbackState->status >= 1) || noteSampleState->bitField0.finished) { + if ((playbackState->adsr.action.s.state == ADSR_STATE_DISABLED) || + noteSampleState->bitField0.finished) { if (playbackState->wantedParentLayer != NO_LAYER) { AudioPlayback_NoteDisable(note); if (playbackState->wantedParentLayer->channel != NULL) { @@ -260,14 +262,14 @@ void AudioPlayback_ProcessNotes(void) { subAttrs.frequency = attrs->freqScale; subAttrs.velocity = attrs->velocity; subAttrs.pan = attrs->pan; - subAttrs.reverbVol = attrs->reverb; - subAttrs.stereo = attrs->stereo; + subAttrs.targetReverbVol = attrs->targetReverbVol; + subAttrs.stereoData = attrs->stereoData; subAttrs.gain = attrs->gain; subAttrs.filter = attrs->filter; - subAttrs.unk_14 = attrs->unk_4; - subAttrs.unk_16 = attrs->unk_6; - subAttrs.unk_3 = attrs->unk_3; - bookOffset = noteSubEu->bitField1.bookOffset; + subAttrs.combFilterSize = attrs->combFilterSize; + subAttrs.combFilterGain = attrs->combFilterGain; + subAttrs.surroundEffectIndex = attrs->surroundEffectIndex; + bookOffset = noteSampleState->bitField1.bookOffset; } else { SequenceLayer* layer = playbackState->parentLayer; SequenceChannel* channel = playbackState->parentLayer->channel; @@ -276,34 +278,35 @@ void AudioPlayback_ProcessNotes(void) { subAttrs.velocity = layer->noteVelocity; subAttrs.pan = layer->notePan; - if (layer->unk_08 == 0x80) { - subAttrs.unk_3 = channel->unk_10; + if (layer->surroundEffectIndex == 0x80) { + subAttrs.surroundEffectIndex = channel->surroundEffectIndex; } else { - subAttrs.unk_3 = layer->unk_08; + subAttrs.surroundEffectIndex = layer->surroundEffectIndex; } - if (layer->stereo.s.bit2 == 0) { - subAttrs.stereo = channel->stereo; + if (layer->stereoData.type == 0) { + subAttrs.stereoData = channel->stereoData; } else { - subAttrs.stereo = layer->stereo; + subAttrs.stereoData = layer->stereoData; } if (layer->unk_0A.s.bit_2 == 1) { - subAttrs.reverbVol = channel->reverb; + subAttrs.targetReverbVol = channel->targetReverbVol; } else { - subAttrs.reverbVol = layer->unk_09; + subAttrs.targetReverbVol = layer->targetReverbVol; } if (layer->unk_0A.s.bit_9 == 1) { subAttrs.gain = channel->gain; } else { subAttrs.gain = 0; + //! FAKE: if (1) {} } subAttrs.filter = channel->filter; - subAttrs.unk_14 = channel->unk_0F; - subAttrs.unk_16 = channel->unk_20; + subAttrs.combFilterSize = channel->combFilterSize; + subAttrs.combFilterGain = channel->combFilterGain; bookOffset = channel->bookOffset & 0x7; if (channel->seqPlayer->muted && (channel->muteFlags & MUTE_FLAGS_3)) { @@ -315,8 +318,8 @@ void AudioPlayback_ProcessNotes(void) { subAttrs.frequency *= playbackState->vibratoFreqScale * playbackState->portamentoFreqScale; subAttrs.frequency *= gAudioContext.audioBufferParameters.resampleRate; subAttrs.velocity *= scale; - AudioPlayback_InitNoteSub(note, noteSubEu2, &subAttrs); - noteSubEu->bitField1.bookOffset = bookOffset; + AudioPlayback_InitSampleState(note, sampleState, &subAttrs); + noteSampleState->bitField1.bookOffset = bookOffset; skip:; } } @@ -500,15 +503,15 @@ void AudioPlayback_SeqLayerDecayRelease(SequenceLayer* layer, s32 target) { channel = layer->channel; if (layer->unk_0A.s.bit_2 == 1) { - attrs->reverb = channel->reverb; + attrs->targetReverbVol = channel->targetReverbVol; } else { - attrs->reverb = layer->unk_09; + attrs->targetReverbVol = layer->targetReverbVol; } - if (layer->unk_08 == 0x80) { - attrs->unk_3 = channel->unk_10; + if (layer->surroundEffectIndex == 0x80) { + attrs->surroundEffectIndex = channel->surroundEffectIndex; } else { - attrs->unk_3 = layer->unk_08; + attrs->surroundEffectIndex = layer->surroundEffectIndex; } if (layer->unk_0A.s.bit_9 == 1) { @@ -526,20 +529,20 @@ void AudioPlayback_SeqLayerDecayRelease(SequenceLayer* layer, s32 target) { attrs->filter = attrs->filterBuf; } - attrs->unk_6 = channel->unk_20; - attrs->unk_4 = channel->unk_0F; + attrs->combFilterGain = channel->combFilterGain; + attrs->combFilterSize = channel->combFilterSize; if (channel->seqPlayer->muted && (channel->muteFlags & MUTE_FLAGS_3)) { - note->noteSubEu.bitField0.finished = true; + note->sampleState.bitField0.finished = true; } - if (layer->stereo.asByte == 0) { - attrs->stereo = channel->stereo; + if (layer->stereoData.asByte == 0) { + attrs->stereoData = channel->stereoData; } else { - attrs->stereo = layer->stereo; + attrs->stereoData = layer->stereoData; } note->playbackState.priority = channel->someOtherPriority; } else { - attrs->stereo = layer->stereo; + attrs->stereoData = layer->stereoData; note->playbackState.priority = 1; } @@ -620,7 +623,7 @@ s32 AudioPlayback_BuildSyntheticWave(Note* note, SequenceLayer* layer, s32 waveI // Save the pointer to the synthethic wave // waveId index starts at 128, there are WAVE_SAMPLE_COUNT samples to read from - note->noteSubEu.waveSampleAddr = &gWaveSamples[waveId - 128][harmonicIndex * WAVE_SAMPLE_COUNT]; + note->sampleState.waveSampleAddr = &gWaveSamples[waveId - 128][harmonicIndex * WAVE_SAMPLE_COUNT]; return harmonicIndex; } @@ -638,7 +641,7 @@ void AudioPlayback_InitSyntheticWave(Note* note, SequenceLayer* layer) { curHarmonicIndex = AudioPlayback_BuildSyntheticWave(note, layer, waveId); if (curHarmonicIndex != prevHarmonicIndex) { - note->noteSubEu.harmonicIndexCurAndPrev = (curHarmonicIndex << 2) + prevHarmonicIndex; + note->sampleState.harmonicIndexCurAndPrev = (curHarmonicIndex << 2) + prevHarmonicIndex; } } @@ -808,7 +811,7 @@ void AudioPlayback_NoteInitForLayer(Note* note, SequenceLayer* layer) { s16 instId; SequenceChannel* channel = layer->channel; NotePlaybackState* playbackState = ¬e->playbackState; - NoteSubEu* noteSubEu = ¬e->noteSubEu; + NoteSampleState* noteSampleState = ¬e->sampleState; playbackState->prevParentLayer = NO_LAYER; playbackState->parentLayer = layer; @@ -825,28 +828,28 @@ void AudioPlayback_NoteInitForLayer(Note* note, SequenceLayer* layer) { if (instId == 0xFF) { instId = channel->instOrWave; } - noteSubEu->tunedSample = layer->tunedSample; + noteSampleState->tunedSample = layer->tunedSample; if (instId >= 0x80 && instId < 0xC0) { - noteSubEu->bitField1.isSyntheticWave = true; + noteSampleState->bitField1.isSyntheticWave = true; } else { - noteSubEu->bitField1.isSyntheticWave = false; + noteSampleState->bitField1.isSyntheticWave = false; } - if (noteSubEu->bitField1.isSyntheticWave) { + if (noteSampleState->bitField1.isSyntheticWave) { AudioPlayback_BuildSyntheticWave(note, layer, instId); } else if (channel->startSamplePos == 1) { - playbackState->startSamplePos = noteSubEu->tunedSample->sample->loop->start; + playbackState->startSamplePos = noteSampleState->tunedSample->sample->loop->start; } else { playbackState->startSamplePos = channel->startSamplePos; - if (playbackState->startSamplePos >= noteSubEu->tunedSample->sample->loop->end) { + if (playbackState->startSamplePos >= noteSampleState->tunedSample->sample->loop->loopEnd) { playbackState->startSamplePos = 0; } } playbackState->fontId = channel->fontId; playbackState->stereoHeadsetEffects = channel->stereoHeadsetEffects; - noteSubEu->bitField1.reverbIndex = channel->reverbIndex & 3; + noteSampleState->bitField1.reverbIndex = channel->reverbIndex & 3; } void func_801963E8(Note* note, SequenceLayer* layer) { @@ -987,7 +990,7 @@ void AudioPlayback_NoteInitAll(void) { for (i = 0; i < gAudioContext.numNotes; i++) { note = &gAudioContext.notes[i]; - note->noteSubEu = gZeroNoteSub; + note->sampleState = gZeroedSampleState; note->playbackState.priority = 0; note->playbackState.status = PLAYBACK_STATUS_0; note->playbackState.parentLayer = NO_LAYER; @@ -1002,7 +1005,8 @@ void AudioPlayback_NoteInitAll(void) { note->playbackState.portamento.speed = 0; note->playbackState.stereoHeadsetEffects = false; note->playbackState.startSamplePos = 0; - note->synthesisState.synthesisBuffers = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, 0x2E0); - note->playbackState.attributes.filterBuf = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, 0x10); + note->synthesisState.synthesisBuffers = + AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, sizeof(NoteSynthesisBuffers)); + note->playbackState.attributes.filterBuf = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, FILTER_SIZE); } } diff --git a/src/code/audio/audio_seqplayer.c b/src/code/audio/audio_seqplayer.c index a8573e33d2..bc5115f8f6 100644 --- a/src/code/audio/audio_seqplayer.c +++ b/src/code/audio/audio_seqplayer.c @@ -282,17 +282,17 @@ void AudioSeq_InitSequenceChannel(SequenceChannel* channel) { channel->transposition = 0; channel->largeNotes = false; channel->bookOffset = 0; - channel->stereo.asByte = 0; + channel->stereoData.asByte = 0; channel->changes.asByte = 0xFF; channel->scriptState.depth = 0; channel->newPan = 0x40; channel->panChannelWeight = 0x80; - channel->unk_10 = 0xFF; + channel->surroundEffectIndex = 0xFF; channel->velocityRandomVariance = 0; channel->gateTimeRandomVariance = 0; channel->noteUnused = NULL; channel->reverbIndex = 0; - channel->reverb = 0; + channel->targetReverbVol = 0; channel->gain = 0; channel->notePriority = 3; channel->someOtherPriority = 1; @@ -308,8 +308,8 @@ void AudioSeq_InitSequenceChannel(SequenceChannel* channel) { channel->vibrato.vibratoExtentChangeDelay = 0; channel->vibrato.vibratoDelay = 0; channel->filter = NULL; - channel->unk_20 = 0; - channel->unk_0F = 0; + channel->combFilterGain = 0; + channel->combFilterSize = 0; channel->volume = 1.0f; channel->volumeScale = 1.0f; channel->freqScale = 1.0f; @@ -345,7 +345,7 @@ s32 AudioSeq_SeqChannelSetLayer(SequenceChannel* channel, s32 layerIndex) { layer->channel = channel; layer->adsr = channel->adsr; layer->adsr.decayIndex = 0; - layer->unk_09 = channel->reverb; + layer->targetReverbVol = channel->targetReverbVol; layer->enabled = true; layer->finished = false; layer->stopSomething = false; @@ -355,8 +355,8 @@ s32 AudioSeq_SeqChannelSetLayer(SequenceChannel* channel, s32 layerIndex) { layer->bit1 = false; layer->notePropertiesNeedInit = false; layer->gateTime = 0x80; - layer->unk_08 = 0x80; - layer->stereo.asByte = 0; + layer->surroundEffectIndex = 0x80; + layer->stereoData.asByte = 0; layer->portamento.mode = PORTAMENTO_MODE_OFF; layer->scriptState.depth = 0; layer->pan = 0x40; @@ -782,7 +782,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep2(SequenceLayer* layer) { break; case 0xCD: // layer: stereo effects - layer->stereo.asByte = AudioSeq_ScriptReadU8(state); + layer->stereoData.asByte = AudioSeq_ScriptReadU8(state); break; case 0xCE: // layer: bend pitch @@ -796,7 +796,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep2(SequenceLayer* layer) { break; case 0xF1: // layer: - layer->unk_08 = AudioSeq_ScriptReadU8(state); + layer->surroundEffectIndex = AudioSeq_ScriptReadU8(state); break; default: @@ -991,13 +991,14 @@ s32 AudioSeq_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd) { if (layer->delay == 0) { if (layer->tunedSample != NULL) { - time = layer->tunedSample->sample->loop->end; + time = layer->tunedSample->sample->loop->loopEnd; } else { time = 0.0f; } time *= seqPlayer->tempo; time *= gAudioContext.unk_2870; time /= layer->freqScale; + //! FAKE: if (1) {} if (time > 0x7FFE) { time = 0x7FFE; @@ -1416,9 +1417,9 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { channel->vibrato.vibratoDelay = cmd * 16; break; - case 0xD4: // channel: set reverb + case 0xD4: // channel: set reverb volume cmd = (u8)cmdArgs[0]; - channel->reverb = cmd; + channel->targetReverbVol = cmd; break; case 0xC6: // channel: set soundFont @@ -1491,7 +1492,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { } else { channel->stereoHeadsetEffects = false; } - channel->stereo.asByte = cmd & 0x7F; + channel->stereoData.asByte = cmd & 0x7F; break; case 0xD1: // channel: set note allocation policy @@ -1537,7 +1538,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { data += 4; channel->newPan = data[-3]; channel->panChannelWeight = data[-2]; - channel->reverb = data[-1]; + channel->targetReverbVol = data[-1]; channel->reverbIndex = data[0]; //! @bug: Not marking reverb state as changed channel->changes.s.pan = true; @@ -1551,7 +1552,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { channel->transposition = (s8)AudioSeq_ScriptReadU8(scriptState); channel->newPan = AudioSeq_ScriptReadU8(scriptState); channel->panChannelWeight = AudioSeq_ScriptReadU8(scriptState); - channel->reverb = AudioSeq_ScriptReadU8(scriptState); + channel->targetReverbVol = AudioSeq_ScriptReadU8(scriptState); channel->reverbIndex = AudioSeq_ScriptReadU8(scriptState); //! @bug: Not marking reverb state as changed channel->changes.s.pan = true; @@ -1569,8 +1570,8 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { channel->adsr.sustain = 0; channel->velocityRandomVariance = 0; channel->gateTimeRandomVariance = 0; - channel->unk_0F = 0; - channel->unk_20 = 0; + channel->combFilterSize = 0; + channel->combFilterGain = 0; channel->bookOffset = 0; channel->startSamplePos = 0; channel->unk_E0 = 0; @@ -1651,8 +1652,8 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { break; case 0xBB: // channel: - channel->unk_0F = cmdArgs[0]; - channel->unk_20 = cmdArgs[1]; + channel->combFilterSize = cmdArgs[0]; + channel->combFilterGain = cmdArgs[1]; break; case 0xBC: // channel: add large @@ -1667,8 +1668,8 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { if (cmdArgs[0] < 5) { if (1) {} if (gAudioContext.unk_29A8[cmdArgs[0]] != NULL) { - D_80208E6C = gAudioContext.unk_29A8[cmdArgs[0]]; - scriptState->value = D_80208E6C(scriptState->value, channel); + gCustomAudioSeqFunction = gAudioContext.unk_29A8[cmdArgs[0]]; + scriptState->value = gCustomAudioSeqFunction(scriptState->value, channel); } } break; @@ -1693,7 +1694,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { break; case 0xA4: // channel: - channel->unk_10 = cmdArgs[0]; + channel->surroundEffectIndex = cmdArgs[0]; break; case 0xA5: // channel: @@ -2197,7 +2198,7 @@ void AudioSeq_ProcessSequences(s32 arg0) { SequencePlayer* seqPlayer; u32 i; - gAudioContext.noteSubEuOffset = + gAudioContext.sampleStateOffset = (gAudioContext.audioBufferParameters.updatesPerFrame - arg0 - 1) * gAudioContext.numNotes; for (i = 0; i < (u32)gAudioContext.audioBufferParameters.numSequencePlayers; i++) { diff --git a/src/code/audio/audio_synthesis.c b/src/code/audio/audio_synthesis.c index 51842a33f7..17b3ff4bea 100644 --- a/src/code/audio/audio_synthesis.c +++ b/src/code/audio/audio_synthesis.c @@ -1,137 +1,1698 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801877D0.s") +// DMEM Addresses for the RSP +#define DMEM_TEMP 0x3B0 +#define DMEM_TEMP2 0x3C0 +#define DMEM_SURROUND_TEMP 0x4B0 +#define DMEM_UNCOMPRESSED_NOTE 0x570 +#define DMEM_HAAS_TEMP 0x5B0 +#define DMEM_COMB_TEMP 0x750 // = DMEM_TEMP + DMEM_2CH_SIZE + a bit more +#define DMEM_COMPRESSED_ADPCM_DATA 0x930 // = DMEM_LEFT_CH +#define DMEM_LEFT_CH 0x930 +#define DMEM_RIGHT_CH 0xAD0 +#define DMEM_WET_TEMP 0x3D0 +#define DMEM_WET_SCRATCH 0x710 // = DMEM_WET_TEMP + DMEM_2CH_SIZE +#define DMEM_WET_LEFT_CH 0xC70 +#define DMEM_WET_RIGHT_CH 0xE10 // = DMEM_WET_LEFT_CH + DMEM_1CH_SIZE + +typedef enum { + /* 0 */ HAAS_EFFECT_DELAY_NONE, + /* 1 */ HAAS_EFFECT_DELAY_LEFT, // Delay left channel so that right channel is heard first + /* 2 */ HAAS_EFFECT_DELAY_RIGHT // Delay right channel so that left channel is heard first +} HaasEffectDelaySide; + +Acmd* AudioSynth_SaveResampledReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 arg2, uintptr_t arg3); +Acmd* AudioSynth_LoadReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb); +Acmd* AudioSynth_SaveReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb); +Acmd* AudioSynth_ProcessSamples(s16* aiBuf, s32 numSamplesPerUpdate, Acmd* cmd, s32 updateIndex); +Acmd* AudioSynth_ProcessSample(s32 noteIndex, NoteSampleState* sampleState, NoteSynthesisState* synthState, s16* aiBuf, + s32 numSamplesPerUpdate, Acmd* cmd, s32 updateIndex); +Acmd* AudioSynth_ApplySurroundEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, s32 size, + s32 dmem, s32 flags); +Acmd* AudioSynth_FinalResample(Acmd* cmd, NoteSynthesisState* synthState, s32 size, u16 pitch, u16 inpDmem, + s32 resampleFlags); +Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, + s32 numSamplesPerUpdate, u16 dmemSrc, s32 haasEffectDelaySide, s32 flags); +Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, + s32 numSamplesToLoad); +Acmd* AudioSynth_ApplyHaasEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, s32 size, + s32 flags, s32 haasEffectDelaySide); + +s32 D_801D5FB0 = 0; + +u32 sEnvMixerOp = _SHIFTL(A_ENVMIXER, 24, 8); + +// Store the left dry channel in a temp space to be delayed to produce the haas effect +u32 sEnvMixerLeftHaasDmemDests = + AUDIO_MK_CMD(DMEM_HAAS_TEMP >> 4, DMEM_RIGHT_CH >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4); + +// Store the right dry channel in a temp space to be delayed to produce the haas effect +u32 sEnvMixerRightHaasDmemDests = + AUDIO_MK_CMD(DMEM_LEFT_CH >> 4, DMEM_HAAS_TEMP >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4); + +u32 sEnvMixerDefaultDmemDests = + AUDIO_MK_CMD(DMEM_LEFT_CH >> 4, DMEM_RIGHT_CH >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4); + +// Unused Data +u16 D_801D5FC4[] = { + 0x7FFF, 0xD001, 0x3FFF, 0xF001, 0x5FFF, 0x9001, 0x7FFF, 0x8001, +}; + +u8 sNumSamplesPerWavePeriod[] = { + WAVE_SAMPLE_COUNT / 1, // 1st harmonic + WAVE_SAMPLE_COUNT / 2, // 2nd harmonic + WAVE_SAMPLE_COUNT / 4, // 4th harmonic + WAVE_SAMPLE_COUNT / 8, // 8th harmonic +}; + +/** + * Add a collection of s16-samples as a single entry to the reverb buffer + */ +void AudioSynth_AddReverbBufferEntry(s32 numSamples, s32 updateIndex, s32 reverbIndex) { + SynthesisReverb* reverb; + ReverbBufferEntry* entry; + s32 extraSamples; + s32 numSamplesAfterDownsampling; + s32 reverbBufPos; + s32 temp_t2; + s32 temp_t4; + s32 count1; + s32 count2; + s32 nextReverbSubBufPos; + + reverb = &gAudioContext.synthesisReverbs[reverbIndex]; + entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + + numSamplesAfterDownsampling = numSamples / gAudioContext.synthesisReverbs[reverbIndex].downsampleRate; + + // Apply resampling effect + if (gAudioContext.synthesisReverbs[reverbIndex].resampleEffectOn) { + if (reverb->downsampleRate == 1) { + count1 = 0; + count2 = 0; + + numSamplesAfterDownsampling += reverb->resampleEffectExtraSamples; + + entry->saveResampleNumSamples = numSamplesAfterDownsampling; + entry->loadResamplePitch = ((u16)numSamplesAfterDownsampling << 0xF) / numSamples; + entry->saveResamplePitch = (numSamples << 0xF) / (u16)numSamplesAfterDownsampling; + + while (true) { + temp_t2 = (entry->loadResamplePitch * numSamples * 2) + reverb->resampleEffectLoadUnk; + temp_t4 = temp_t2 >> 0x10; + + if ((temp_t4 != numSamplesAfterDownsampling) && (count1 == 0)) { + entry->loadResamplePitch = + ((numSamplesAfterDownsampling << 0x10) - reverb->resampleEffectLoadUnk) / (numSamples * 2); + count1++; + } else { + count1++; + if (temp_t4 > numSamplesAfterDownsampling) { + entry->loadResamplePitch--; + } else if (temp_t4 < numSamplesAfterDownsampling) { + entry->loadResamplePitch++; + } else { + break; + } + } + } + + reverb->resampleEffectLoadUnk = temp_t2 & 0xFFFF; + + while (true) { + temp_t2 = (entry->saveResamplePitch * numSamplesAfterDownsampling * 2) + reverb->resampleEffectSaveUnk; + temp_t4 = temp_t2 >> 0x10; + + if ((temp_t4 != numSamples) && (count2 == 0)) { + entry->saveResamplePitch = + ((numSamples << 0x10) - reverb->resampleEffectSaveUnk) / (numSamplesAfterDownsampling * 2); + count2++; + } else { + count2++; + if (temp_t4 > numSamples) { + entry->saveResamplePitch--; + } else if (temp_t4 < numSamples) { + entry->saveResamplePitch++; + } else { + break; + } + } + } + + reverb->resampleEffectSaveUnk = temp_t2 & 0xFFFF; + } + } + + extraSamples = (reverb->nextReverbBufPos + numSamplesAfterDownsampling) - reverb->delayNumSamples; + reverbBufPos = reverb->nextReverbBufPos; + + // Add a reverb entry + if (extraSamples < 0) { + entry->size = numSamplesAfterDownsampling * SAMPLE_SIZE; + entry->wrappedSize = 0; + entry->startPos = reverb->nextReverbBufPos; + reverb->nextReverbBufPos += numSamplesAfterDownsampling; + } else { + // End of the buffer is reached. Loop back around + entry->size = (numSamplesAfterDownsampling - extraSamples) * SAMPLE_SIZE; + entry->wrappedSize = extraSamples * SAMPLE_SIZE; + entry->startPos = reverb->nextReverbBufPos; + reverb->nextReverbBufPos = extraSamples; + } + + entry->numSamplesAfterDownsampling = numSamplesAfterDownsampling; + entry->numSamples = numSamples; + + // Add a sub-reverb entry + if (reverb->subDelay != 0) { + nextReverbSubBufPos = reverb->subDelay + reverbBufPos; + if (nextReverbSubBufPos >= reverb->delayNumSamples) { + nextReverbSubBufPos -= reverb->delayNumSamples; + } + + entry = &reverb->subBufEntry[reverb->curFrame][updateIndex]; + numSamplesAfterDownsampling = numSamples / reverb->downsampleRate; + extraSamples = (nextReverbSubBufPos + numSamplesAfterDownsampling) - reverb->delayNumSamples; + + if (extraSamples < 0) { + entry->size = numSamplesAfterDownsampling * SAMPLE_SIZE; + entry->wrappedSize = 0; + entry->startPos = nextReverbSubBufPos; + } else { + // End of the buffer is reached. Loop back around + entry->size = (numSamplesAfterDownsampling - extraSamples) * SAMPLE_SIZE; + entry->wrappedSize = extraSamples * SAMPLE_SIZE; + entry->startPos = nextReverbSubBufPos; + } + + entry->numSamplesAfterDownsampling = numSamplesAfterDownsampling; + entry->numSamples = numSamples; + } +} + +/** + * Sync the sample states between the notes and the list + */ +void AudioSynth_SyncSampleStates(s32 updateIndex) { + NoteSampleState* noteSampleState; + NoteSampleState* sampleState; + s32 sampleStateBaseIndex; + s32 i; + + sampleStateBaseIndex = gAudioContext.numNotes * updateIndex; + for (i = 0; i < gAudioContext.numNotes; i++) { + noteSampleState = &gAudioContext.notes[i].sampleState; + sampleState = &gAudioContext.sampleStateList[sampleStateBaseIndex + i]; + if (noteSampleState->bitField0.enabled) { + noteSampleState->bitField0.needsInit = false; + } else { + sampleState->bitField0.enabled = false; + } + + noteSampleState->harmonicIndexCurAndPrev = 0; + } +} + +Acmd* AudioSynth_Update(Acmd* abiCmdStart, s32* numAbiCmds, s16* aiBufStart, s32 numSamplesPerFrame) { + s32 numSamplesPerUpdate; + s16* curAiBufPos; + Acmd* curCmd = abiCmdStart; + s32 reverseUpdateIndex; + s32 reverbIndex; + SynthesisReverb* reverb; + + for (reverseUpdateIndex = gAudioContext.audioBufferParameters.updatesPerFrame; reverseUpdateIndex > 0; + reverseUpdateIndex--) { + AudioSeq_ProcessSequences(reverseUpdateIndex - 1); + AudioSynth_SyncSampleStates(gAudioContext.audioBufferParameters.updatesPerFrame - reverseUpdateIndex); + } + + curAiBufPos = aiBufStart; + gAudioContext.adpcmCodeBook = NULL; + + // Process/Update all samples multiple times in a single frame + for (reverseUpdateIndex = gAudioContext.audioBufferParameters.updatesPerFrame; reverseUpdateIndex > 0; + reverseUpdateIndex--) { + if (reverseUpdateIndex == 1) { + // Final Update + numSamplesPerUpdate = numSamplesPerFrame; + } else if ((numSamplesPerFrame / reverseUpdateIndex) >= + gAudioContext.audioBufferParameters.numSamplesPerUpdateMax) { + numSamplesPerUpdate = gAudioContext.audioBufferParameters.numSamplesPerUpdateMax; + } else if ((numSamplesPerFrame / reverseUpdateIndex) <= + gAudioContext.audioBufferParameters.numSamplesPerUpdateMin) { + numSamplesPerUpdate = gAudioContext.audioBufferParameters.numSamplesPerUpdateMin; + } else { + numSamplesPerUpdate = gAudioContext.audioBufferParameters.numSamplesPerUpdate; + } + + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { + if (gAudioContext.synthesisReverbs[reverbIndex].useReverb) { + AudioSynth_AddReverbBufferEntry( + numSamplesPerUpdate, gAudioContext.audioBufferParameters.updatesPerFrame - reverseUpdateIndex, + reverbIndex); + } + } + + curCmd = AudioSynth_ProcessSamples(curAiBufPos, numSamplesPerUpdate, curCmd, + gAudioContext.audioBufferParameters.updatesPerFrame - reverseUpdateIndex); + numSamplesPerFrame -= numSamplesPerUpdate; + curAiBufPos += numSamplesPerUpdate * SAMPLE_SIZE; + } + + // Update reverb frame info + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { + if (gAudioContext.synthesisReverbs[reverbIndex].framesToIgnore != 0) { + gAudioContext.synthesisReverbs[reverbIndex].framesToIgnore--; + } + gAudioContext.synthesisReverbs[reverbIndex].curFrame ^= 1; + } + + *numAbiCmds = curCmd - abiCmdStart; + return curCmd; +} + +void AudioSynth_DisableSampleStates(s32 updateIndex, s32 noteIndex) { + NoteSampleState* sampleState; + s32 i; + + for (i = updateIndex + 1; i < gAudioContext.audioBufferParameters.updatesPerFrame; i++) { + sampleState = &gAudioContext.sampleStateList[(gAudioContext.numNotes * i) + noteIndex]; + if (sampleState->bitField0.needsInit) { + break; + } + sampleState->bitField0.enabled = false; + } +} + +/** + * Load reverb samples from a different reverb index + */ +Acmd* AudioSynth_LoadMixedReverbSamples(Acmd* cmd, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_TEMP, entry->startPos, entry->size, reverb); + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_TEMP + entry->size, 0, entry->wrappedSize, reverb); + } + return cmd; +} + +/** + * Save reverb samples from a different reverb index + */ +Acmd* AudioSynth_SaveMixedReverbSamples(Acmd* cmd, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + + cmd = AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_TEMP, entry->startPos, entry->size, reverb); + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_TEMP + entry->size, 0, entry->wrappedSize, reverb); + } + return cmd; +} + +void AudioSynth_Noop1(void) { +} + +void AudioSynth_ClearBuffer(Acmd* cmd, s32 dmem, s32 size) { + aClearBuffer(cmd, dmem, size); +} + +void AudioSynth_Noop2(void) { +} + +void AudioSynth_Noop3(void) { +} + +void AudioSynth_Noop4(void) { +} + +void AudioSynth_Mix(Acmd* cmd, size_t size, s32 gain, s32 dmemIn, s32 dmemOut) { + aMix(cmd, size, gain, dmemIn, dmemOut); +} + +void AudioSynth_Noop5(void) { +} + +void AudioSynth_Noop6(void) { +} + +void AudioSynth_Noop7(void) { +} + +void AudioSynth_SetBuffer(Acmd* cmd, s32 flags, s32 dmemIn, s32 dmemOut, size_t size) { + aSetBuffer(cmd, flags, dmemIn, dmemOut, size); +} + +void AudioSynth_Noop8(void) { +} + +void AudioSynth_Noop9(void) { +} + +void AudioSynth_DMemMove(Acmd* cmd, s32 dmemIn, s32 dmemOut, size_t size) { + // aDMEMMove(cmd, dmemIn, dmemOut, size); + cmd->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(dmemIn, 0, 24); + cmd->words.w1 = _SHIFTL(dmemOut, 16, 16) | _SHIFTL(size, 0, 16); +} + +void AudioSynth_Noop10(void) { +} + +void AudioSynth_Noop11(void) { +} + +void AudioSynth_Noop12(void) { +} + +void AudioSynth_Noop13(void) { +} + +void AudioSynth_InterL(Acmd* cmd, s32 dmemIn, s32 dmemOut, s32 numSamples) { + // aInterl(cmd, dmemIn, dmemOut, numSamples); + cmd->words.w0 = _SHIFTL(A_INTERL, 24, 8) | _SHIFTL(numSamples, 0, 16); + cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16); +} + +void AudioSynth_EnvSetup1(Acmd* cmd, s32 reverbVol, s32 rampReverb, s32 rampLeft, s32 rampRight) { + aEnvSetup1(cmd, reverbVol, rampReverb, rampLeft, rampRight); +} + +void AudioSynth_Noop14(void) { +} + +void AudioSynth_LoadBuffer(Acmd* cmd, s32 dmemDest, s32 size, void* addrSrc) { + aLoadBuffer(cmd, addrSrc, dmemDest, size); +} + +void AudioSynth_SaveBuffer(Acmd* cmd, s32 dmemSrc, s32 size, void* addrDest) { + aSaveBuffer(cmd, dmemSrc, addrDest, size); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187B64.s") +void AudioSynth_EnvSetup2(Acmd* cmd, s32 volLeft, s32 volRight) { + // aEnvSetup2(cmd, volLeft, volRight); + cmd->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8); + cmd->words.w1 = _SHIFTL(volLeft, 16, 16) | _SHIFTL(volRight, 0, 16); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187BEC.s") +void AudioSynth_Noop15(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187DE8.s") +void AudioSynth_Noop16(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187E58.s") +void AudioSynth_Noop17(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187F00.s") +void AudioSynth_S8Dec(Acmd* cmd, s32 flags, s16* state) { + aS8Dec(cmd, flags, state); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FA8.s") +void AudioSynth_HiLoGain(Acmd* cmd, s32 gain, s32 dmemIn, s32 dmemOut, s32 size) { + // aHiLoGain(cmd, gain, size, dmemIn, dmemOut); + cmd->words.w0 = _SHIFTL(A_HILOGAIN, 24, 8) | _SHIFTL(gain, 16, 8) | _SHIFTL(size, 0, 16); + cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FB0.s") +// Remnant of OoT +void AudioSynth_UnkCmd19(Acmd* cmd, s32 dmem1, s32 dmem2, s32 size, s32 arg4) { + cmd->words.w0 = _SHIFTL(A_SPNOOP, 24, 8) | _SHIFTL(arg4, 16, 8) | _SHIFTL(size, 0, 16); + cmd->words.w1 = _SHIFTL(dmem1, 16, 16) | _SHIFTL(dmem2, 0, 16); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FD0.s") +void AudioSynth_Noop18(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FD8.s") +void AudioSynth_Noop19(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FE0.s") +void AudioSynth_Noop20(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80187FE8.s") +void AudioSynth_Noop21(void) { +} -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018801C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188024.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018802C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188034.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188068.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188070.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188078.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880A4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880AC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880B4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880BC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880C4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801880E8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018811C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188124.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018814C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188174.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188190.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188198.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801881A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801881A8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801881C4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801881F8.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188224.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018822C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188234.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018823C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188244.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018824C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188254.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018825C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188264.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188288.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801882A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188304.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801884A0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188698.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018883C.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801888E4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_801889A4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188A50.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188AFC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188C48.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188CB4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188D20.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188D28.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188D68.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188DDC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80188FBC.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80189064.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_80189620.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018A4B4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018A768.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018A808.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018ACC4.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/audio_synthesis/func_8018AE34.s") +void AudioSynth_Noop22(void) { +} + +void AudioSynth_Noop23(void) { +} + +void AudioSynth_Noop24(void) { +} + +void AudioSynth_Noop25(void) { +} + +void AudioSynth_LoadFilterBuffer(Acmd* cmd, s32 flags, s32 buf, s16* addr) { + aFilter(cmd, flags, buf, addr); +} + +void AudioSynth_LoadFilterSize(Acmd* cmd, size_t size, s16* addr) { + aFilter(cmd, 2, size, addr); +} + +/** + * Leak some audio from the left reverb channel into the right reverb channel and vice versa (pan) + */ +Acmd* AudioSynth_LeakReverb(Acmd* cmd, SynthesisReverb* reverb) { + aDMEMMove(cmd++, DMEM_WET_LEFT_CH, DMEM_WET_SCRATCH, DMEM_1CH_SIZE); + aMix(cmd++, DMEM_1CH_SIZE >> 4, reverb->leakRtl, DMEM_WET_RIGHT_CH, DMEM_WET_LEFT_CH); + aMix(cmd++, DMEM_1CH_SIZE >> 4, reverb->leakLtr, DMEM_WET_SCRATCH, DMEM_WET_RIGHT_CH); + + return cmd; +} + +Acmd* AudioSynth_LoadDownsampledReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, + s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + s16 offsetSize = (entry->startPos & 7) * SAMPLE_SIZE; + s16 wrappedOffsetSize = ALIGN16(offsetSize + entry->size); + + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_TEMP, entry->startPos - (offsetSize / (s32)SAMPLE_SIZE), + DMEM_1CH_SIZE, reverb); + + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_TEMP + wrappedOffsetSize, 0, + DMEM_1CH_SIZE - wrappedOffsetSize, reverb); + } + + aSetBuffer(cmd++, 0, DMEM_WET_TEMP + offsetSize, DMEM_WET_LEFT_CH, numSamplesPerUpdate * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, reverb->downsamplePitch, reverb->leftLoadResampleBuf); + aSetBuffer(cmd++, 0, DMEM_WET_TEMP + DMEM_1CH_SIZE + offsetSize, DMEM_WET_RIGHT_CH, + numSamplesPerUpdate * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, reverb->downsamplePitch, reverb->rightLoadResampleBuf); + + return cmd; +} + +Acmd* AudioSynth_SaveResampledReverbSamples(Acmd* cmd, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + s16 numSamples = entry->numSamples; + u32 size = numSamples * SAMPLE_SIZE; + + // Left Resample + aDMEMMove(cmd++, DMEM_WET_LEFT_CH, DMEM_WET_TEMP, size); + aSetBuffer(cmd++, 0, DMEM_WET_TEMP, DMEM_WET_SCRATCH, entry->saveResampleNumSamples * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, entry->saveResamplePitch, reverb->leftSaveResampleBuf); + + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, DMEM_WET_SCRATCH, entry->size, + &reverb->leftReverbBuf[entry->startPos]); + + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, entry->size + DMEM_WET_SCRATCH, entry->wrappedSize, + reverb->leftReverbBuf); + } + + // Right Resample + aDMEMMove(cmd++, DMEM_WET_RIGHT_CH, DMEM_WET_TEMP, size); + aSetBuffer(cmd++, 0, DMEM_WET_TEMP, DMEM_WET_SCRATCH, entry->saveResampleNumSamples * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, entry->saveResamplePitch, reverb->rightSaveResampleBuf); + + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, DMEM_WET_SCRATCH, entry->size, + &reverb->rightReverbBuf[entry->startPos]); + + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, entry->size + DMEM_WET_SCRATCH, entry->wrappedSize, + reverb->rightReverbBuf); + } + + return cmd; +} + +Acmd* AudioSynth_LoadResampledReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, + s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + s16 offsetSize = (entry->startPos & 7) * SAMPLE_SIZE; + s16 wrappedOffsetSize = ALIGN16(offsetSize + entry->size); + + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_TEMP, entry->startPos - (offsetSize / (s32)SAMPLE_SIZE), + DMEM_1CH_SIZE, reverb); + + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, wrappedOffsetSize + DMEM_WET_TEMP, 0, + DMEM_1CH_SIZE - wrappedOffsetSize, reverb); + } + + aSetBuffer(cmd++, 0, DMEM_WET_TEMP + offsetSize, DMEM_WET_LEFT_CH, numSamplesPerUpdate * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, entry->loadResamplePitch, reverb->leftLoadResampleBuf); + aSetBuffer(cmd++, 0, DMEM_WET_TEMP + DMEM_1CH_SIZE + offsetSize, DMEM_WET_RIGHT_CH, + numSamplesPerUpdate * SAMPLE_SIZE); + aResample(cmd++, reverb->resampleFlags, entry->loadResamplePitch, reverb->rightLoadResampleBuf); + + return cmd; +} + +/** + * Apply a filter (convolution) to each reverb channel. + */ +Acmd* AudioSynth_FilterReverb(Acmd* cmd, s32 size, SynthesisReverb* reverb) { + if (reverb->filterLeft != NULL) { + aFilter(cmd++, 2, size, reverb->filterLeft); + aFilter(cmd++, reverb->resampleFlags, DMEM_WET_LEFT_CH, reverb->filterLeftState); + } + + if (reverb->filterRight != NULL) { + aFilter(cmd++, 2, size, reverb->filterRight); + aFilter(cmd++, reverb->resampleFlags, DMEM_WET_RIGHT_CH, reverb->filterRightState); + } + + return cmd; +} + +/** + * Mix in reverb from a different reverb index + */ +Acmd* AudioSynth_MixOtherReverbIndex(Acmd* cmd, SynthesisReverb* reverb, s32 updateIndex) { + SynthesisReverb* mixReverb; + + if (reverb->mixReverbIndex >= gAudioContext.numSynthesisReverbs) { + return cmd; + } + + mixReverb = &gAudioContext.synthesisReverbs[reverb->mixReverbIndex]; + if (mixReverb->downsampleRate == 1) { + cmd = AudioSynth_LoadMixedReverbSamples(cmd, mixReverb, updateIndex); + aMix(cmd++, DMEM_2CH_SIZE >> 4, reverb->mixReverbStrength, DMEM_WET_LEFT_CH, DMEM_WET_TEMP); + cmd = AudioSynth_SaveMixedReverbSamples(cmd, mixReverb, updateIndex); + } + + return cmd; +} + +Acmd* AudioSynth_LoadDefaultReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, + s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH, entry->startPos, entry->size, reverb); + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH + entry->size, 0, entry->wrappedSize, reverb); + } + + return cmd; +} + +Acmd* AudioSynth_LoadSubReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* subEntry = &reverb->subBufEntry[reverb->curFrame][updateIndex]; + + cmd = AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH, subEntry->startPos, subEntry->size, reverb); + if (subEntry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = + AudioSynth_LoadReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH + subEntry->size, 0, subEntry->wrappedSize, reverb); + } + + return cmd; +} + +Acmd* AudioSynth_SaveResampledReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 size, uintptr_t startAddr) { + s32 startAddrAlignDropped; + u32 endAddr; + s32 endAddrAlignDropped; + + endAddr = startAddr + size; + + endAddrAlignDropped = endAddr & 0xF; + if (endAddrAlignDropped != 0) { + aLoadBuffer(cmd++, (endAddr - endAddrAlignDropped), DMEM_TEMP, 0x10); + aDMEMMove(cmd++, dmem, DMEM_TEMP2, size); + aDMEMMove(cmd++, DMEM_TEMP + endAddrAlignDropped, size + DMEM_TEMP2, 0x10 - endAddrAlignDropped); + + size += (0x10 - endAddrAlignDropped); + dmem = DMEM_TEMP2; + } + + startAddrAlignDropped = startAddr & 0xF; + if (startAddrAlignDropped != 0) { + aLoadBuffer(cmd++, startAddr - startAddrAlignDropped, DMEM_TEMP, 0x10); + aDMEMMove(cmd++, dmem, startAddrAlignDropped + DMEM_TEMP, size); + + size += startAddrAlignDropped; + dmem = DMEM_TEMP; + } + + aSaveBuffer(cmd++, dmem, startAddr - startAddrAlignDropped, size); + + return cmd; +} + +Acmd* AudioSynth_LoadReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb) { + aLoadBuffer(cmd++, &reverb->leftReverbBuf[startPos], dmem, size); + aLoadBuffer(cmd++, &reverb->rightReverbBuf[startPos], dmem + DMEM_1CH_SIZE, size); + + return cmd; +} + +Acmd* AudioSynth_SaveReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb) { + aSaveBuffer(cmd++, dmem, &reverb->leftReverbBuf[startPos], size); + aSaveBuffer(cmd++, dmem + DMEM_1CH_SIZE, &reverb->rightReverbBuf[startPos], size); + + return cmd; +} + +void AudioSynth_Noop26(void) { +} + +Acmd* AudioSynth_LoadSubReverbSamplesWithoutDownsample(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, + s16 updateIndex) { + if (reverb->downsampleRate == 1) { + cmd = AudioSynth_LoadSubReverbSamples(cmd, numSamplesPerUpdate, reverb, updateIndex); + } + + return cmd; +} + +Acmd* AudioSynth_LoadReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, SynthesisReverb* reverb, s16 updateIndex) { + if (reverb->downsampleRate == 1) { + if (reverb->resampleEffectOn) { + cmd = AudioSynth_LoadResampledReverbSamples(cmd, numSamplesPerUpdate, reverb, updateIndex); + } else { + cmd = AudioSynth_LoadDefaultReverbSamples(cmd, numSamplesPerUpdate, reverb, updateIndex); + } + } else { + cmd = AudioSynth_LoadDownsampledReverbSamples(cmd, numSamplesPerUpdate, reverb, updateIndex); + } + + return cmd; +} + +Acmd* AudioSynth_SaveReverbSamples(Acmd* cmd, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* entry = &reverb->bufEntry[reverb->curFrame][updateIndex]; + s32 downsampleRate; + s32 numSamples; + + if (reverb->downsampleRate == 1) { + if (reverb->resampleEffectOn) { + cmd = AudioSynth_SaveResampledReverbSamples(cmd, reverb, updateIndex); + } else { + // Put the oldest samples in the ring buffer into the wet channels + cmd = AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH, entry->startPos, entry->size, reverb); + if (entry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH + entry->size, 0, entry->wrappedSize, + reverb); + } + } + } else { + //! FAKE: + if (1) {} + + downsampleRate = reverb->downsampleRate; + numSamples = 13 * SAMPLES_PER_FRAME; + + while (downsampleRate >= 2) { + aInterl(cmd++, DMEM_WET_LEFT_CH, DMEM_WET_LEFT_CH, numSamples); + aInterl(cmd++, DMEM_WET_RIGHT_CH, DMEM_WET_RIGHT_CH, numSamples); + downsampleRate >>= 1; + numSamples >>= 1; + } + + if (entry->size != 0) { + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH, entry->size, + &reverb->leftReverbBuf[entry->startPos]); + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, DMEM_WET_RIGHT_CH, entry->size, + &reverb->rightReverbBuf[entry->startPos]); + } + + if (entry->wrappedSize != 0) { + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, entry->size + DMEM_WET_LEFT_CH, entry->wrappedSize, + reverb->leftReverbBuf); + cmd = AudioSynth_SaveResampledReverbSamplesImpl(cmd, entry->size + DMEM_WET_RIGHT_CH, entry->wrappedSize, + reverb->rightReverbBuf); + } + } + + reverb->resampleFlags = 0; + + return cmd; +} + +Acmd* AudioSynth_SaveSubReverbSamples(Acmd* cmd, SynthesisReverb* reverb, s16 updateIndex) { + ReverbBufferEntry* subEntry = &reverb->subBufEntry[reverb->curFrame][updateIndex]; + + cmd = AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH, subEntry->startPos, subEntry->size, reverb); + if (subEntry->wrappedSize != 0) { + // Ring buffer wrapped + cmd = + AudioSynth_SaveReverbSamplesImpl(cmd, DMEM_WET_LEFT_CH + subEntry->size, 0, subEntry->wrappedSize, reverb); + } + + return cmd; +} + +/** + * Process all samples embedded in a note. Every sample has numSamplesPerUpdate processed, + * and each of those are mixed together into both DMEM_LEFT_CH and DMEM_RIGHT_CH + */ +Acmd* AudioSynth_ProcessSamples(s16* aiBuf, s32 numSamplesPerUpdate, Acmd* cmd, s32 updateIndex) { + s32 size; + u8 noteIndices[0x58]; + s16 noteCount = 0; + s16 reverbIndex; + SynthesisReverb* reverb; + s32 useReverb; + s32 sampleStateOffset = gAudioContext.numNotes * updateIndex; + s32 i; + + if (gAudioContext.numSynthesisReverbs == 0) { + for (i = 0; i < gAudioContext.numNotes; i++) { + if (gAudioContext.sampleStateList[sampleStateOffset + i].bitField0.enabled) { + noteIndices[noteCount++] = i; + } + } + } else { + NoteSampleState* sampleState; + + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { + for (i = 0; i < gAudioContext.numNotes; i++) { + sampleState = &gAudioContext.sampleStateList[sampleStateOffset + i]; + if (sampleState->bitField0.enabled && (sampleState->bitField1.reverbIndex == reverbIndex)) { + noteIndices[noteCount++] = i; + } + } + } + + for (i = 0; i < gAudioContext.numNotes; i++) { + sampleState = &gAudioContext.sampleStateList[sampleStateOffset + i]; + if (sampleState->bitField0.enabled && + (sampleState->bitField1.reverbIndex >= gAudioContext.numSynthesisReverbs)) { + noteIndices[noteCount++] = i; + } + } + } + + aClearBuffer(cmd++, DMEM_LEFT_CH, DMEM_2CH_SIZE); + + i = 0; + for (reverbIndex = 0; reverbIndex < gAudioContext.numSynthesisReverbs; reverbIndex++) { + s32 subDelay; + NoteSampleState* sampleState; + + reverb = &gAudioContext.synthesisReverbs[reverbIndex]; + useReverb = reverb->useReverb; + if (useReverb) { + + // Loads reverb samples from DRAM (ringBuffer) into DMEM (DMEM_WET_LEFT_CH) + cmd = AudioSynth_LoadReverbSamples(cmd, numSamplesPerUpdate, reverb, updateIndex); + + // Mixes reverb sample into the main dry channel + // reverb->volume is always set to 0x7FFF (audio spec), and DMEM_LEFT_CH is cleared before reverbs. + // So this is essentially a DMEMmove from DMEM_WET_LEFT_CH to DMEM_LEFT_CH + aMix(cmd++, DMEM_2CH_SIZE >> 4, reverb->volume, DMEM_WET_LEFT_CH, DMEM_LEFT_CH); + + subDelay = reverb->subDelay; + if (subDelay != 0) { + aDMEMMove(cmd++, DMEM_WET_LEFT_CH, DMEM_WET_TEMP, DMEM_2CH_SIZE); + } + + // Decays reverb over time. The (+ 0x8000) here is -100% + aMix(cmd++, DMEM_2CH_SIZE >> 4, reverb->decayRatio + 0x8000, DMEM_WET_LEFT_CH, DMEM_WET_LEFT_CH); + + if (((reverb->leakRtl != 0) || (reverb->leakLtr != 0)) && (gAudioContext.soundMode != SOUNDMODE_MONO)) { + cmd = AudioSynth_LeakReverb(cmd, reverb); + } + + if (subDelay != 0) { + if (reverb->mixReverbIndex != REVERB_INDEX_NONE) { + cmd = AudioSynth_MixOtherReverbIndex(cmd, reverb, updateIndex); + } + cmd = AudioSynth_SaveReverbSamples(cmd, reverb, updateIndex); + cmd = AudioSynth_LoadSubReverbSamplesWithoutDownsample(cmd, numSamplesPerUpdate, reverb, updateIndex); + aMix(cmd++, DMEM_2CH_SIZE >> 4, reverb->subVolume, DMEM_WET_TEMP, DMEM_WET_LEFT_CH); + } + } + + while (i < noteCount) { + sampleState = &gAudioContext.sampleStateList[sampleStateOffset + noteIndices[i]]; + if (sampleState->bitField1.reverbIndex != reverbIndex) { + break; + } + cmd = AudioSynth_ProcessSample(noteIndices[i], sampleState, + &gAudioContext.notes[noteIndices[i]].synthesisState, aiBuf, + numSamplesPerUpdate, cmd, updateIndex); + i++; + } + + if (useReverb) { + if ((reverb->filterLeft != NULL) || (reverb->filterRight != NULL)) { + cmd = AudioSynth_FilterReverb(cmd, numSamplesPerUpdate * SAMPLE_SIZE, reverb); + } + + // Saves the wet channel sample from DMEM (DMEM_WET_LEFT_CH) into (ringBuffer) DRAM for future use + if (subDelay != 0) { + cmd = AudioSynth_SaveSubReverbSamples(cmd, reverb, updateIndex); + } else { + if (reverb->mixReverbIndex != REVERB_INDEX_NONE) { + cmd = AudioSynth_MixOtherReverbIndex(cmd, reverb, updateIndex); + } + cmd = AudioSynth_SaveReverbSamples(cmd, reverb, updateIndex); + } + } + } + + while (i < noteCount) { + cmd = AudioSynth_ProcessSample( + noteIndices[i], &gAudioContext.sampleStateList[sampleStateOffset + noteIndices[i]], + &gAudioContext.notes[noteIndices[i]].synthesisState, aiBuf, numSamplesPerUpdate, cmd, updateIndex); + i++; + } + + size = numSamplesPerUpdate * SAMPLE_SIZE; + aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, size); + + if (gCustomAudioSynthFunction != NULL) { + cmd = gCustomAudioSynthFunction(cmd, 2 * size, updateIndex); + } + aSaveBuffer(cmd++, DMEM_TEMP, aiBuf, 2 * size); + + return cmd; +} + +Acmd* AudioSynth_ProcessSample(s32 noteIndex, NoteSampleState* sampleState, NoteSynthesisState* synthState, s16* aiBuf, + s32 numSamplesPerUpdate, Acmd* cmd, s32 updateIndex) { + s32 pad1[2]; + void* reverbAddrSrc; + Sample* sample; + AdpcmLoop* loopInfo; + s32 numSamplesUntilEnd; + s32 numSamplesInThisIteration; + s32 sampleFinished; + s32 loopToPoint; + s32 flags; + u16 frequencyFixedPoint; + s32 gain; + s32 frameIndex; + s32 skipBytes; + void* combFilterState; + s32 numSamplesToDecode; + s32 numFirstFrameSamplesToIgnore; + u8* sampleAddr; + u32 numSamplesToLoadFixedPoint; + s32 numSamplesToLoadAdj; + s32 numSamplesProcessed; + s32 sampleEndPos; + s32 numSamplesToProcess; + s32 dmemUncompressedAddrOffset2; + s32 pad2[3]; + s32 numSamplesInFirstFrame; + s32 numTrailingSamplesToIgnore; + s32 pad3[3]; + s32 frameSize; + s32 numFramesToDecode; + s32 skipInitialSamples; + s32 zeroOffset; + u8* samplesToLoadAddr; + s32 numParts; + s32 curPart; + s32 sampleDataChunkAlignPad; + s32 haasEffectDelaySide; + s32 numSamplesToLoadFirstPart; + u16 sampleDmemBeforeResampling; + s32 sampleAddrOffset; + s32 combFilterDmem; + s32 dmemUncompressedAddrOffset1; + Note* note; + u32 numSamplesToLoad; + u16 combFilterSize; + u16 combFilterGain; + s16* filter; + s32 bookOffset = sampleState->bitField1.bookOffset; + s32 finished = sampleState->bitField0.finished; + s32 sampleDataChunkSize; + s16 sampleDataDmemAddr; + + note = &gAudioContext.notes[noteIndex]; + flags = A_CONTINUE; + + // Initialize the synthesis state + if (sampleState->bitField0.needsInit == true) { + flags = A_INIT; + synthState->atLoopPoint = false; + synthState->stopLoop = false; + synthState->samplePosInt = note->playbackState.startSamplePos; + synthState->samplePosFrac = 0; + synthState->curVolLeft = 0; + synthState->curVolRight = 0; + synthState->prevHaasEffectLeftDelaySize = 0; + synthState->prevHaasEffectRightDelaySize = 0; + synthState->curReverbVol = sampleState->targetReverbVol; + synthState->numParts = 0; + synthState->combFilterNeedsInit = true; + note->sampleState.bitField0.finished = false; + synthState->unk_1F = note->playbackState.unk_80; // Never set, never used + finished = false; + } + + // Process the sample in either one or two parts + numParts = sampleState->bitField1.hasTwoParts + 1; + + // Determine number of samples to load based on numSamplesPerUpdate and relative frequency + frequencyFixedPoint = sampleState->frequencyFixedPoint; + numSamplesToLoadFixedPoint = (frequencyFixedPoint * numSamplesPerUpdate * 2) + synthState->samplePosFrac; + numSamplesToLoad = numSamplesToLoadFixedPoint >> 16; + + if (numSamplesToLoad == 0) { + skipBytes = false; + } + + synthState->samplePosFrac = numSamplesToLoadFixedPoint & 0xFFFF; + + // Partially-optimized out no-op ifs required for matching. SM64 decomp + // makes it clear that this is how it should look. + if ((synthState->numParts == 1) && (numParts == 2)) { + } else if ((synthState->numParts == 2) && (numParts == 1)) { + } else { + } + + synthState->numParts = numParts; + + if (sampleState->bitField1.isSyntheticWave) { + cmd = AudioSynth_LoadWaveSamples(cmd, sampleState, synthState, numSamplesToLoad); + sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * 2); + synthState->samplePosInt += numSamplesToLoad; + } else { + sample = sampleState->tunedSample->sample; + loopInfo = sample->loop; + + if (note->playbackState.status != PLAYBACK_STATUS_0) { + synthState->stopLoop = true; + } + + if ((loopInfo->count == 2) && synthState->stopLoop) { + sampleEndPos = loopInfo->sampleEnd; + } else { + sampleEndPos = loopInfo->loopEnd; + } + + sampleAddr = sample->sampleAddr; + numSamplesToLoadFirstPart = 0; + + // If the frequency requested is more than double that of the raw sample, + // then the sample processing is split into two parts. + for (curPart = 0; curPart < numParts; curPart++) { + numSamplesProcessed = 0; + dmemUncompressedAddrOffset1 = 0; + + // Adjust the number of samples to load only if there are two parts and an odd number of samples + if (numParts == 1) { + numSamplesToLoadAdj = numSamplesToLoad; + } else if (numSamplesToLoad & 1) { + // round down for the first part + // round up for the second part + numSamplesToLoadAdj = (numSamplesToLoad & ~1) + (curPart * 2); + } else { + numSamplesToLoadAdj = numSamplesToLoad; + } + + // Load the ADPCM codeBook + if ((sample->codec == CODEC_ADPCM) || (sample->codec == CODEC_SMALL_ADPCM)) { + if (gAudioContext.adpcmCodeBook != sample->book->codeBook) { + u32 numEntries; + + switch (bookOffset) { + case 1: + gAudioContext.adpcmCodeBook = &gInvalidAdpcmCodeBook[1]; + break; + + case 2: + case 3: + default: + gAudioContext.adpcmCodeBook = sample->book->codeBook; + break; + } + + numEntries = SAMPLES_PER_FRAME * sample->book->order * sample->book->numPredictors; + aLoadADPCM(cmd++, numEntries, gAudioContext.adpcmCodeBook); + } + } + + // Continue processing samples until the number of samples needed to load is reached + while (numSamplesProcessed != numSamplesToLoadAdj) { + sampleFinished = false; + loopToPoint = false; + dmemUncompressedAddrOffset2 = 0; + + numFirstFrameSamplesToIgnore = synthState->samplePosInt & 0xF; + numSamplesUntilEnd = sampleEndPos - synthState->samplePosInt; + + // Calculate number of samples to process this loop + numSamplesToProcess = numSamplesToLoadAdj - numSamplesProcessed; + + if ((numFirstFrameSamplesToIgnore == 0) && !synthState->atLoopPoint) { + numFirstFrameSamplesToIgnore = SAMPLES_PER_FRAME; + } + numSamplesInFirstFrame = SAMPLES_PER_FRAME - numFirstFrameSamplesToIgnore; + + // Determine the number of samples to decode based on whether the end will be reached or not. + if (numSamplesToProcess < numSamplesUntilEnd) { + // The end will not be reached. + numFramesToDecode = + (s32)(numSamplesToProcess - numSamplesInFirstFrame + SAMPLES_PER_FRAME - 1) / SAMPLES_PER_FRAME; + numSamplesToDecode = numFramesToDecode * SAMPLES_PER_FRAME; + numTrailingSamplesToIgnore = numSamplesInFirstFrame + numSamplesToDecode - numSamplesToProcess; + } else { + // The end will be reached. + numSamplesToDecode = numSamplesUntilEnd - numSamplesInFirstFrame; + numTrailingSamplesToIgnore = 0; + if (numSamplesToDecode <= 0) { + numSamplesToDecode = 0; + numSamplesInFirstFrame = numSamplesUntilEnd; + } + numFramesToDecode = (numSamplesToDecode + SAMPLES_PER_FRAME - 1) / SAMPLES_PER_FRAME; + if (loopInfo->count != 0) { + if ((loopInfo->count == 2) && synthState->stopLoop) { + sampleFinished = true; + } else { + // Loop around and restart + loopToPoint = true; + } + } else { + sampleFinished = true; + } + } + + // Set parameters based on compression type + switch (sample->codec) { + case CODEC_ADPCM: + // 16 2-byte samples (32 bytes) compressed into 4-bit samples (8 bytes) + 1 header byte + frameSize = 9; + skipInitialSamples = SAMPLES_PER_FRAME; + zeroOffset = 0; + break; + + case CODEC_SMALL_ADPCM: + // 16 2-byte samples (32 bytes) compressed into 2-bit samples (4 bytes) + 1 header byte + frameSize = 5; + skipInitialSamples = SAMPLES_PER_FRAME; + zeroOffset = 0; + break; + + case CODEC_UNK7: + // 2 2-byte samples (4 bytes) processed without decompression + frameSize = 4; + skipInitialSamples = SAMPLES_PER_FRAME; + zeroOffset = 0; + break; + + case CODEC_S8: + // 16 2-byte samples (32 bytes) compressed into 8-bit samples (16 bytes) + frameSize = 16; + skipInitialSamples = SAMPLES_PER_FRAME; + zeroOffset = 0; + break; + + case CODEC_REVERB: + reverbAddrSrc = (void*)0xFFFFFFFF; + if (gCustomAudioReverbFunction != NULL) { + reverbAddrSrc = gCustomAudioReverbFunction(sample, numSamplesToLoadAdj, flags, noteIndex); + } + + if (reverbAddrSrc == (void*)0xFFFFFFFF) { + sampleFinished = true; + } else if (reverbAddrSrc == NULL) { + return cmd; + } else { + AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, + (numSamplesToLoadAdj + SAMPLES_PER_FRAME) * SAMPLE_SIZE, + reverbAddrSrc); + flags = A_CONTINUE; + skipBytes = 0; + numSamplesProcessed = numSamplesToLoadAdj; + dmemUncompressedAddrOffset1 = numSamplesToLoadAdj; + } + goto skip; + + case CODEC_S16_INMEMORY: + case CODEC_UNK6: + AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, + (numSamplesToLoadAdj + SAMPLES_PER_FRAME) * SAMPLE_SIZE); + flags = A_CONTINUE; + skipBytes = 0; + numSamplesProcessed = numSamplesToLoadAdj; + dmemUncompressedAddrOffset1 = numSamplesToLoadAdj; + goto skip; + + case CODEC_S16: + AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, + (numSamplesToLoadAdj + SAMPLES_PER_FRAME) * SAMPLE_SIZE); + flags = A_CONTINUE; + skipBytes = 0; + numSamplesProcessed = numSamplesToLoadAdj; + dmemUncompressedAddrOffset1 = numSamplesToLoadAdj; + goto skip; + + default: + break; + } + + // Move the compressed raw sample data from ram into the rsp (DMEM) + if (numFramesToDecode != 0) { + // Get the offset from the start of the sample to where the sample is currently playing from + frameIndex = (synthState->samplePosInt + skipInitialSamples - numFirstFrameSamplesToIgnore) / + SAMPLES_PER_FRAME; + sampleAddrOffset = frameIndex * frameSize; + + // Get the ram address of the requested sample chunk + if (sample->medium == MEDIUM_RAM) { + // Sample is already loaded into ram + samplesToLoadAddr = sampleAddr + (zeroOffset + sampleAddrOffset); + } else if (gAudioContext.unk_29B8) { // always false + return cmd; + } else if (sample->medium == MEDIUM_UNK) { + // This medium is unsupported so terminate processing this note + return cmd; + } else { + // This medium is not in ram, so dma the requested sample into ram + samplesToLoadAddr = + AudioLoad_DmaSampleData(sampleAddr + (zeroOffset + sampleAddrOffset), + ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME), flags, + &synthState->sampleDmaIndex, sample->medium); + } + + if (samplesToLoadAddr == NULL) { + // The ram address was unsuccessfully allocated + return cmd; + } + + // Move the raw sample chunk from ram to the rsp + // DMEM at the addresses before DMEM_COMPRESSED_ADPCM_DATA + sampleDataChunkAlignPad = (u32)samplesToLoadAddr & 0xF; + sampleDataChunkSize = ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME); + sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize; + aLoadBuffer(cmd++, samplesToLoadAddr - sampleDataChunkAlignPad, sampleDataDmemAddr, + sampleDataChunkSize); + } else { + numSamplesToDecode = 0; + sampleDataChunkAlignPad = 0; + } + + if (synthState->atLoopPoint) { + aSetLoop(cmd++, sample->loop->predictorState); + flags = A_LOOP; + synthState->atLoopPoint = false; + } + + numSamplesInThisIteration = numSamplesToDecode + numSamplesInFirstFrame - numTrailingSamplesToIgnore; + + if (numSamplesProcessed == 0) { + //! FAKE: + if (1) {} + skipBytes = numFirstFrameSamplesToIgnore * SAMPLE_SIZE; + } else { + dmemUncompressedAddrOffset2 = ALIGN16(dmemUncompressedAddrOffset1 + 8 * SAMPLE_SIZE); + } + + // Decompress the raw sample chunks in the rsp + // Goes from adpcm (compressed) sample data to pcm (uncompressed) sample data + switch (sample->codec) { + case CODEC_ADPCM: + sampleDataChunkSize = ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME); + sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize; + aSetBuffer(cmd++, 0, sampleDataDmemAddr + sampleDataChunkAlignPad, + DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset2, + numSamplesToDecode * SAMPLE_SIZE); + aADPCMdec(cmd++, flags, synthState->synthesisBuffers->adpcmState); + break; + + case CODEC_SMALL_ADPCM: + sampleDataChunkSize = ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME); + sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize; + aSetBuffer(cmd++, 0, sampleDataDmemAddr + sampleDataChunkAlignPad, + DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset2, + numSamplesToDecode * SAMPLE_SIZE); + aADPCMdec(cmd++, flags | A_ADPCM_SHORT, synthState->synthesisBuffers->adpcmState); + break; + + case CODEC_S8: + sampleDataChunkSize = ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME); + sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize; + AudioSynth_SetBuffer(cmd++, 0, sampleDataDmemAddr + sampleDataChunkAlignPad, + DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset2, + numSamplesToDecode * SAMPLE_SIZE); + AudioSynth_S8Dec(cmd++, flags, synthState->synthesisBuffers->adpcmState); + break; + + case CODEC_UNK7: + default: + // No decompression + break; + } + + if (numSamplesProcessed != 0) { + aDMEMMove(cmd++, + DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset2 + + (numFirstFrameSamplesToIgnore * SAMPLE_SIZE), + DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset1, + numSamplesInThisIteration * SAMPLE_SIZE); + } + + numSamplesProcessed += numSamplesInThisIteration; + + switch (flags) { + case A_INIT: + skipBytes = SAMPLES_PER_FRAME * SAMPLE_SIZE; + dmemUncompressedAddrOffset1 = (numSamplesToDecode + SAMPLES_PER_FRAME) * SAMPLE_SIZE; + break; + + case A_LOOP: + dmemUncompressedAddrOffset1 = + numSamplesInThisIteration * SAMPLE_SIZE + dmemUncompressedAddrOffset1; + break; + + default: + if (dmemUncompressedAddrOffset1 != 0) { + dmemUncompressedAddrOffset1 = + numSamplesInThisIteration * SAMPLE_SIZE + dmemUncompressedAddrOffset1; + } else { + dmemUncompressedAddrOffset1 = + (numFirstFrameSamplesToIgnore + numSamplesInThisIteration) * SAMPLE_SIZE; + } + break; + } + + flags = A_CONTINUE; + + skip: + + // Update what to do with the samples next + if (sampleFinished) { + if ((numSamplesToLoadAdj - numSamplesProcessed) != 0) { + AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE + dmemUncompressedAddrOffset1, + (numSamplesToLoadAdj - numSamplesProcessed) * SAMPLE_SIZE); + } + finished = true; + note->sampleState.bitField0.finished = true; + AudioSynth_DisableSampleStates(updateIndex, noteIndex); + break; // break out of the for-loop + } else if (loopToPoint) { + synthState->atLoopPoint = true; + synthState->samplePosInt = loopInfo->start; + } else { + synthState->samplePosInt += numSamplesToProcess; + } + } + + switch (numParts) { + case 1: + sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + skipBytes; + break; + + case 2: + switch (curPart) { + case 0: + AudioSynth_InterL(cmd++, DMEM_UNCOMPRESSED_NOTE + skipBytes, + DMEM_TEMP + (SAMPLES_PER_FRAME * SAMPLE_SIZE), + ALIGN8(numSamplesToLoadAdj / 2)); + numSamplesToLoadFirstPart = numSamplesToLoadAdj; + sampleDmemBeforeResampling = DMEM_TEMP + (SAMPLES_PER_FRAME * SAMPLE_SIZE); + if (finished) { + AudioSynth_ClearBuffer(cmd++, sampleDmemBeforeResampling + numSamplesToLoadFirstPart, + numSamplesToLoadAdj + SAMPLES_PER_FRAME); + } + break; + + case 1: + AudioSynth_InterL(cmd++, DMEM_UNCOMPRESSED_NOTE + skipBytes, + DMEM_TEMP + (SAMPLES_PER_FRAME * SAMPLE_SIZE) + numSamplesToLoadFirstPart, + ALIGN8(numSamplesToLoadAdj / 2)); + break; + + default: + break; + } + break; + + default: + break; + } + if (finished) { + break; + } + } + } + + // Update the flags for the signal processing below + flags = A_CONTINUE; + if (sampleState->bitField0.needsInit == true) { + sampleState->bitField0.needsInit = false; + flags = A_INIT; + } + + // Resample the decompressed mono-signal to the correct pitch + cmd = AudioSynth_FinalResample(cmd, synthState, numSamplesPerUpdate * SAMPLE_SIZE, frequencyFixedPoint, + sampleDmemBeforeResampling, flags); + + // UnkCmd19 was removed from the audio microcode + // This block performs no operation + if (bookOffset == 3) { + AudioSynth_UnkCmd19(cmd++, DMEM_TEMP, DMEM_TEMP, numSamplesPerUpdate * (s32)SAMPLE_SIZE, 0); + } + + // Apply the gain to the mono-signal to adjust the volume + gain = sampleState->gain; + if (gain != 0) { + // A gain of 0x10 (a UQ4.4 number) is equivalent to 1.0 and represents no volume change + if (gain < 0x10) { + gain = 0x10; + } + AudioSynth_HiLoGain(cmd++, gain, DMEM_TEMP, 0, (numSamplesPerUpdate + SAMPLES_PER_FRAME) * SAMPLE_SIZE); + } + + // Apply the filter to the mono-signal + filter = sampleState->filter; + if (filter != 0) { + AudioSynth_LoadFilterSize(cmd++, numSamplesPerUpdate * SAMPLE_SIZE, filter); + AudioSynth_LoadFilterBuffer(cmd++, flags, DMEM_TEMP, synthState->synthesisBuffers->filterState); + } + + // Apply the comb filter to the mono-signal by taking the signal with a small temporal offset, + // and adding it back to itself + combFilterSize = sampleState->combFilterSize; + combFilterGain = sampleState->combFilterGain; + combFilterState = synthState->synthesisBuffers->combFilterState; + if ((combFilterSize != 0) && (sampleState->combFilterGain != 0)) { + AudioSynth_DMemMove(cmd++, DMEM_TEMP, DMEM_COMB_TEMP, numSamplesPerUpdate * SAMPLE_SIZE); + combFilterDmem = DMEM_COMB_TEMP - combFilterSize; + if (synthState->combFilterNeedsInit) { + AudioSynth_ClearBuffer(cmd++, combFilterDmem, combFilterSize); + synthState->combFilterNeedsInit = false; + } else { + AudioSynth_LoadBuffer(cmd++, combFilterDmem, combFilterSize, combFilterState); + } + AudioSynth_SaveBuffer(cmd++, DMEM_TEMP + (numSamplesPerUpdate * SAMPLE_SIZE) - combFilterSize, combFilterSize, + combFilterState); + AudioSynth_Mix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, combFilterGain, DMEM_COMB_TEMP, + combFilterDmem); + AudioSynth_DMemMove(cmd++, combFilterDmem, DMEM_TEMP, numSamplesPerUpdate * SAMPLE_SIZE); + } else { + synthState->combFilterNeedsInit = true; + } + + // Determine the behavior of the audio processing that leads to the haas effect + if ((sampleState->haasEffectLeftDelaySize != 0) || (synthState->prevHaasEffectLeftDelaySize != 0)) { + haasEffectDelaySide = HAAS_EFFECT_DELAY_LEFT; + } else if ((sampleState->haasEffectRightDelaySize != 0) || (synthState->prevHaasEffectRightDelaySize != 0)) { + haasEffectDelaySide = HAAS_EFFECT_DELAY_RIGHT; + } else { + haasEffectDelaySide = HAAS_EFFECT_DELAY_NONE; + } + + // Apply an unknown effect based on the surround sound-mode + if (gAudioContext.soundMode == SOUNDMODE_SURROUND) { + sampleState->targetVolLeft = sampleState->targetVolLeft >> 1; + sampleState->targetVolRight = sampleState->targetVolRight >> 1; + if (sampleState->surroundEffectIndex != 0xFF) { + cmd = AudioSynth_ApplySurroundEffect(cmd, sampleState, synthState, numSamplesPerUpdate, DMEM_TEMP, flags); + } + } + + // Split the mono-signal into left and right channels: + // Both for dry signal (to go to the speakers now) + // and for wet signal (to go to a reverb buffer to be stored, and brought back later to produce an echo) + cmd = AudioSynth_ProcessEnvelope(cmd, sampleState, synthState, numSamplesPerUpdate, DMEM_TEMP, haasEffectDelaySide, + flags); + + // Apply the haas effect by delaying either the left or the right channel by a small amount + if (sampleState->bitField1.useHaasEffect) { + if (!(flags & A_INIT)) { + flags = A_CONTINUE; + } + cmd = AudioSynth_ApplyHaasEffect(cmd, sampleState, synthState, numSamplesPerUpdate * (s32)SAMPLE_SIZE, flags, + haasEffectDelaySide); + } + + return cmd; +} + +Acmd* AudioSynth_ApplySurroundEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, + s32 numSamplesPerUpdate, s32 haasDmem, s32 flags) { + s32 wetGain; + u16 dryGain; + s64 dmem = DMEM_SURROUND_TEMP; + f32 decayGain; + + AudioSynth_DMemMove(cmd++, haasDmem, DMEM_HAAS_TEMP, numSamplesPerUpdate * SAMPLE_SIZE); + dryGain = synthState->surroundEffectGain; + + if (flags == A_INIT) { + aClearBuffer(cmd++, dmem, sizeof(synthState->synthesisBuffers->surroundEffectState)); + synthState->surroundEffectGain = 0; + } else { + aLoadBuffer(cmd++, synthState->synthesisBuffers->surroundEffectState, dmem, + sizeof(synthState->synthesisBuffers->surroundEffectState)); + aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, dryGain, dmem, DMEM_LEFT_CH); + aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (dryGain ^ 0xFFFF), dmem, DMEM_RIGHT_CH); + + wetGain = (dryGain * synthState->curReverbVol) >> 7; + + aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, wetGain, dmem, DMEM_WET_LEFT_CH); + aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (wetGain ^ 0xFFFF), dmem, DMEM_WET_RIGHT_CH); + } + + aSaveBuffer(cmd++, DMEM_SURROUND_TEMP + (numSamplesPerUpdate * SAMPLE_SIZE), + synthState->synthesisBuffers->surroundEffectState, + sizeof(synthState->synthesisBuffers->surroundEffectState)); + + decayGain = (sampleState->targetVolLeft + sampleState->targetVolRight) * (1.0f / 0x2000); + + if (decayGain > 1.0f) { + decayGain = 1.0f; + } + + decayGain = decayGain * gDefaultPanVolume[127 - sampleState->surroundEffectIndex]; + synthState->surroundEffectGain = ((decayGain * 0x7FFF) + synthState->surroundEffectGain) / 2; + + AudioSynth_DMemMove(cmd++, DMEM_HAAS_TEMP, haasDmem, numSamplesPerUpdate * SAMPLE_SIZE); + + return cmd; +} + +Acmd* AudioSynth_FinalResample(Acmd* cmd, NoteSynthesisState* synthState, s32 size, u16 pitch, u16 inpDmem, + s32 resampleFlags) { + if (pitch == 0) { + AudioSynth_ClearBuffer(cmd++, DMEM_TEMP, size); + } else { + aSetBuffer(cmd++, 0, inpDmem, DMEM_TEMP, size); + aResample(cmd++, resampleFlags, pitch, synthState->synthesisBuffers->finalResampleState); + } + + return cmd; +} + +Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, + s32 numSamplesPerUpdate, u16 dmemSrc, s32 haasEffectDelaySide, s32 flags) { + u32 dmemDests; + u16 curVolLeft; + u16 targetVolLeft; + s32 curReverbVol; + u16 curVolRight; + s16 targetReverbVol; + s16 rampLeft; + s16 rampRight; + s16 rampReverb; + s16 curReverbVolAndFlags; + u16 targetVolRight; + f32 defaultPanVolume; + s32 pad; + + targetReverbVol = sampleState->targetReverbVol; + + curVolLeft = synthState->curVolLeft; + curVolRight = synthState->curVolRight; + + targetVolLeft = sampleState->targetVolLeft; + targetVolLeft <<= 4; + targetVolRight = sampleState->targetVolRight; + targetVolRight <<= 4; + + if ((gAudioContext.soundMode == SOUNDMODE_SURROUND) && (sampleState->surroundEffectIndex != 0xFF)) { + defaultPanVolume = gDefaultPanVolume[sampleState->surroundEffectIndex]; + targetVolLeft *= defaultPanVolume; + targetVolRight *= defaultPanVolume; + } + + if (targetVolLeft != curVolLeft) { + rampLeft = (targetVolLeft - curVolLeft) / (numSamplesPerUpdate >> 3); + } else { + rampLeft = 0; + } + + if (targetVolRight != curVolRight) { + rampRight = (targetVolRight - curVolRight) / (numSamplesPerUpdate >> 3); + } else { + rampRight = 0; + } + + curReverbVolAndFlags = synthState->curReverbVol; + curReverbVol = curReverbVolAndFlags & 0x7F; + + if (curReverbVolAndFlags != targetReverbVol) { + rampReverb = (((targetReverbVol & 0x7F) - curReverbVol) << 9) / (numSamplesPerUpdate >> 3); + synthState->curReverbVol = targetReverbVol; + } else { + rampReverb = 0; + } + + synthState->curVolLeft = curVolLeft + (rampLeft * (numSamplesPerUpdate >> 3)); + synthState->curVolRight = curVolRight + (rampRight * (numSamplesPerUpdate >> 3)); + + if (sampleState->bitField1.useHaasEffect) { + AudioSynth_ClearBuffer(cmd++, DMEM_HAAS_TEMP, DMEM_1CH_SIZE); + AudioSynth_EnvSetup1(cmd++, curReverbVol * 2, rampReverb, rampLeft, rampRight); + AudioSynth_EnvSetup2(cmd++, curVolLeft, curVolRight); + + switch (haasEffectDelaySide) { + case HAAS_EFFECT_DELAY_LEFT: + // Store the left dry channel in a temp space to be delayed to produce the haas effect + dmemDests = sEnvMixerLeftHaasDmemDests; + break; + + case HAAS_EFFECT_DELAY_RIGHT: + // Store the right dry channel in a temp space to be delayed to produce the haas effect + dmemDests = sEnvMixerRightHaasDmemDests; + break; + + default: // HAAS_EFFECT_DELAY_NONE + dmemDests = sEnvMixerDefaultDmemDests; + break; + } + } else { + aEnvSetup1(cmd++, curReverbVol * 2, rampReverb, rampLeft, rampRight); + aEnvSetup2(cmd++, curVolLeft, curVolRight); + dmemDests = sEnvMixerDefaultDmemDests; + } + + aEnvMixer(cmd++, dmemSrc, numSamplesPerUpdate, (curReverbVolAndFlags & 0x80) >> 7, + sampleState->bitField0.strongReverbRight, sampleState->bitField0.strongReverbLeft, + sampleState->bitField0.strongRight, sampleState->bitField0.strongLeft, dmemDests, sEnvMixerOp); + + return cmd; +} + +Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, + s32 numSamplesToLoad) { + s32 numSamplesAvailable; + s32 harmonicIndexCurAndPrev = sampleState->harmonicIndexCurAndPrev; + s32 samplePosInt = synthState->samplePosInt; + s32 numDuplicates; + + if (sampleState->bitField1.bookOffset != 0) { + // Move the noise wave (that reads compiled assembly as samples) from ram to dmem + AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(numSamplesToLoad * SAMPLE_SIZE), gWaveSamples[8]); + // Offset the address for the samples read by gWaveSamples[8] to the next set of samples + gWaveSamples[8] += numSamplesToLoad * SAMPLE_SIZE; + + return cmd; + } else { + // Move the synthetic wave from ram to dmem + aLoadBuffer(cmd++, sampleState->waveSampleAddr, DMEM_UNCOMPRESSED_NOTE, WAVE_SAMPLE_COUNT * SAMPLE_SIZE); + + // If the harmonic changes, map the offset in the wave from one harmonic to another for continuity + if (harmonicIndexCurAndPrev != 0) { + samplePosInt = (samplePosInt * sNumSamplesPerWavePeriod[harmonicIndexCurAndPrev >> 2]) / + sNumSamplesPerWavePeriod[harmonicIndexCurAndPrev & 3]; + } + + // Offset in the WAVE_SAMPLE_COUNT samples of gWaveSamples to start processing the wave for continuity + samplePosInt = (u32)samplePosInt % WAVE_SAMPLE_COUNT; + // Number of samples in the initial WAVE_SAMPLE_COUNT samples available to be used to process + numSamplesAvailable = WAVE_SAMPLE_COUNT - samplePosInt; + + // Require duplicates if there are more samples to load than available + if (numSamplesToLoad > numSamplesAvailable) { + // Duplicate (copy) the WAVE_SAMPLE_COUNT samples as many times as needed to reach numSamplesToLoad. + // (numSamplesToLoad - numSamplesAvailable) is the number of samples missing. + // Divide by WAVE_SAMPLE_COUNT, rounding up, to get the amount of duplicates + numDuplicates = ((numSamplesToLoad - numSamplesAvailable + WAVE_SAMPLE_COUNT - 1) / WAVE_SAMPLE_COUNT); + if (numDuplicates != 0) { + aDuplicate(cmd++, numDuplicates, DMEM_UNCOMPRESSED_NOTE, + DMEM_UNCOMPRESSED_NOTE + (WAVE_SAMPLE_COUNT * SAMPLE_SIZE)); + } + } + synthState->samplePosInt = samplePosInt; + } + + return cmd; +} + +/** + * The Haas Effect gives directionality to sound by applying a small (< 35ms) delay to either the left or right channel. + * The delay is small enough that the sound is still perceived as one sound, but the channel that is not delayed will + * reach our ear first and give a sense of directionality. The sound is directed towards the opposite side of the delay. + */ +Acmd* AudioSynth_ApplyHaasEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState, s32 size, + s32 flags, s32 haasEffectDelaySide) { + u16 dmemDest; + u16 pitch; + u8 prevHaasEffectDelaySize; + u8 haasEffectDelaySize; + + switch (haasEffectDelaySide) { + case HAAS_EFFECT_DELAY_LEFT: + // Delay the sample on the left channel + // This allows the right channel to be heard first + dmemDest = DMEM_LEFT_CH; + haasEffectDelaySize = sampleState->haasEffectLeftDelaySize; + prevHaasEffectDelaySize = synthState->prevHaasEffectLeftDelaySize; + synthState->prevHaasEffectRightDelaySize = 0; + synthState->prevHaasEffectLeftDelaySize = haasEffectDelaySize; + break; + + case HAAS_EFFECT_DELAY_RIGHT: + // Delay the sample on the right channel + // This allows the left channel to be heard first + dmemDest = DMEM_RIGHT_CH; + haasEffectDelaySize = sampleState->haasEffectRightDelaySize; + prevHaasEffectDelaySize = synthState->prevHaasEffectRightDelaySize; + synthState->prevHaasEffectRightDelaySize = haasEffectDelaySize; + synthState->prevHaasEffectLeftDelaySize = 0; + break; + + default: // HAAS_EFFECT_DELAY_NONE + return cmd; + } + + if (flags != A_INIT) { + // Slightly adjust the sample rate in order to fit a change in sample delay + if (haasEffectDelaySize != prevHaasEffectDelaySize) { + pitch = (((size << 0xF) / 2) - 1) / ((size + haasEffectDelaySize - prevHaasEffectDelaySize - 2) / 2); + aSetBuffer(cmd++, 0, DMEM_HAAS_TEMP, DMEM_TEMP, size + haasEffectDelaySize - prevHaasEffectDelaySize); + aResampleZoh(cmd++, pitch, 0); + } else { + aDMEMMove(cmd++, DMEM_HAAS_TEMP, DMEM_TEMP, size); + } + + if (prevHaasEffectDelaySize != 0) { + aLoadBuffer(cmd++, synthState->synthesisBuffers->haasEffectDelayState, DMEM_HAAS_TEMP, + ALIGN16(prevHaasEffectDelaySize)); + aDMEMMove(cmd++, DMEM_TEMP, DMEM_HAAS_TEMP + prevHaasEffectDelaySize, + size + haasEffectDelaySize - prevHaasEffectDelaySize); + } else { + aDMEMMove(cmd++, DMEM_TEMP, DMEM_HAAS_TEMP, size + haasEffectDelaySize); + } + } else { + // Just apply a delay directly + aDMEMMove(cmd++, DMEM_HAAS_TEMP, DMEM_TEMP, size); + if (haasEffectDelaySize) { // != 0 + aClearBuffer(cmd++, DMEM_HAAS_TEMP, haasEffectDelaySize); + } + aDMEMMove(cmd++, DMEM_TEMP, DMEM_HAAS_TEMP + haasEffectDelaySize, size); + } + + if (haasEffectDelaySize) { // != 0 + // Save excessive samples for next iteration + aSaveBuffer(cmd++, DMEM_HAAS_TEMP + size, synthState->synthesisBuffers->haasEffectDelayState, + ALIGN16(haasEffectDelaySize)); + } + + aAddMixer(cmd++, ALIGN64(size), DMEM_HAAS_TEMP, dmemDest, 0x7FFF); + + return cmd; +} diff --git a/src/code/audio/code_8019AF00.c b/src/code/audio/code_8019AF00.c index 007d7ca856..98be413977 100644 --- a/src/code/audio/code_8019AF00.c +++ b/src/code/audio/code_8019AF00.c @@ -4078,7 +4078,7 @@ void AudioSfx_SetProperties(u8 bankId, u8 entryIndex, u8 channelIndex) { } u32 AudioSfx_SetFreqAndStereoBits(u8 seqScriptValIn, SequenceChannel* channel) { - channel->stereo.asByte = sSfxChannelState[seqScriptValIn].stereoBits; + channel->stereoData.asByte = sSfxChannelState[seqScriptValIn].stereoBits; channel->freqScale = sSfxChannelState[seqScriptValIn].freqScale; channel->changes.s.freqScale = true; diff --git a/src/overlays/actors/ovl_En_Kusa2/z_en_kusa2.c b/src/overlays/actors/ovl_En_Kusa2/z_en_kusa2.c index 4ed5b82a04..fdf3cc9ac5 100644 --- a/src/overlays/actors/ovl_En_Kusa2/z_en_kusa2.c +++ b/src/overlays/actors/ovl_En_Kusa2/z_en_kusa2.c @@ -4,7 +4,6 @@ * Description: Keaton grass */ -#include "prevent_bss_reordering.h" #include "z_en_kusa2.h" #include "objects/gameplay_field_keep/gameplay_field_keep.h" #include "objects/gameplay_keep/gameplay_keep.h" diff --git a/tools/disasm/files.txt b/tools/disasm/files.txt index ffa305cddd..c546c1f69b 100644 --- a/tools/disasm/files.txt +++ b/tools/disasm/files.txt @@ -597,6 +597,7 @@ 0x801D9090 : "audio_sound_params", 0x801DB470 : "code_801A5BD0", 0x801DB4C0 : "code_801A7B10", + 0x801DB4E0 : "audio_init_params", # .rodata section 0x801DBDF0 : "z_en_item00", diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 057170442e..20fa0265c2 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -3478,74 +3478,74 @@ 0x801872FC:("osFlashWriteBuffer",), 0x801873BC:("osFlashWriteArray",), 0x8018752C:("osFlashReadArray",), - 0x801877D0:("func_801877D0",), - 0x80187B64:("func_80187B64",), - 0x80187BEC:("func_80187BEC",), - 0x80187DE8:("func_80187DE8",), - 0x80187E58:("func_80187E58",), - 0x80187F00:("func_80187F00",), - 0x80187FA8:("func_80187FA8",), - 0x80187FB0:("func_80187FB0",), - 0x80187FD0:("func_80187FD0",), - 0x80187FD8:("func_80187FD8",), - 0x80187FE0:("func_80187FE0",), - 0x80187FE8:("func_80187FE8",), - 0x8018801C:("func_8018801C",), - 0x80188024:("func_80188024",), - 0x8018802C:("func_8018802C",), - 0x80188034:("func_80188034",), - 0x80188068:("func_80188068",), - 0x80188070:("func_80188070",), - 0x80188078:("func_80188078",), - 0x801880A4:("func_801880A4",), - 0x801880AC:("func_801880AC",), - 0x801880B4:("func_801880B4",), - 0x801880BC:("func_801880BC",), - 0x801880C4:("func_801880C4",), - 0x801880E8:("func_801880E8",), - 0x8018811C:("func_8018811C",), - 0x80188124:("func_80188124",), - 0x8018814C:("func_8018814C",), - 0x80188174:("func_80188174",), - 0x80188190:("func_80188190",), - 0x80188198:("func_80188198",), - 0x801881A0:("func_801881A0",), - 0x801881A8:("func_801881A8",), - 0x801881C4:("func_801881C4",), - 0x801881F8:("func_801881F8",), - 0x80188224:("func_80188224",), - 0x8018822C:("func_8018822C",), - 0x80188234:("func_80188234",), - 0x8018823C:("func_8018823C",), - 0x80188244:("func_80188244",), - 0x8018824C:("func_8018824C",), - 0x80188254:("func_80188254",), - 0x8018825C:("func_8018825C",), - 0x80188264:("func_80188264",), - 0x80188288:("func_80188288",), - 0x801882A0:("func_801882A0",), - 0x80188304:("func_80188304",), - 0x801884A0:("func_801884A0",), - 0x80188698:("func_80188698",), - 0x8018883C:("func_8018883C",), - 0x801888E4:("func_801888E4",), - 0x801889A4:("func_801889A4",), - 0x80188A50:("func_80188A50",), - 0x80188AFC:("func_80188AFC",), - 0x80188C48:("func_80188C48",), - 0x80188CB4:("func_80188CB4",), - 0x80188D20:("func_80188D20",), - 0x80188D28:("func_80188D28",), - 0x80188D68:("func_80188D68",), - 0x80188DDC:("func_80188DDC",), - 0x80188FBC:("func_80188FBC",), - 0x80189064:("func_80189064",), - 0x80189620:("func_80189620",), - 0x8018A4B4:("func_8018A4B4",), - 0x8018A768:("func_8018A768",), - 0x8018A808:("func_8018A808",), - 0x8018ACC4:("func_8018ACC4",), - 0x8018AE34:("func_8018AE34",), + 0x801877D0:("AudioSynth_AddReverbBufferEntry",), + 0x80187B64:("AudioSynth_SyncSampleStates",), + 0x80187BEC:("AudioSynth_Update",), + 0x80187DE8:("AudioSynth_DisableSampleStates",), + 0x80187E58:("AudioSynth_LoadMixedReverbSamples",), + 0x80187F00:("AudioSynth_SaveMixedReverbSamples",), + 0x80187FA8:("AudioSynth_Noop1",), + 0x80187FB0:("AudioSynth_ClearBuffer",), + 0x80187FD0:("AudioSynth_Noop2",), + 0x80187FD8:("AudioSynth_Noop3",), + 0x80187FE0:("AudioSynth_Noop4",), + 0x80187FE8:("AudioSynth_Mix",), + 0x8018801C:("AudioSynth_Noop5",), + 0x80188024:("AudioSynth_Noop6",), + 0x8018802C:("AudioSynth_Noop7",), + 0x80188034:("AudioSynth_SetBuffer",), + 0x80188068:("AudioSynth_Noop8",), + 0x80188070:("AudioSynth_Noop9",), + 0x80188078:("AudioSynth_DMemMove",), + 0x801880A4:("AudioSynth_Noop10",), + 0x801880AC:("AudioSynth_Noop11",), + 0x801880B4:("AudioSynth_Noop12",), + 0x801880BC:("AudioSynth_Noop13",), + 0x801880C4:("AudioSynth_InterL",), + 0x801880E8:("AudioSynth_EnvSetup1",), + 0x8018811C:("AudioSynth_Noop14",), + 0x80188124:("AudioSynth_LoadBuffer",), + 0x8018814C:("AudioSynth_SaveBuffer",), + 0x80188174:("AudioSynth_EnvSetup2",), + 0x80188190:("AudioSynth_Noop15",), + 0x80188198:("AudioSynth_Noop16",), + 0x801881A0:("AudioSynth_Noop17",), + 0x801881A8:("AudioSynth_S8Dec",), + 0x801881C4:("AudioSynth_HiLoGain",), + 0x801881F8:("AudioSynth_UnkCmd19",), + 0x80188224:("AudioSynth_Noop18",), + 0x8018822C:("AudioSynth_Noop19",), + 0x80188234:("AudioSynth_Noop20",), + 0x8018823C:("AudioSynth_Noop21",), + 0x80188244:("AudioSynth_Noop22",), + 0x8018824C:("AudioSynth_Noop23",), + 0x80188254:("AudioSynth_Noop24",), + 0x8018825C:("AudioSynth_Noop25",), + 0x80188264:("AudioSynth_LoadFilterBuffer",), + 0x80188288:("AudioSynth_LoadFilterSize",), + 0x801882A0:("AudioSynth_LeakReverb",), + 0x80188304:("AudioSynth_LoadDownsampledReverbSamples",), + 0x801884A0:("AudioSynth_SaveResampledReverbSamples",), + 0x80188698:("AudioSynth_LoadResampledReverbSamples",), + 0x8018883C:("AudioSynth_FilterReverb",), + 0x801888E4:("AudioSynth_MixOtherReverbIndex",), + 0x801889A4:("AudioSynth_LoadDefaultReverbSamples",), + 0x80188A50:("AudioSynth_LoadSubReverbSamples",), + 0x80188AFC:("AudioSynth_SaveResampledReverbSamplesImpl",), + 0x80188C48:("AudioSynth_LoadReverbSamplesImpl",), + 0x80188CB4:("AudioSynth_SaveReverbSamplesImpl",), + 0x80188D20:("AudioSynth_Noop26",), + 0x80188D28:("AudioSynth_LoadSubReverbSamplesWithoutDownsample",), + 0x80188D68:("AudioSynth_LoadReverbSamples",), + 0x80188DDC:("AudioSynth_SaveReverbSamples",), + 0x80188FBC:("AudioSynth_SaveSubReverbSamples",), + 0x80189064:("AudioSynth_ProcessSamples",), + 0x80189620:("AudioSynth_ProcessSample",), + 0x8018A4B4:("AudioSynth_ApplySurroundEffect",), + 0x8018A768:("AudioSynth_FinalResample",), + 0x8018A808:("AudioSynth_ProcessEnvelope",), + 0x8018ACC4:("AudioSynth_LoadWaveSamples",), + 0x8018AE34:("AudioSynth_ApplyHaasEffect",), 0x8018B0F0:("AudioHeap_CalculateAdsrDecay",), 0x8018B10C:("AudioHeap_InitAdsrDecayTable",), 0x8018B250:("AudioHeap_ResetLoadStatus",), @@ -3726,7 +3726,7 @@ 0x80194804:("func_80194804",), 0x80194840:("func_80194840",), 0x801948B0:("func_801948B0",), - 0x80194930:("AudioPlayback_InitNoteSub",), + 0x80194930:("AudioPlayback_InitSampleState",), 0x80194DB0:("AudioPlayback_NoteSetResamplingRate",), 0x80194E60:("AudioPlayback_NoteInit",), 0x80194F20:("AudioPlayback_NoteDisable",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index a0b3692644..5c8147eefb 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -2220,11 +2220,11 @@ 0x801D57B4:("gDefaultShortNoteVelocityTable","UNK_TYPE1","",0x1), 0x801D57C4:("gDefaultShortNoteGateTimeTable","UNK_TYPE1","",0x1), 0x801D57D4:("gDefaultEnvelope","UNK_TYPE1","",0x1), - 0x801D57E4:("gZeroNoteSub","UNK_TYPE4","",0x4), - 0x801D5804:("gDefaultNoteSub","UNK_TYPE4","",0x4), - 0x801D5824:("gHeadsetPanQuantization","u16","[64]",0x80), + 0x801D57E4:("gZeroedSampleState","UNK_TYPE4","",0x4), + 0x801D5804:("gDefaultSampleState","UNK_TYPE4","",0x4), + 0x801D5824:("gHaasEffectDelaySize","u16","[64]",0x80), 0x801D58A4:("D_801D58A4","s32","",0x4), - 0x801D58A8:("D_801D58A8","s16","[64]",0x80), + 0x801D58A8:("gInvalidAdpcmCodeBook","s16","[64]",0x80), 0x801D5928:("gHeadsetPanVolume","f32","[128]",0x200), 0x801D5B28:("gStereoPanVolume","f32","[128]",0x200), 0x801D5D28:("gDefaultPanVolume","f32","[128]",0x200), @@ -2411,7 +2411,7 @@ 0x801DB870:("D_801DB870","UNK_TYPE1","",0x1), 0x801DB8B8:("D_801DB8B8","UNK_TYPE1","",0x1), 0x801DB900:("D_801DB900","UNK_TYPE1","",0x1), - 0x801DB930:("D_801DB930","UNK_PTR","",0x4), + 0x801DB930:("gReverbSettingsTable","UNK_PTR","",0x4), 0x801DB958:("gAudioSpecs","AudioSpec","[21]",0x498), 0x801DBDF0:("D_801DBDF0","f32","",0x4), 0x801DBDF4:("jtbl_801DBDF4","UNK_PTR","",0x4), @@ -4354,10 +4354,10 @@ 0x80200BCE:("D_80200BCE","UNK_TYPE1","",0x1), 0x80200BD0:("D_80200BD0","UNK_TYPE1","",0x1), 0x80200C70:("gAudioContext","AudioContext","",0x81F8), - 0x80208E68:("D_80208E68","UNK_TYPE4","",0x4), - 0x80208E6C:("D_80208E6C","UNK_TYPE4","",0x4), - 0x80208E70:("D_80208E70","UNK_TYPE4","",0x4), - 0x80208E74:("D_80208E74","UNK_TYPE4","",0x4), + 0x80208E68:("gCustomAudioUpdateFunction","UNK_TYPE4","",0x4), + 0x80208E6C:("gCustomAudioSeqFunction","UNK_TYPE4","",0x4), + 0x80208E70:("gCustomAudioReverbFunction","UNK_TYPE4","",0x4), + 0x80208E74:("gCustomAudioSynthFunction","UNK_TYPE4","",0x4), 0x80208E90:("sJpegBitStreamPtr","UNK_TYPE1","",0x1), 0x80208E94:("sJpegBitStreamByteIdx","UNK_TYPE1","",0x1), 0x80208E98:("sJpegBitStreamBitIdx","UNK_TYPE1","",0x1), diff --git a/tools/sizes/code_functions.csv b/tools/sizes/code_functions.csv index f64c45241e..9db0c0308e 100644 --- a/tools/sizes/code_functions.csv +++ b/tools/sizes/code_functions.csv @@ -2996,74 +2996,74 @@ asm/non_matchings/code/osFlash/func_80187284.s,func_80187284,0x80187284,0x1E asm/non_matchings/code/osFlash/func_801872FC.s,func_801872FC,0x801872FC,0x30 asm/non_matchings/code/osFlash/func_801873BC.s,func_801873BC,0x801873BC,0x5C asm/non_matchings/code/osFlash/func_8018752C.s,func_8018752C,0x8018752C,0x9D -asm/non_matchings/code/audio_synthesis/func_801877D0.s,func_801877D0,0x801877D0,0xE5 -asm/non_matchings/code/audio_synthesis/func_80187B64.s,func_80187B64,0x80187B64,0x22 -asm/non_matchings/code/audio_synthesis/func_80187BEC.s,func_80187BEC,0x80187BEC,0x7F -asm/non_matchings/code/audio_synthesis/func_80187DE8.s,func_80187DE8,0x80187DE8,0x1C -asm/non_matchings/code/audio_synthesis/func_80187E58.s,func_80187E58,0x80187E58,0x2A -asm/non_matchings/code/audio_synthesis/func_80187F00.s,func_80187F00,0x80187F00,0x2A -asm/non_matchings/code/audio_synthesis/func_80187FA8.s,func_80187FA8,0x80187FA8,0x2 -asm/non_matchings/code/audio_synthesis/func_80187FB0.s,func_80187FB0,0x80187FB0,0x8 -asm/non_matchings/code/audio_synthesis/func_80187FD0.s,func_80187FD0,0x80187FD0,0x2 -asm/non_matchings/code/audio_synthesis/func_80187FD8.s,func_80187FD8,0x80187FD8,0x2 -asm/non_matchings/code/audio_synthesis/func_80187FE0.s,func_80187FE0,0x80187FE0,0x2 -asm/non_matchings/code/audio_synthesis/func_80187FE8.s,func_80187FE8,0x80187FE8,0xD -asm/non_matchings/code/audio_synthesis/func_8018801C.s,func_8018801C,0x8018801C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188024.s,func_80188024,0x80188024,0x2 -asm/non_matchings/code/audio_synthesis/func_8018802C.s,func_8018802C,0x8018802C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188034.s,func_80188034,0x80188034,0xD -asm/non_matchings/code/audio_synthesis/func_80188068.s,func_80188068,0x80188068,0x2 -asm/non_matchings/code/audio_synthesis/func_80188070.s,func_80188070,0x80188070,0x2 -asm/non_matchings/code/audio_synthesis/func_80188078.s,func_80188078,0x80188078,0xB -asm/non_matchings/code/audio_synthesis/func_801880A4.s,func_801880A4,0x801880A4,0x2 -asm/non_matchings/code/audio_synthesis/func_801880AC.s,func_801880AC,0x801880AC,0x2 -asm/non_matchings/code/audio_synthesis/func_801880B4.s,func_801880B4,0x801880B4,0x2 -asm/non_matchings/code/audio_synthesis/func_801880BC.s,func_801880BC,0x801880BC,0x2 -asm/non_matchings/code/audio_synthesis/func_801880C4.s,func_801880C4,0x801880C4,0x9 -asm/non_matchings/code/audio_synthesis/func_801880E8.s,func_801880E8,0x801880E8,0xD -asm/non_matchings/code/audio_synthesis/func_8018811C.s,func_8018811C,0x8018811C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188124.s,func_80188124,0x80188124,0xA -asm/non_matchings/code/audio_synthesis/func_8018814C.s,func_8018814C,0x8018814C,0xA -asm/non_matchings/code/audio_synthesis/func_80188174.s,func_80188174,0x80188174,0x7 -asm/non_matchings/code/audio_synthesis/func_80188190.s,func_80188190,0x80188190,0x2 -asm/non_matchings/code/audio_synthesis/func_80188198.s,func_80188198,0x80188198,0x2 -asm/non_matchings/code/audio_synthesis/func_801881A0.s,func_801881A0,0x801881A0,0x2 -asm/non_matchings/code/audio_synthesis/func_801881A8.s,func_801881A8,0x801881A8,0x7 -asm/non_matchings/code/audio_synthesis/func_801881C4.s,func_801881C4,0x801881C4,0xD -asm/non_matchings/code/audio_synthesis/func_801881F8.s,func_801881F8,0x801881F8,0xB -asm/non_matchings/code/audio_synthesis/func_80188224.s,func_80188224,0x80188224,0x2 -asm/non_matchings/code/audio_synthesis/func_8018822C.s,func_8018822C,0x8018822C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188234.s,func_80188234,0x80188234,0x2 -asm/non_matchings/code/audio_synthesis/func_8018823C.s,func_8018823C,0x8018823C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188244.s,func_80188244,0x80188244,0x2 -asm/non_matchings/code/audio_synthesis/func_8018824C.s,func_8018824C,0x8018824C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188254.s,func_80188254,0x80188254,0x2 -asm/non_matchings/code/audio_synthesis/func_8018825C.s,func_8018825C,0x8018825C,0x2 -asm/non_matchings/code/audio_synthesis/func_80188264.s,func_80188264,0x80188264,0x9 -asm/non_matchings/code/audio_synthesis/func_80188288.s,func_80188288,0x80188288,0x6 -asm/non_matchings/code/audio_synthesis/func_801882A0.s,func_801882A0,0x801882A0,0x19 -asm/non_matchings/code/audio_synthesis/func_80188304.s,func_80188304,0x80188304,0x67 -asm/non_matchings/code/audio_synthesis/func_801884A0.s,func_801884A0,0x801884A0,0x7E -asm/non_matchings/code/audio_synthesis/func_80188698.s,func_80188698,0x80188698,0x69 -asm/non_matchings/code/audio_synthesis/func_8018883C.s,func_8018883C,0x8018883C,0x2A -asm/non_matchings/code/audio_synthesis/func_801888E4.s,func_801888E4,0x801888E4,0x30 -asm/non_matchings/code/audio_synthesis/func_801889A4.s,func_801889A4,0x801889A4,0x2B -asm/non_matchings/code/audio_synthesis/func_80188A50.s,func_80188A50,0x80188A50,0x2B -asm/non_matchings/code/audio_synthesis/func_80188AFC.s,func_80188AFC,0x80188AFC,0x53 -asm/non_matchings/code/audio_synthesis/func_80188C48.s,func_80188C48,0x80188C48,0x1B -asm/non_matchings/code/audio_synthesis/func_80188CB4.s,func_80188CB4,0x80188CB4,0x1B -asm/non_matchings/code/audio_synthesis/func_80188D20.s,func_80188D20,0x80188D20,0x2 -asm/non_matchings/code/audio_synthesis/func_80188D28.s,func_80188D28,0x80188D28,0x10 -asm/non_matchings/code/audio_synthesis/func_80188D68.s,func_80188D68,0x80188D68,0x1D -asm/non_matchings/code/audio_synthesis/func_80188DDC.s,func_80188DDC,0x80188DDC,0x78 -asm/non_matchings/code/audio_synthesis/func_80188FBC.s,func_80188FBC,0x80188FBC,0x2A -asm/non_matchings/code/audio_synthesis/func_80189064.s,func_80189064,0x80189064,0x16F -asm/non_matchings/code/audio_synthesis/func_80189620.s,func_80189620,0x80189620,0x3A5 -asm/non_matchings/code/audio_synthesis/func_8018A4B4.s,func_8018A4B4,0x8018A4B4,0xAD -asm/non_matchings/code/audio_synthesis/func_8018A768.s,func_8018A768,0x8018A768,0x28 -asm/non_matchings/code/audio_synthesis/func_8018A808.s,func_8018A808,0x8018A808,0x12F -asm/non_matchings/code/audio_synthesis/func_8018ACC4.s,func_8018ACC4,0x8018ACC4,0x5C -asm/non_matchings/code/audio_synthesis/func_8018AE34.s,func_8018AE34,0x8018AE34,0xAF +asm/non_matchings/code/audio_synthesis/AudioSynth_AddReverbBufferEntry.s,AudioSynth_AddReverbBufferEntry,0x801877D0,0xE5 +asm/non_matchings/code/audio_synthesis/AudioSynth_SyncSampleStates.s,AudioSynth_SyncSampleStates,0x80187B64,0x22 +asm/non_matchings/code/audio_synthesis/AudioSynth_Update.s,AudioSynth_Update,0x80187BEC,0x7F +asm/non_matchings/code/audio_synthesis/AudioSynth_DisableSampleStates.s,AudioSynth_DisableSampleStates,0x80187DE8,0x1C +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadMixedReverbSamples.s,AudioSynth_LoadMixedReverbSamples,0x80187E58,0x2A +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveMixedReverbSamples.s,AudioSynth_SaveMixedReverbSamples,0x80187F00,0x2A +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop1.s,AudioSynth_Noop1,0x80187FA8,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_ClearBuffer.s,AudioSynth_ClearBuffer,0x80187FB0,0x8 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop2.s,AudioSynth_Noop2,0x80187FD0,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop3.s,AudioSynth_Noop3,0x80187FD8,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop4.s,AudioSynth_Noop4,0x80187FE0,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Mix.s,AudioSynth_Mix,0x80187FE8,0xD +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop5.s,AudioSynth_Noop5,0x8018801C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop6.s,AudioSynth_Noop6,0x80188024,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop7.s,AudioSynth_Noop7,0x8018802C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_SetBuffer.s,AudioSynth_SetBuffer,0x80188034,0xD +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop8.s,AudioSynth_Noop8,0x80188068,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop9.s,AudioSynth_Noop9,0x80188070,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_DMemMove.s,AudioSynth_DMemMove,0x80188078,0xB +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop10.s,AudioSynth_Noop10,0x801880A4,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop11.s,AudioSynth_Noop11,0x801880AC,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop12.s,AudioSynth_Noop12,0x801880B4,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop13.s,AudioSynth_Noop13,0x801880BC,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_InterL.s,AudioSynth_InterL,0x801880C4,0x9 +asm/non_matchings/code/audio_synthesis/AudioSynth_EnvSetup1.s,AudioSynth_EnvSetup1,0x801880E8,0xD +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop14.s,AudioSynth_Noop14,0x8018811C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadBuffer.s,AudioSynth_LoadBuffer,0x80188124,0xA +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveBuffer.s,AudioSynth_SaveBuffer,0x8018814C,0xA +asm/non_matchings/code/audio_synthesis/AudioSynth_EnvSetup2.s,AudioSynth_EnvSetup2,0x80188174,0x7 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop15.s,AudioSynth_Noop15,0x80188190,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop16.s,AudioSynth_Noop16,0x80188198,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop17.s,AudioSynth_Noop17,0x801881A0,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_S8Dec.s,AudioSynth_S8Dec,0x801881A8,0x7 +asm/non_matchings/code/audio_synthesis/AudioSynth_HiLoGain.s,AudioSynth_HiLoGain,0x801881C4,0xD +asm/non_matchings/code/audio_synthesis/AudioSynth_UnkCmd19.s,AudioSynth_UnkCmd19,0x801881F8,0xB +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop18.s,AudioSynth_Noop18,0x80188224,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop19.s,AudioSynth_Noop19,0x8018822C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop20.s,AudioSynth_Noop20,0x80188234,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop21.s,AudioSynth_Noop21,0x8018823C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop22.s,AudioSynth_Noop22,0x80188244,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop23.s,AudioSynth_Noop23,0x8018824C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop24.s,AudioSynth_Noop24,0x80188254,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop25.s,AudioSynth_Noop25,0x8018825C,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadFilterBuffer.s,AudioSynth_LoadFilterBuffer,0x80188264,0x9 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadFilterSize.s,AudioSynth_LoadFilterSize,0x80188288,0x6 +asm/non_matchings/code/audio_synthesis/AudioSynth_LeakReverb.s,AudioSynth_LeakReverb,0x801882A0,0x19 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadDownsampledReverbSamples.s,AudioSynth_LoadDownsampledReverbSamples,0x80188304,0x67 +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveResampledReverbSamples.s,AudioSynth_SaveResampledReverbSamples,0x801884A0,0x7E +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadResampledReverbSamples.s,AudioSynth_LoadResampledReverbSamples,0x80188698,0x69 +asm/non_matchings/code/audio_synthesis/AudioSynth_FilterReverb.s,AudioSynth_FilterReverb,0x8018883C,0x2A +asm/non_matchings/code/audio_synthesis/AudioSynth_MixOtherReverbIndex.s,AudioSynth_MixOtherReverbIndex,0x801888E4,0x30 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadDefaultReverbSamples.s,AudioSynth_LoadDefaultReverbSamples,0x801889A4,0x2B +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadSubReverbSamples.s,AudioSynth_LoadSubReverbSamples,0x80188A50,0x2B +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveResampledReverbSamplesImpl.s,AudioSynth_SaveResampledReverbSamplesImpl,0x80188AFC,0x53 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadReverbSamplesImpl.s,AudioSynth_LoadReverbSamplesImpl,0x80188C48,0x1B +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveReverbSamplesImpl.s,AudioSynth_SaveReverbSamplesImpl,0x80188CB4,0x1B +asm/non_matchings/code/audio_synthesis/AudioSynth_Noop26.s,AudioSynth_Noop26,0x80188D20,0x2 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadSubReverbSamplesWithoutDownsample.s,AudioSynth_LoadSubReverbSamplesWithoutDownsample,0x80188D28,0x10 +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadReverbSamples.s,AudioSynth_LoadReverbSamples,0x80188D68,0x1D +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveReverbSamples.s,AudioSynth_SaveReverbSamples,0x80188DDC,0x78 +asm/non_matchings/code/audio_synthesis/AudioSynth_SaveSubReverbSamples.s,AudioSynth_SaveSubReverbSamples,0x80188FBC,0x2A +asm/non_matchings/code/audio_synthesis/AudioSynth_ProcessSamples.s,AudioSynth_ProcessSamples,0x80189064,0x16F +asm/non_matchings/code/audio_synthesis/AudioSynth_ProcessSample.s,AudioSynth_ProcessSample,0x80189620,0x3A5 +asm/non_matchings/code/audio_synthesis/AudioSynth_ApplySurroundEffect.s,AudioSynth_ApplySurroundEffect,0x8018A4B4,0xAD +asm/non_matchings/code/audio_synthesis/AudioSynth_FinalResample.s,AudioSynth_FinalResample,0x8018A768,0x28 +asm/non_matchings/code/audio_synthesis/AudioSynth_ProcessEnvelope.s,AudioSynth_ProcessEnvelope,0x8018A808,0x12F +asm/non_matchings/code/audio_synthesis/AudioSynth_LoadWaveSamples.s,AudioSynth_LoadWaveSamples,0x8018ACC4,0x5C +asm/non_matchings/code/audio_synthesis/AudioSynth_ApplyHaasEffect.s,AudioSynth_ApplyHaasEffect,0x8018AE34,0xAF asm/non_matchings/code/audio_heap/AudioHeap_ResetLoadStatus.s,AudioHeap_ResetLoadStatus,0x8018B250,0x32 asm/non_matchings/code/audio_heap/AudioHeap_DiscardFont.s,AudioHeap_DiscardFont,0x8018B318,0x39 asm/non_matchings/code/audio_heap/AudioHeap_ReleaseNotesForFont.s,AudioHeap_ReleaseNotesForFont,0x8018B3FC,0x1E @@ -3242,7 +3242,7 @@ asm/non_matchings/code/code_80194710/osAiSetNextBuffer.s,osAiSetNextBuffer,0x801 asm/non_matchings/code/code_80194710/func_80194804.s,func_80194804,0x80194804,0xF asm/non_matchings/code/code_80194710/func_80194840.s,func_80194840,0x80194840,0x1C asm/non_matchings/code/code_80194710/func_801948B0.s,func_801948B0,0x801948B0,0x20 -asm/non_matchings/code/audio_playback/AudioPlayback_InitNoteSub.s,AudioPlayback_InitNoteSub,0x80194930,0x120 +asm/non_matchings/code/audio_playback/AudioPlayback_InitSampleState.s,AudioPlayback_InitSampleState,0x80194930,0x120 asm/non_matchings/code/audio_playback/AudioPlayback_NoteSetResamplingRate.s,AudioPlayback_NoteSetResamplingRate,0x80194DB0,0x2C asm/non_matchings/code/audio_playback/AudioPlayback_NoteInit.s,AudioPlayback_NoteInit,0x80194E60,0x30 asm/non_matchings/code/audio_playback/AudioPlayback_NoteDisable.s,AudioPlayback_NoteDisable,0x80194F20,0x19