From 00b98027dbb1898f477aebbd9464b37c6f1a80f0 Mon Sep 17 00:00:00 2001 From: engineer124 <47598039+engineer124@users.noreply.github.com> Date: Mon, 20 Jun 2022 21:55:01 -0400 Subject: [PATCH] Synthetic Waves Documentation (#1256) * Synthetic wave documentation * Better docs * harmonicIndex * More * typo * Complete the abi buffer docs * Small change * Revert change * PR suggestions * Missed one * PR Feedback * Better documents * Well that was a silly copy-pasta mistake * Typo * Another comment * Plural * Make it more block-like * Capitalization * Add comments for gWaveSamples[8] * Adjust comment * More PR Suggestions * PR Suggestions * missed a phrasing * PR Suggestions * Update include/z64audio.h Co-authored-by: Dragorn421 Co-authored-by: Dragorn421 --- include/ultra64/abi.h | 90 ++++++++++++++++++++++------------ include/z64audio.h | 9 ++-- src/code/audio_playback.c | 58 +++++++++++++--------- src/code/audio_synthesis.c | 99 +++++++++++++++++++++++--------------- src/code/code_800E4FE0.c | 10 ++-- 5 files changed, 168 insertions(+), 98 deletions(-) diff --git a/include/ultra64/abi.h b/include/ultra64/abi.h index 53f4a9ec36..a71beb9e79 100644 --- a/include/ultra64/abi.h +++ b/include/ultra64/abi.h @@ -294,13 +294,20 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (u32)(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 = (u32)(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) \ { \ @@ -330,14 +337,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 = (u32)(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) \ { \ @@ -366,14 +380,21 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (u32)(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 = (u32)(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) \ { \ @@ -461,14 +482,21 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (u32)(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/z64audio.h b/include/z64audio.h index 7cf081aa42..40e2757ee7 100644 --- a/include/z64audio.h +++ b/include/z64audio.h @@ -18,6 +18,9 @@ #define AIBUF_LEN 0x580 +// Must be the same amount of samples as copied by aDuplicate() (audio microcode) +#define WAVE_SAMPLE_COUNT 64 + #define AUDIO_RELOCATED_ADDRESS_START K0BASE typedef enum { @@ -493,7 +496,7 @@ typedef struct { typedef struct { /* 0x00 */ u8 priority; /* 0x01 */ u8 waveId; - /* 0x02 */ u8 sampleCountIndex; + /* 0x02 */ u8 harmonicIndex; // the harmonic index for the synthetic wave contained in gWaveSamples (also matches the base 2 logarithm of the harmonic order) /* 0x03 */ u8 fontId; /* 0x04 */ u8 unk_04; /* 0x05 */ u8 stereoHeadsetEffects; @@ -531,7 +534,7 @@ typedef struct { /* 0x03 */ u8 headsetPanRight; /* 0x04 */ u8 headsetPanLeft; /* 0x05 */ u8 reverbVol; - /* 0x06 */ u8 unk_06; + /* 0x06 */ u8 harmonicIndexCurAndPrev; // bits 3..2 store curHarmonicIndex, bits 1..0 store prevHarmonicIndex /* 0x07 */ u8 unk_07; /* 0x08 */ u16 targetVolLeft; /* 0x0A */ u16 targetVolRight; @@ -539,7 +542,7 @@ typedef struct { /* 0x0E */ u16 unk_0E; /* 0x10 */ union { TunedSample* tunedSample; - s16* samples; // used for synthetic waves + s16* waveSampleAddr; // used for synthetic waves }; /* 0x14 */ s16* filter; /* 0x18 */ char pad_18[0x8]; diff --git a/src/code/audio_playback.c b/src/code/audio_playback.c index 91fbaa2d83..01f47afd01 100644 --- a/src/code/audio_playback.c +++ b/src/code/audio_playback.c @@ -19,8 +19,8 @@ void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) { sub->bitField0 = note->noteSubEu.bitField0; sub->bitField1 = note->noteSubEu.bitField1; - sub->samples = note->noteSubEu.samples; - sub->unk_06 = note->noteSubEu.unk_06; + sub->waveSampleAddr = note->noteSubEu.waveSampleAddr; + sub->harmonicIndexCurAndPrev = note->noteSubEu.harmonicIndexCurAndPrev; Audio_NoteSetResamplingRate(sub, attrs->frequency); @@ -529,10 +529,18 @@ void Audio_SeqLayerNoteRelease(SequenceLayer* layer) { Audio_SeqLayerDecayRelease(layer, ADSR_STATE_RELEASE); } +/** + * Extract the synthetic wave to use from gWaveSamples and update corresponding frequencies + * + * @param note + * @param layer + * @param waveId the index of the type of synthetic wave to use, offset by 128 + * @return harmonicIndex, the index of the harmonic for the synthetic wave contained in gWaveSamples + */ s32 Audio_BuildSyntheticWave(Note* note, SequenceLayer* layer, s32 waveId) { f32 freqScale; - f32 ratio; - u8 sampleCountIndex; + f32 freqRatio; + u8 harmonicIndex; if (waveId < 128) { waveId = 128; @@ -542,42 +550,48 @@ s32 Audio_BuildSyntheticWave(Note* note, SequenceLayer* layer, s32 waveId) { if (layer->portamento.mode != 0 && 0.0f < layer->portamento.extent) { freqScale *= (layer->portamento.extent + 1.0f); } + + // Map frequency to the harmonic to use from gWaveSamples if (freqScale < 0.99999f) { - sampleCountIndex = 0; - ratio = 1.0465f; + harmonicIndex = 0; + freqRatio = 1.0465f; } else if (freqScale < 1.99999f) { - sampleCountIndex = 1; - ratio = 0.52325f; + harmonicIndex = 1; + freqRatio = 1.0465f / 2; } else if (freqScale < 3.99999f) { - sampleCountIndex = 2; - ratio = 0.26263f; + harmonicIndex = 2; + freqRatio = 1.0465f / 4 + 1.005E-3; } else { - sampleCountIndex = 3; - ratio = 0.13081f; + harmonicIndex = 3; + freqRatio = 1.0465f / 8 - 2.5E-6; } - layer->freqScale *= ratio; + + // Update results + layer->freqScale *= freqRatio; note->playbackState.waveId = waveId; - note->playbackState.sampleCountIndex = sampleCountIndex; + note->playbackState.harmonicIndex = harmonicIndex; - note->noteSubEu.samples = &gWaveSamples[waveId - 128][sampleCountIndex * 64]; + // 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]; - return sampleCountIndex; + return harmonicIndex; } void Audio_InitSyntheticWave(Note* note, SequenceLayer* layer) { - s32 sampleCountIndex; - s32 waveSampleCountIndex; + s32 prevHarmonicIndex; + s32 curHarmonicIndex; s32 waveId = layer->instOrWave; if (waveId == 0xFF) { waveId = layer->channel->instOrWave; } - sampleCountIndex = note->playbackState.sampleCountIndex; - waveSampleCountIndex = Audio_BuildSyntheticWave(note, layer, waveId); + prevHarmonicIndex = note->playbackState.harmonicIndex; + curHarmonicIndex = Audio_BuildSyntheticWave(note, layer, waveId); - if (waveSampleCountIndex != sampleCountIndex) { - note->noteSubEu.unk_06 = waveSampleCountIndex * 4 + sampleCountIndex; + if (curHarmonicIndex != prevHarmonicIndex) { + note->noteSubEu.harmonicIndexCurAndPrev = (curHarmonicIndex << 2) + prevHarmonicIndex; } } diff --git a/src/code/audio_synthesis.c b/src/code/audio_synthesis.c index 0e8e332f5c..2cebdef855 100644 --- a/src/code/audio_synthesis.c +++ b/src/code/audio_synthesis.c @@ -23,7 +23,7 @@ Acmd* AudioSynth_SaveRingBufferPart(Acmd* cmd, u16 dmem, u16 startPos, s32 lengt Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updateIndex); Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updateIndex); -Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 nSamplesToLoad); +Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 numSamplesToLoad); Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 bufLen, s32 flags, s32 side); Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 aiBufLen, @@ -40,7 +40,12 @@ u16 D_801304B0[] = { 0x7FFF, 0xD001, 0x3FFF, 0xF001, 0x5FFF, 0x9001, 0x7FFF, 0x8001, }; -u8 D_801304C0[] = { 0x40, 0x20, 0x10, 0x8 }; +u8 sNumSamplesPerWavePeriod[] = { + WAVE_SAMPLE_COUNT, // 1st harmonic + WAVE_SAMPLE_COUNT / 2, // 2nd harmonic + WAVE_SAMPLE_COUNT / 4, // 4th harmonic + WAVE_SAMPLE_COUNT / 8, // 8th harmonic +}; void AudioSynth_InitNextRingBuf(s32 chunkLen, s32 updateIndex, s32 reverbIndex) { ReverbRingBufferItem* bufItem; @@ -129,7 +134,7 @@ void func_800DB03C(s32 updateIndex) { subEu2->bitField0.enabled = false; } - subEu->unk_06 = 0; + subEu->harmonicIndexCurAndPrev = 0; } } @@ -326,8 +331,8 @@ Acmd* AudioSynth_MaybeMixRingBuffer1(Acmd* cmd, SynthesisReverb* reverb, s32 upd void func_800DBB94(void) { } -void AudioSynth_ClearBuffer(Acmd* cmd, s32 arg1, s32 arg2) { - aClearBuffer(cmd, arg1, arg2); +void AudioSynth_ClearBuffer(Acmd* cmd, s32 dmem, s32 size) { + aClearBuffer(cmd, dmem, size); } void func_800DBBBC(void) { @@ -392,12 +397,12 @@ void AudioSynth_EnvSetup1(Acmd* cmd, s32 arg1, s32 arg2, s32 arg3, s32 arg4) { void func_800DBD08(void) { } -void AudioSynth_LoadBuffer(Acmd* cmd, s32 arg1, s32 arg2, void* arg3) { - aLoadBuffer(cmd, arg3, arg1, arg2); +void AudioSynth_LoadBuffer(Acmd* cmd, s32 dmemDest, s32 size, void* addrSrc) { + aLoadBuffer(cmd, addrSrc, dmemDest, size); } -void AudioSynth_SaveBuffer(Acmd* cmd, s32 arg1, s32 arg2, void* arg3) { - aSaveBuffer(cmd, arg1, arg3, arg2); +void AudioSynth_SaveBuffer(Acmd* cmd, s32 dmemSrc, s32 size, void* addrDest) { + aSaveBuffer(cmd, dmemSrc, addrDest, size); } void AudioSynth_EnvSetup2(Acmd* cmd, s32 volLeft, s32 volRight) { @@ -722,12 +727,12 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS s32 sampleDataStartPad; s32 side; s32 resampledTempLen; - u16 noteSamplesDmemAddrBeforeResampling; + u16 sampleDmemBeforeResampling; s32 sampleDataOffset; s32 thing; s32 s5; Note* note; - u32 nSamplesToLoad; + u32 numSamplesToLoad; u16 unk7; u16 unkE; s16* filter; @@ -761,7 +766,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint; nParts = noteSubEu->bitField1.hasTwoParts + 1; samplesLenFixedPoint = (resamplingRateFixedPoint * aiBufLen * 2) + synthState->samplePosFrac; - nSamplesToLoad = samplesLenFixedPoint >> 16; + numSamplesToLoad = samplesLenFixedPoint >> 16; synthState->samplePosFrac = samplesLenFixedPoint & 0xFFFF; // Partially-optimized out no-op ifs required for matching. SM64 decomp @@ -774,9 +779,9 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS synthState->numParts = nParts; if (noteSubEu->bitField1.isSyntheticWave) { - cmd = AudioSynth_LoadWaveSamples(cmd, noteSubEu, synthState, nSamplesToLoad); - noteSamplesDmemAddrBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * 2); - synthState->samplePosInt += nSamplesToLoad; + cmd = AudioSynth_LoadWaveSamples(cmd, noteSubEu, synthState, numSamplesToLoad); + sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * (s32)sizeof(s16)); + synthState->samplePosInt += numSamplesToLoad; } else { sample = noteSubEu->tunedSample->sample; loopInfo = sample->loop; @@ -789,11 +794,11 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS s5 = 0; if (nParts == 1) { - samplesLenAdjusted = nSamplesToLoad; - } else if (nSamplesToLoad & 1) { - samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2); + samplesLenAdjusted = numSamplesToLoad; + } else if (numSamplesToLoad & 1) { + samplesLenAdjusted = (numSamplesToLoad & ~1) + (curPart * 2); } else { - samplesLenAdjusted = nSamplesToLoad; + samplesLenAdjusted = numSamplesToLoad; } if (sample->codec == CODEC_ADPCM || sample->codec == CODEC_SMALL_ADPCM) { @@ -1004,7 +1009,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS switch (nParts) { case 1: - noteSamplesDmemAddrBeforeResampling = DMEM_UNCOMPRESSED_NOTE + skipBytes; + sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + skipBytes; break; case 2: @@ -1013,9 +1018,9 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS AudioSynth_InterL(cmd++, DMEM_UNCOMPRESSED_NOTE + skipBytes, DMEM_TEMP + 0x20, ALIGN8(samplesLenAdjusted / 2)); resampledTempLen = samplesLenAdjusted; - noteSamplesDmemAddrBeforeResampling = DMEM_TEMP + 0x20; + sampleDmemBeforeResampling = DMEM_TEMP + 0x20; if (finished) { - AudioSynth_ClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen, + AudioSynth_ClearBuffer(cmd++, sampleDmemBeforeResampling + resampledTempLen, samplesLenAdjusted + 0x10); } break; @@ -1038,8 +1043,8 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS flags = A_INIT; } - cmd = AudioSynth_FinalResample(cmd, synthState, aiBufLen * 2, resamplingRateFixedPoint, - noteSamplesDmemAddrBeforeResampling, flags); + cmd = AudioSynth_FinalResample(cmd, synthState, aiBufLen * 2, resamplingRateFixedPoint, sampleDmemBeforeResampling, + flags); if (bookOffset == 3) { AudioSynth_UnkCmd19(cmd++, DMEM_TEMP, DMEM_TEMP, aiBufLen * 2, 0); } @@ -1184,27 +1189,43 @@ Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS return cmd; } -Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 nSamplesToLoad) { - s32 temp_v0; - s32 unk6 = noteSubEu->unk_06; +Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, + s32 numSamplesToLoad) { + s32 numSamplesAvail; + s32 harmonicIndexCurAndPrev = noteSubEu->harmonicIndexCurAndPrev; s32 samplePosInt = synthState->samplePosInt; - s32 repeats; + s32 numDuplicates; if (noteSubEu->bitField1.bookOffset != 0) { - AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2), gWaveSamples[8]); - gWaveSamples[8] += nSamplesToLoad * 2; + // Move the noise wave (that reads compiled assembly as samples) from ram to dmem + AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(numSamplesToLoad * sizeof(s16)), gWaveSamples[8]); + // Offset the address for the samples read by gWaveSamples[8] to the next set of samples + gWaveSamples[8] += numSamplesToLoad * sizeof(s16); return cmd; } else { - aLoadBuffer(cmd++, noteSubEu->samples, DMEM_UNCOMPRESSED_NOTE, 0x80); - if (unk6 != 0) { - samplePosInt = (samplePosInt * D_801304C0[unk6 >> 2]) / D_801304C0[unk6 & 3]; + // Move the synthetic wave from ram to dmem + aLoadBuffer(cmd++, noteSubEu->waveSampleAddr, DMEM_UNCOMPRESSED_NOTE, WAVE_SAMPLE_COUNT * sizeof(s16)); + + // 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]; } - samplePosInt &= 0x3F; - temp_v0 = 0x40 - samplePosInt; - if (temp_v0 < nSamplesToLoad) { - repeats = ((nSamplesToLoad - temp_v0 + 0x3F) / 0x40); - if (repeats != 0) { - aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80, 0x80); + + // 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 + numSamplesAvail = WAVE_SAMPLE_COUNT - samplePosInt; + + // Require duplicates if there are more samples to load than available + if (numSamplesToLoad > numSamplesAvail) { + // Duplicate (copy) the WAVE_SAMPLE_COUNT samples as many times as needed to reach numSamplesToLoad. + // (numSamplesToLoad - numSamplesAvail) is the number of samples missing. + // Divide by WAVE_SAMPLE_COUNT, rounding up, to get the amount of duplicates + numDuplicates = ((numSamplesToLoad - numSamplesAvail + (WAVE_SAMPLE_COUNT - 1)) / WAVE_SAMPLE_COUNT); + if (numDuplicates != 0) { + aDuplicate(cmd++, numDuplicates, DMEM_UNCOMPRESSED_NOTE, + DMEM_UNCOMPRESSED_NOTE + (WAVE_SAMPLE_COUNT * sizeof(s16))); } } synthState->samplePosInt = samplePosInt; diff --git a/src/code/code_800E4FE0.c b/src/code/code_800E4FE0.c index 785a02cf1e..4e7fd9eb44 100644 --- a/src/code/code_800E4FE0.c +++ b/src/code/code_800E4FE0.c @@ -153,8 +153,6 @@ AudioTask* func_800E5000(void) { if (gAudioContext.resetStatus == 0) { // msg = 0000RREE R = read pos, E = End Pos while (osRecvMesg(gAudioContext.cmdProcQueueP, (OSMesg*)&sp4C, OS_MESG_NOBLOCK) != -1) { - if (1) {} - if (1) {} if (1) {} Audio_ProcessCmds(sp4C); j++; @@ -166,9 +164,15 @@ AudioTask* func_800E5000(void) { gAudioContext.curAbiCmdBuf = AudioSynth_Update(gAudioContext.curAbiCmdBuf, &abiCmdCnt, currAiBuffer, gAudioContext.aiBufLengths[index]); + + // Update audioRandom to the next random number gAudioContext.audioRandom = (gAudioContext.audioRandom + gAudioContext.totalTaskCount) * osGetCount(); gAudioContext.audioRandom = - gAudioContext.aiBuffers[index][gAudioContext.totalTaskCount & 0xFF] + gAudioContext.audioRandom; + gAudioContext.audioRandom + gAudioContext.aiBuffers[index][gAudioContext.totalTaskCount & 0xFF]; + + // gWaveSamples[8] interprets compiled assembly code as s16 samples as a way to generate sound with noise. + // Start with the address of func_800E4FE0, and offset it by a random number between 0 - 0xFFF0 + // Use the resulting address as the starting address to interpret an array of samples i.e. `s16 samples[]` gWaveSamples[8] = (s16*)(((u8*)func_800E4FE0) + (gAudioContext.audioRandom & 0xFFF0)); index = gAudioContext.rspTaskIndex;