mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-11 03:39:59 +00:00
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 <Dragorn421@users.noreply.github.com> Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com>
This commit is contained in:
parent
e7e2da86a8
commit
00b98027db
5 changed files with 168 additions and 98 deletions
|
@ -294,13 +294,20 @@ typedef short ENVMIX_STATE[40];
|
||||||
_a->words.w1 = (u32)(a2); \
|
_a->words.w1 = (u32)(a2); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define aClearBuffer(pkt, d, c) \
|
/*
|
||||||
{ \
|
* Clears DMEM by writing zeros.
|
||||||
Acmd *_a = (Acmd *)pkt; \
|
*
|
||||||
\
|
* @param pkt pointer to an Acmd buffer
|
||||||
_a->words.w0 = _SHIFTL(A_CLEARBUFF, 24, 8) | _SHIFTL(d, 0, 24); \
|
* @param dmem DMEM address to clear
|
||||||
_a->words.w1 = (u32)(c); \
|
* @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) \
|
#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); \
|
_a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define aLoadBuffer(pkt, s, d, c) \
|
/*
|
||||||
{ \
|
* Loads a buffer to DMEM from any physical source address, KSEG0, or KSEG1
|
||||||
Acmd *_a = (Acmd *)pkt; \
|
*
|
||||||
\
|
* @param pkt pointer to an Acmd buffer
|
||||||
_a->words.w0 = (_SHIFTL(A_LOADBUFF, 24, 8) | \
|
* @param addrSrc Any physical source address, KSEG0, or KSEG1
|
||||||
_SHIFTL((c) >> 4, 16, 8) | _SHIFTL(d, 0, 16)); \
|
* @param dmemDest DMEM destination address
|
||||||
_a->words.w1 = (u32)(s); \
|
* @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) \
|
#define aMix(pkt, f, g, i, o) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -366,14 +380,21 @@ typedef short ENVMIX_STATE[40];
|
||||||
_a->words.w1 = (u32)(s); \
|
_a->words.w1 = (u32)(s); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define aSaveBuffer(pkt, s, d, c) \
|
/*
|
||||||
{ \
|
* Stores a buffer from DMEM to any physical source address, KSEG0, or KSEG1
|
||||||
Acmd *_a = (Acmd *)pkt; \
|
*
|
||||||
\
|
* @param pkt pointer to an Acmd buffer
|
||||||
_a->words.w0 = (_SHIFTL(A_SAVEBUFF, 24, 8) | \
|
* @param dmemSrc DMEM source address
|
||||||
_SHIFTL((c) >> 4, 16, 8) | _SHIFTL(s, 0, 16)); \
|
* @param addrDest Any physical source address, KSEG0, or KSEG1
|
||||||
_a->words.w1 = (u32)(d); \
|
* @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) \
|
#define aSegment(pkt, s, b) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -461,14 +482,21 @@ typedef short ENVMIX_STATE[40];
|
||||||
_a->words.w1 = (u32)(addr); \
|
_a->words.w1 = (u32)(addr); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define aDuplicate(pkt, count, dmemi, dmemo, a4) \
|
/*
|
||||||
{ \
|
* Duplicates 128 bytes of data a specified number of times.
|
||||||
Acmd *_a = (Acmd *)pkt; \
|
*
|
||||||
\
|
* @param pkt pointer to an Acmd buffer
|
||||||
_a->words.w0 = (_SHIFTL(A_DUPLICATE, 24, 8) | \
|
* @param numCopies number of times to duplicate 128 bytes from src
|
||||||
_SHIFTL(count, 16, 8) | _SHIFTL(dmemi, 0, 16)); \
|
* @param dmemSrc DMEM source address
|
||||||
_a->words.w1 = _SHIFTL(dmemo, 16, 16) | _SHIFTL(a4, 0, 16); \
|
* @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) \
|
#define aAddMixer(pkt, count, dmemi, dmemo, a4) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
|
|
||||||
#define AIBUF_LEN 0x580
|
#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
|
#define AUDIO_RELOCATED_ADDRESS_START K0BASE
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -493,7 +496,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ u8 priority;
|
/* 0x00 */ u8 priority;
|
||||||
/* 0x01 */ u8 waveId;
|
/* 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;
|
/* 0x03 */ u8 fontId;
|
||||||
/* 0x04 */ u8 unk_04;
|
/* 0x04 */ u8 unk_04;
|
||||||
/* 0x05 */ u8 stereoHeadsetEffects;
|
/* 0x05 */ u8 stereoHeadsetEffects;
|
||||||
|
@ -531,7 +534,7 @@ typedef struct {
|
||||||
/* 0x03 */ u8 headsetPanRight;
|
/* 0x03 */ u8 headsetPanRight;
|
||||||
/* 0x04 */ u8 headsetPanLeft;
|
/* 0x04 */ u8 headsetPanLeft;
|
||||||
/* 0x05 */ u8 reverbVol;
|
/* 0x05 */ u8 reverbVol;
|
||||||
/* 0x06 */ u8 unk_06;
|
/* 0x06 */ u8 harmonicIndexCurAndPrev; // bits 3..2 store curHarmonicIndex, bits 1..0 store prevHarmonicIndex
|
||||||
/* 0x07 */ u8 unk_07;
|
/* 0x07 */ u8 unk_07;
|
||||||
/* 0x08 */ u16 targetVolLeft;
|
/* 0x08 */ u16 targetVolLeft;
|
||||||
/* 0x0A */ u16 targetVolRight;
|
/* 0x0A */ u16 targetVolRight;
|
||||||
|
@ -539,7 +542,7 @@ typedef struct {
|
||||||
/* 0x0E */ u16 unk_0E;
|
/* 0x0E */ u16 unk_0E;
|
||||||
/* 0x10 */ union {
|
/* 0x10 */ union {
|
||||||
TunedSample* tunedSample;
|
TunedSample* tunedSample;
|
||||||
s16* samples; // used for synthetic waves
|
s16* waveSampleAddr; // used for synthetic waves
|
||||||
};
|
};
|
||||||
/* 0x14 */ s16* filter;
|
/* 0x14 */ s16* filter;
|
||||||
/* 0x18 */ char pad_18[0x8];
|
/* 0x18 */ char pad_18[0x8];
|
||||||
|
|
|
@ -19,8 +19,8 @@ void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
|
||||||
|
|
||||||
sub->bitField0 = note->noteSubEu.bitField0;
|
sub->bitField0 = note->noteSubEu.bitField0;
|
||||||
sub->bitField1 = note->noteSubEu.bitField1;
|
sub->bitField1 = note->noteSubEu.bitField1;
|
||||||
sub->samples = note->noteSubEu.samples;
|
sub->waveSampleAddr = note->noteSubEu.waveSampleAddr;
|
||||||
sub->unk_06 = note->noteSubEu.unk_06;
|
sub->harmonicIndexCurAndPrev = note->noteSubEu.harmonicIndexCurAndPrev;
|
||||||
|
|
||||||
Audio_NoteSetResamplingRate(sub, attrs->frequency);
|
Audio_NoteSetResamplingRate(sub, attrs->frequency);
|
||||||
|
|
||||||
|
@ -529,10 +529,18 @@ void Audio_SeqLayerNoteRelease(SequenceLayer* layer) {
|
||||||
Audio_SeqLayerDecayRelease(layer, ADSR_STATE_RELEASE);
|
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) {
|
s32 Audio_BuildSyntheticWave(Note* note, SequenceLayer* layer, s32 waveId) {
|
||||||
f32 freqScale;
|
f32 freqScale;
|
||||||
f32 ratio;
|
f32 freqRatio;
|
||||||
u8 sampleCountIndex;
|
u8 harmonicIndex;
|
||||||
|
|
||||||
if (waveId < 128) {
|
if (waveId < 128) {
|
||||||
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) {
|
if (layer->portamento.mode != 0 && 0.0f < layer->portamento.extent) {
|
||||||
freqScale *= (layer->portamento.extent + 1.0f);
|
freqScale *= (layer->portamento.extent + 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map frequency to the harmonic to use from gWaveSamples
|
||||||
if (freqScale < 0.99999f) {
|
if (freqScale < 0.99999f) {
|
||||||
sampleCountIndex = 0;
|
harmonicIndex = 0;
|
||||||
ratio = 1.0465f;
|
freqRatio = 1.0465f;
|
||||||
} else if (freqScale < 1.99999f) {
|
} else if (freqScale < 1.99999f) {
|
||||||
sampleCountIndex = 1;
|
harmonicIndex = 1;
|
||||||
ratio = 0.52325f;
|
freqRatio = 1.0465f / 2;
|
||||||
} else if (freqScale < 3.99999f) {
|
} else if (freqScale < 3.99999f) {
|
||||||
sampleCountIndex = 2;
|
harmonicIndex = 2;
|
||||||
ratio = 0.26263f;
|
freqRatio = 1.0465f / 4 + 1.005E-3;
|
||||||
} else {
|
} else {
|
||||||
sampleCountIndex = 3;
|
harmonicIndex = 3;
|
||||||
ratio = 0.13081f;
|
freqRatio = 1.0465f / 8 - 2.5E-6;
|
||||||
}
|
}
|
||||||
layer->freqScale *= ratio;
|
|
||||||
|
// Update results
|
||||||
|
layer->freqScale *= freqRatio;
|
||||||
note->playbackState.waveId = waveId;
|
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) {
|
void Audio_InitSyntheticWave(Note* note, SequenceLayer* layer) {
|
||||||
s32 sampleCountIndex;
|
s32 prevHarmonicIndex;
|
||||||
s32 waveSampleCountIndex;
|
s32 curHarmonicIndex;
|
||||||
s32 waveId = layer->instOrWave;
|
s32 waveId = layer->instOrWave;
|
||||||
|
|
||||||
if (waveId == 0xFF) {
|
if (waveId == 0xFF) {
|
||||||
waveId = layer->channel->instOrWave;
|
waveId = layer->channel->instOrWave;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleCountIndex = note->playbackState.sampleCountIndex;
|
prevHarmonicIndex = note->playbackState.harmonicIndex;
|
||||||
waveSampleCountIndex = Audio_BuildSyntheticWave(note, layer, waveId);
|
curHarmonicIndex = Audio_BuildSyntheticWave(note, layer, waveId);
|
||||||
|
|
||||||
if (waveSampleCountIndex != sampleCountIndex) {
|
if (curHarmonicIndex != prevHarmonicIndex) {
|
||||||
note->noteSubEu.unk_06 = waveSampleCountIndex * 4 + sampleCountIndex;
|
note->noteSubEu.harmonicIndexCurAndPrev = (curHarmonicIndex << 2) + prevHarmonicIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updateIndex);
|
||||||
Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s16* aiBuf,
|
Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s16* aiBuf,
|
||||||
s32 aiBufLen, Acmd* cmd, s32 updateIndex);
|
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,
|
Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 bufLen,
|
||||||
s32 flags, s32 side);
|
s32 flags, s32 side);
|
||||||
Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 aiBufLen,
|
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,
|
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) {
|
void AudioSynth_InitNextRingBuf(s32 chunkLen, s32 updateIndex, s32 reverbIndex) {
|
||||||
ReverbRingBufferItem* bufItem;
|
ReverbRingBufferItem* bufItem;
|
||||||
|
@ -129,7 +134,7 @@ void func_800DB03C(s32 updateIndex) {
|
||||||
subEu2->bitField0.enabled = false;
|
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 func_800DBB94(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSynth_ClearBuffer(Acmd* cmd, s32 arg1, s32 arg2) {
|
void AudioSynth_ClearBuffer(Acmd* cmd, s32 dmem, s32 size) {
|
||||||
aClearBuffer(cmd, arg1, arg2);
|
aClearBuffer(cmd, dmem, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_800DBBBC(void) {
|
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 func_800DBD08(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSynth_LoadBuffer(Acmd* cmd, s32 arg1, s32 arg2, void* arg3) {
|
void AudioSynth_LoadBuffer(Acmd* cmd, s32 dmemDest, s32 size, void* addrSrc) {
|
||||||
aLoadBuffer(cmd, arg3, arg1, arg2);
|
aLoadBuffer(cmd, addrSrc, dmemDest, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSynth_SaveBuffer(Acmd* cmd, s32 arg1, s32 arg2, void* arg3) {
|
void AudioSynth_SaveBuffer(Acmd* cmd, s32 dmemSrc, s32 size, void* addrDest) {
|
||||||
aSaveBuffer(cmd, arg1, arg3, arg2);
|
aSaveBuffer(cmd, dmemSrc, addrDest, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSynth_EnvSetup2(Acmd* cmd, s32 volLeft, s32 volRight) {
|
void AudioSynth_EnvSetup2(Acmd* cmd, s32 volLeft, s32 volRight) {
|
||||||
|
@ -722,12 +727,12 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
s32 sampleDataStartPad;
|
s32 sampleDataStartPad;
|
||||||
s32 side;
|
s32 side;
|
||||||
s32 resampledTempLen;
|
s32 resampledTempLen;
|
||||||
u16 noteSamplesDmemAddrBeforeResampling;
|
u16 sampleDmemBeforeResampling;
|
||||||
s32 sampleDataOffset;
|
s32 sampleDataOffset;
|
||||||
s32 thing;
|
s32 thing;
|
||||||
s32 s5;
|
s32 s5;
|
||||||
Note* note;
|
Note* note;
|
||||||
u32 nSamplesToLoad;
|
u32 numSamplesToLoad;
|
||||||
u16 unk7;
|
u16 unk7;
|
||||||
u16 unkE;
|
u16 unkE;
|
||||||
s16* filter;
|
s16* filter;
|
||||||
|
@ -761,7 +766,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
|
resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
|
||||||
nParts = noteSubEu->bitField1.hasTwoParts + 1;
|
nParts = noteSubEu->bitField1.hasTwoParts + 1;
|
||||||
samplesLenFixedPoint = (resamplingRateFixedPoint * aiBufLen * 2) + synthState->samplePosFrac;
|
samplesLenFixedPoint = (resamplingRateFixedPoint * aiBufLen * 2) + synthState->samplePosFrac;
|
||||||
nSamplesToLoad = samplesLenFixedPoint >> 16;
|
numSamplesToLoad = samplesLenFixedPoint >> 16;
|
||||||
synthState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
|
synthState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
|
||||||
|
|
||||||
// Partially-optimized out no-op ifs required for matching. SM64 decomp
|
// 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;
|
synthState->numParts = nParts;
|
||||||
|
|
||||||
if (noteSubEu->bitField1.isSyntheticWave) {
|
if (noteSubEu->bitField1.isSyntheticWave) {
|
||||||
cmd = AudioSynth_LoadWaveSamples(cmd, noteSubEu, synthState, nSamplesToLoad);
|
cmd = AudioSynth_LoadWaveSamples(cmd, noteSubEu, synthState, numSamplesToLoad);
|
||||||
noteSamplesDmemAddrBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * 2);
|
sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * (s32)sizeof(s16));
|
||||||
synthState->samplePosInt += nSamplesToLoad;
|
synthState->samplePosInt += numSamplesToLoad;
|
||||||
} else {
|
} else {
|
||||||
sample = noteSubEu->tunedSample->sample;
|
sample = noteSubEu->tunedSample->sample;
|
||||||
loopInfo = sample->loop;
|
loopInfo = sample->loop;
|
||||||
|
@ -789,11 +794,11 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
s5 = 0;
|
s5 = 0;
|
||||||
|
|
||||||
if (nParts == 1) {
|
if (nParts == 1) {
|
||||||
samplesLenAdjusted = nSamplesToLoad;
|
samplesLenAdjusted = numSamplesToLoad;
|
||||||
} else if (nSamplesToLoad & 1) {
|
} else if (numSamplesToLoad & 1) {
|
||||||
samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2);
|
samplesLenAdjusted = (numSamplesToLoad & ~1) + (curPart * 2);
|
||||||
} else {
|
} else {
|
||||||
samplesLenAdjusted = nSamplesToLoad;
|
samplesLenAdjusted = numSamplesToLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample->codec == CODEC_ADPCM || sample->codec == CODEC_SMALL_ADPCM) {
|
if (sample->codec == CODEC_ADPCM || sample->codec == CODEC_SMALL_ADPCM) {
|
||||||
|
@ -1004,7 +1009,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
|
|
||||||
switch (nParts) {
|
switch (nParts) {
|
||||||
case 1:
|
case 1:
|
||||||
noteSamplesDmemAddrBeforeResampling = DMEM_UNCOMPRESSED_NOTE + skipBytes;
|
sampleDmemBeforeResampling = DMEM_UNCOMPRESSED_NOTE + skipBytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -1013,9 +1018,9 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
AudioSynth_InterL(cmd++, DMEM_UNCOMPRESSED_NOTE + skipBytes, DMEM_TEMP + 0x20,
|
AudioSynth_InterL(cmd++, DMEM_UNCOMPRESSED_NOTE + skipBytes, DMEM_TEMP + 0x20,
|
||||||
ALIGN8(samplesLenAdjusted / 2));
|
ALIGN8(samplesLenAdjusted / 2));
|
||||||
resampledTempLen = samplesLenAdjusted;
|
resampledTempLen = samplesLenAdjusted;
|
||||||
noteSamplesDmemAddrBeforeResampling = DMEM_TEMP + 0x20;
|
sampleDmemBeforeResampling = DMEM_TEMP + 0x20;
|
||||||
if (finished) {
|
if (finished) {
|
||||||
AudioSynth_ClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen,
|
AudioSynth_ClearBuffer(cmd++, sampleDmemBeforeResampling + resampledTempLen,
|
||||||
samplesLenAdjusted + 0x10);
|
samplesLenAdjusted + 0x10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1038,8 +1043,8 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
flags = A_INIT;
|
flags = A_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = AudioSynth_FinalResample(cmd, synthState, aiBufLen * 2, resamplingRateFixedPoint,
|
cmd = AudioSynth_FinalResample(cmd, synthState, aiBufLen * 2, resamplingRateFixedPoint, sampleDmemBeforeResampling,
|
||||||
noteSamplesDmemAddrBeforeResampling, flags);
|
flags);
|
||||||
if (bookOffset == 3) {
|
if (bookOffset == 3) {
|
||||||
AudioSynth_UnkCmd19(cmd++, DMEM_TEMP, DMEM_TEMP, aiBufLen * 2, 0);
|
AudioSynth_UnkCmd19(cmd++, DMEM_TEMP, DMEM_TEMP, aiBufLen * 2, 0);
|
||||||
}
|
}
|
||||||
|
@ -1184,27 +1189,43 @@ Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 nSamplesToLoad) {
|
Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState,
|
||||||
s32 temp_v0;
|
s32 numSamplesToLoad) {
|
||||||
s32 unk6 = noteSubEu->unk_06;
|
s32 numSamplesAvail;
|
||||||
|
s32 harmonicIndexCurAndPrev = noteSubEu->harmonicIndexCurAndPrev;
|
||||||
s32 samplePosInt = synthState->samplePosInt;
|
s32 samplePosInt = synthState->samplePosInt;
|
||||||
s32 repeats;
|
s32 numDuplicates;
|
||||||
|
|
||||||
if (noteSubEu->bitField1.bookOffset != 0) {
|
if (noteSubEu->bitField1.bookOffset != 0) {
|
||||||
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2), gWaveSamples[8]);
|
// Move the noise wave (that reads compiled assembly as samples) from ram to dmem
|
||||||
gWaveSamples[8] += nSamplesToLoad * 2;
|
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;
|
return cmd;
|
||||||
} else {
|
} else {
|
||||||
aLoadBuffer(cmd++, noteSubEu->samples, DMEM_UNCOMPRESSED_NOTE, 0x80);
|
// Move the synthetic wave from ram to dmem
|
||||||
if (unk6 != 0) {
|
aLoadBuffer(cmd++, noteSubEu->waveSampleAddr, DMEM_UNCOMPRESSED_NOTE, WAVE_SAMPLE_COUNT * sizeof(s16));
|
||||||
samplePosInt = (samplePosInt * D_801304C0[unk6 >> 2]) / D_801304C0[unk6 & 3];
|
|
||||||
|
// 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;
|
// Offset in the WAVE_SAMPLE_COUNT samples of gWaveSamples to start processing the wave for continuity
|
||||||
if (temp_v0 < nSamplesToLoad) {
|
samplePosInt = (u32)samplePosInt % WAVE_SAMPLE_COUNT;
|
||||||
repeats = ((nSamplesToLoad - temp_v0 + 0x3F) / 0x40);
|
// Number of samples in the initial WAVE_SAMPLE_COUNT samples available to be used to process
|
||||||
if (repeats != 0) {
|
numSamplesAvail = WAVE_SAMPLE_COUNT - samplePosInt;
|
||||||
aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80, 0x80);
|
|
||||||
|
// 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;
|
synthState->samplePosInt = samplePosInt;
|
||||||
|
|
|
@ -153,8 +153,6 @@ AudioTask* func_800E5000(void) {
|
||||||
if (gAudioContext.resetStatus == 0) {
|
if (gAudioContext.resetStatus == 0) {
|
||||||
// msg = 0000RREE R = read pos, E = End Pos
|
// msg = 0000RREE R = read pos, E = End Pos
|
||||||
while (osRecvMesg(gAudioContext.cmdProcQueueP, (OSMesg*)&sp4C, OS_MESG_NOBLOCK) != -1) {
|
while (osRecvMesg(gAudioContext.cmdProcQueueP, (OSMesg*)&sp4C, OS_MESG_NOBLOCK) != -1) {
|
||||||
if (1) {}
|
|
||||||
if (1) {}
|
|
||||||
if (1) {}
|
if (1) {}
|
||||||
Audio_ProcessCmds(sp4C);
|
Audio_ProcessCmds(sp4C);
|
||||||
j++;
|
j++;
|
||||||
|
@ -166,9 +164,15 @@ AudioTask* func_800E5000(void) {
|
||||||
|
|
||||||
gAudioContext.curAbiCmdBuf =
|
gAudioContext.curAbiCmdBuf =
|
||||||
AudioSynth_Update(gAudioContext.curAbiCmdBuf, &abiCmdCnt, currAiBuffer, gAudioContext.aiBufLengths[index]);
|
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.audioRandom + gAudioContext.totalTaskCount) * osGetCount();
|
||||||
gAudioContext.audioRandom =
|
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));
|
gWaveSamples[8] = (s16*)(((u8*)func_800E4FE0) + (gAudioContext.audioRandom & 0xFFF0));
|
||||||
|
|
||||||
index = gAudioContext.rspTaskIndex;
|
index = gAudioContext.rspTaskIndex;
|
||||||
|
|
Loading…
Reference in a new issue