mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-10 19:20:13 +00:00
Document the Haas Effect (#1302)
* Document Haas Effect * More docs * cleanup * add comments * Adjust comment * More cleanup * Fix * Add description of the Haas Effect * roman suggestion
This commit is contained in:
parent
b24b8ad096
commit
e25bb1485a
5 changed files with 137 additions and 98 deletions
|
@ -121,7 +121,7 @@ extern u8 gDefaultShortNoteGateTimeTable[16];
|
|||
extern EnvelopePoint gDefaultEnvelope[4];
|
||||
extern NoteSubEu gZeroNoteSub;
|
||||
extern NoteSubEu gDefaultNoteSub;
|
||||
extern u16 gHeadsetPanQuantization[64];
|
||||
extern u16 gHaasEffectDelaySizes[64];
|
||||
extern s16 D_8012FBA8[];
|
||||
extern f32 gHeadsetPanVolume[128];
|
||||
extern f32 gStereoPanVolume[128];
|
||||
|
|
|
@ -484,19 +484,19 @@ typedef struct SequenceLayer {
|
|||
} SequenceLayer; // size = 0x80
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ s16 adpcmdecState[0x10];
|
||||
/* 0x0020 */ s16 finalResampleState[0x10];
|
||||
/* 0x0040 */ s16 mixEnvelopeState[0x28];
|
||||
/* 0x0090 */ s16 panResampleState[0x10];
|
||||
/* 0x00B0 */ s16 panSamplesBuffer[0x20];
|
||||
/* 0x00F0 */ s16 dummyResampleState[0x10];
|
||||
} NoteSynthesisBuffers; // size = 0x110
|
||||
/* 0x000 */ s16 adpcmdecState[16];
|
||||
/* 0x020 */ s16 finalResampleState[16];
|
||||
/* 0x040 */ s16 mixEnvelopeState[32];
|
||||
/* 0x080 */ s16 unusedState[16];
|
||||
/* 0x0A0 */ s16 haasEffectDelayState[32];
|
||||
/* 0x0E0 */ s16 unkState[128];
|
||||
} NoteSynthesisBuffers; // size = 0x1E0
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8 restart;
|
||||
/* 0x01 */ u8 sampleDmaIndex;
|
||||
/* 0x02 */ u8 prevHeadsetPanRight;
|
||||
/* 0x03 */ u8 prevHeadsetPanLeft;
|
||||
/* 0x02 */ u8 prevHaasEffectLeftDelaySize;
|
||||
/* 0x03 */ u8 prevHaasEffectRightDelaySize;
|
||||
/* 0x04 */ u8 reverbVol;
|
||||
/* 0x05 */ u8 numParts;
|
||||
/* 0x06 */ u16 samplePosFrac;
|
||||
|
@ -559,11 +559,11 @@ typedef struct {
|
|||
/* 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;
|
||||
/* 0x03 */ u8 haasEffectLeftDelaySize;
|
||||
/* 0x04 */ u8 haasEffectRightDelaySize;
|
||||
/* 0x05 */ u8 reverbVol;
|
||||
/* 0x06 */ u8 harmonicIndexCurAndPrev; // bits 3..2 store curHarmonicIndex, bits 1..0 store prevHarmonicIndex
|
||||
/* 0x07 */ u8 unk_07;
|
||||
|
|
|
@ -556,7 +556,7 @@ NoteSubEu gDefaultNoteSub = {
|
|||
{ 1, 1, 0, 0, 0, 0, 0, 0 }, { 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
u16 gHeadsetPanQuantization[64] = {
|
||||
u16 gHaasEffectDelaySizes[64] = {
|
||||
30 * SAMPLE_SIZE,
|
||||
29 * SAMPLE_SIZE,
|
||||
28 * SAMPLE_SIZE,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "global.h"
|
||||
|
||||
void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
|
||||
f32 volRight, volLeft;
|
||||
s32 smallPanIndex;
|
||||
f32 volLeft;
|
||||
f32 volRight;
|
||||
s32 halfPanIndex;
|
||||
u64 pad;
|
||||
u8 strongLeft;
|
||||
u8 strongRight;
|
||||
|
@ -31,22 +32,22 @@ void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
|
|||
sub->bitField0.stereoHeadsetEffects = stereoData.stereoHeadsetEffects;
|
||||
sub->bitField0.usesHeadsetPanEffects = stereoData.usesHeadsetPanEffects;
|
||||
if (stereoHeadsetEffects && (gAudioContext.soundMode == SOUNDMODE_HEADSET)) {
|
||||
smallPanIndex = pan >> 1;
|
||||
if (smallPanIndex > 0x3F) {
|
||||
smallPanIndex = 0x3F;
|
||||
halfPanIndex = pan >> 1;
|
||||
if (halfPanIndex > 0x3F) {
|
||||
halfPanIndex = 0x3F;
|
||||
}
|
||||
|
||||
sub->headsetPanLeft = gHeadsetPanQuantization[smallPanIndex];
|
||||
sub->headsetPanRight = gHeadsetPanQuantization[0x3F - smallPanIndex];
|
||||
sub->bitField1.usesHeadsetPanEffects2 = true;
|
||||
sub->haasEffectRightDelaySize = gHaasEffectDelaySizes[halfPanIndex];
|
||||
sub->haasEffectLeftDelaySize = gHaasEffectDelaySizes[0x3F - halfPanIndex];
|
||||
sub->bitField1.useHaasEffect = true;
|
||||
|
||||
volLeft = gHeadsetPanVolume[pan];
|
||||
volRight = gHeadsetPanVolume[0x7F - pan];
|
||||
} else if (stereoHeadsetEffects && (gAudioContext.soundMode == SOUNDMODE_STEREO)) {
|
||||
strongLeft = strongRight = 0;
|
||||
sub->headsetPanRight = 0;
|
||||
sub->headsetPanLeft = 0;
|
||||
sub->bitField1.usesHeadsetPanEffects2 = false;
|
||||
sub->haasEffectLeftDelaySize = 0;
|
||||
sub->haasEffectRightDelaySize = 0;
|
||||
sub->bitField1.useHaasEffect = false;
|
||||
|
||||
volLeft = gStereoPanVolume[pan];
|
||||
volRight = gStereoPanVolume[0x7F - pan];
|
||||
|
@ -945,6 +946,7 @@ void Audio_NoteInitAll(void) {
|
|||
note->playbackState.portamento.speed = 0;
|
||||
note->playbackState.stereoHeadsetEffects = false;
|
||||
note->startSamplePos = 0;
|
||||
note->synthesisState.synthesisBuffers = AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, 0x1E0);
|
||||
note->synthesisState.synthesisBuffers =
|
||||
AudioHeap_AllocDmaMemory(&gAudioContext.miscPool, sizeof(NoteSynthesisBuffers));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// DMEM Addresses for the RSP
|
||||
#define DMEM_TEMP 0x3C0
|
||||
#define DMEM_UNCOMPRESSED_NOTE 0x580
|
||||
#define DMEM_NOTE_PAN_TEMP 0x5C0
|
||||
#define DMEM_HAAS_TEMP 0x5C0
|
||||
#define DMEM_SCRATCH2 0x760 // = DMEM_TEMP + DMEM_2CH_SIZE + a bit more
|
||||
#define DMEM_COMPRESSED_ADPCM_DATA 0x940 // = DMEM_LEFT_CH
|
||||
#define DMEM_LEFT_CH 0x940
|
||||
|
@ -14,6 +14,12 @@
|
|||
#define DMEM_WET_LEFT_CH 0xC80
|
||||
#define DMEM_WET_RIGHT_CH 0xE20 // = 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_LoadRingBufferPart(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb);
|
||||
Acmd* AudioSynth_SaveBufferOffset(Acmd* cmd, u16 dmem, u16 offset, s32 size, s16* buf);
|
||||
Acmd* AudioSynth_SaveRingBufferPart(Acmd* cmd, u16 dmem, u16 startPos, s32 size, SynthesisReverb* reverb);
|
||||
|
@ -21,17 +27,25 @@ Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updat
|
|||
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 numSamplesToLoad);
|
||||
Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 bufLen,
|
||||
s32 flags, s32 side);
|
||||
Acmd* AudioSynth_ApplyHaasEffect(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 size, s32 flags,
|
||||
s32 haasEffectDelaySide);
|
||||
Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 aiBufLen,
|
||||
u16 inBuf, s32 headsetPanSettings, s32 flags);
|
||||
u16 dmemSrc, s32 haasEffectDelaySide, s32 flags);
|
||||
Acmd* AudioSynth_FinalResample(Acmd* cmd, NoteSynthesisState* synthState, s32 size, u16 pitch, u16 inpDmem,
|
||||
s32 resampleFlags);
|
||||
|
||||
u32 D_801304A0 = _SHIFTL(A_ENVMIXER, 24, 8);
|
||||
u32 D_801304A4 = MK_CMD(DMEM_NOTE_PAN_TEMP >> 4, DMEM_RIGHT_CH >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4);
|
||||
u32 D_801304A8 = MK_CMD(DMEM_LEFT_CH >> 4, DMEM_NOTE_PAN_TEMP >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4);
|
||||
u32 D_801304AC = MK_CMD(DMEM_LEFT_CH >> 4, DMEM_RIGHT_CH >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4);
|
||||
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 =
|
||||
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 =
|
||||
MK_CMD(DMEM_LEFT_CH >> 4, DMEM_HAAS_TEMP >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4);
|
||||
|
||||
u32 sEnvMixerDefaultDmemDests =
|
||||
MK_CMD(DMEM_LEFT_CH >> 4, DMEM_RIGHT_CH >> 4, DMEM_WET_LEFT_CH >> 4, DMEM_WET_RIGHT_CH >> 4);
|
||||
|
||||
u16 D_801304B0[] = {
|
||||
0x7FFF, 0xD001, 0x3FFF, 0xF001, 0x5FFF, 0x9001, 0x7FFF, 0x8001,
|
||||
|
@ -723,7 +737,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
s32 nParts;
|
||||
s32 curPart;
|
||||
s32 sampleDataStartPad;
|
||||
s32 side;
|
||||
s32 haasEffectDelaySide;
|
||||
s32 resampledTempLen;
|
||||
u16 sampleDmemBeforeResampling;
|
||||
s32 sampleDataOffset;
|
||||
|
@ -752,8 +766,8 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
synthState->samplePosFrac = 0;
|
||||
synthState->curVolLeft = 0;
|
||||
synthState->curVolRight = 0;
|
||||
synthState->prevHeadsetPanRight = 0;
|
||||
synthState->prevHeadsetPanLeft = 0;
|
||||
synthState->prevHaasEffectLeftDelaySize = 0;
|
||||
synthState->prevHaasEffectRightDelaySize = 0;
|
||||
synthState->reverbVol = noteSubEu->reverbVol;
|
||||
synthState->numParts = 0;
|
||||
synthState->unk_1A = 1;
|
||||
|
@ -1078,7 +1092,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
|
||||
unk7 = noteSubEu->unk_07;
|
||||
unkE = noteSubEu->unk_0E;
|
||||
buf = &synthState->synthesisBuffers->panSamplesBuffer[0x18];
|
||||
buf = synthState->synthesisBuffers->unkState;
|
||||
if (unk7 != 0 && noteSubEu->unk_0E != 0) {
|
||||
AudioSynth_DMemMove(cmd++, DMEM_TEMP, DMEM_SCRATCH2, aiBufLen * SAMPLE_SIZE);
|
||||
thing = DMEM_SCRATCH2 - unk7;
|
||||
|
@ -1095,21 +1109,24 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
synthState->unk_1A = 1;
|
||||
}
|
||||
|
||||
if (noteSubEu->headsetPanRight != 0 || synthState->prevHeadsetPanRight != 0) {
|
||||
side = 1;
|
||||
} else if (noteSubEu->headsetPanLeft != 0 || synthState->prevHeadsetPanLeft != 0) {
|
||||
side = 2;
|
||||
if ((noteSubEu->haasEffectLeftDelaySize != 0) || (synthState->prevHaasEffectLeftDelaySize != 0)) {
|
||||
haasEffectDelaySide = HAAS_EFFECT_DELAY_LEFT;
|
||||
} else if ((noteSubEu->haasEffectRightDelaySize != 0) || (synthState->prevHaasEffectRightDelaySize != 0)) {
|
||||
haasEffectDelaySide = HAAS_EFFECT_DELAY_RIGHT;
|
||||
} else {
|
||||
side = 0;
|
||||
haasEffectDelaySide = HAAS_EFFECT_DELAY_NONE;
|
||||
}
|
||||
cmd = AudioSynth_ProcessEnvelope(cmd, noteSubEu, synthState, aiBufLen, DMEM_TEMP, side, flags);
|
||||
if (noteSubEu->bitField1.usesHeadsetPanEffects2) {
|
||||
|
||||
cmd = AudioSynth_ProcessEnvelope(cmd, noteSubEu, synthState, aiBufLen, DMEM_TEMP, haasEffectDelaySide, flags);
|
||||
|
||||
if (noteSubEu->bitField1.useHaasEffect) {
|
||||
if (!(flags & A_INIT)) {
|
||||
flags = A_CONTINUE;
|
||||
}
|
||||
cmd =
|
||||
AudioSynth_NoteApplyHeadsetPanEffects(cmd, noteSubEu, synthState, aiBufLen * (s32)SAMPLE_SIZE, flags, side);
|
||||
cmd = AudioSynth_ApplyHaasEffect(cmd, noteSubEu, synthState, aiBufLen * (s32)SAMPLE_SIZE, flags,
|
||||
haasEffectDelaySide);
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
@ -1125,8 +1142,8 @@ Acmd* AudioSynth_FinalResample(Acmd* cmd, NoteSynthesisState* synthState, s32 si
|
|||
}
|
||||
|
||||
Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 aiBufLen,
|
||||
u16 inBuf, s32 headsetPanSettings, s32 flags) {
|
||||
u32 phi_a1;
|
||||
u16 dmemSrc, s32 haasEffectDelaySide, s32 flags) {
|
||||
u32 dmemDests;
|
||||
u16 curVolLeft;
|
||||
u16 targetVolLeft;
|
||||
s32 phi_t1;
|
||||
|
@ -1171,30 +1188,36 @@ Acmd* AudioSynth_ProcessEnvelope(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
synthState->curVolLeft = curVolLeft + (rampLeft * (aiBufLen >> 3));
|
||||
synthState->curVolRight = curVolRight + (rampRight * (aiBufLen >> 3));
|
||||
|
||||
if (noteSubEu->bitField1.usesHeadsetPanEffects2) {
|
||||
AudioSynth_ClearBuffer(cmd++, DMEM_NOTE_PAN_TEMP, DMEM_1CH_SIZE);
|
||||
if (noteSubEu->bitField1.useHaasEffect) {
|
||||
AudioSynth_ClearBuffer(cmd++, DMEM_HAAS_TEMP, DMEM_1CH_SIZE);
|
||||
AudioSynth_EnvSetup1(cmd++, phi_t1 * 2, rampReverb, rampLeft, rampRight);
|
||||
AudioSynth_EnvSetup2(cmd++, curVolLeft, curVolRight);
|
||||
switch (headsetPanSettings) {
|
||||
case 1:
|
||||
phi_a1 = D_801304A4;
|
||||
|
||||
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 2:
|
||||
phi_a1 = D_801304A8;
|
||||
|
||||
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:
|
||||
phi_a1 = D_801304AC;
|
||||
|
||||
default: // HAAS_EFFECT_DELAY_NONE
|
||||
dmemDests = sEnvMixerDefaultDmemDests;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
aEnvSetup1(cmd++, phi_t1 * 2, rampReverb, rampLeft, rampRight);
|
||||
aEnvSetup2(cmd++, curVolLeft, curVolRight);
|
||||
phi_a1 = D_801304AC;
|
||||
dmemDests = sEnvMixerDefaultDmemDests;
|
||||
}
|
||||
|
||||
aEnvMixer(cmd++, inBuf, aiBufLen, (sourceReverbVol & 0x80) >> 7, noteSubEu->bitField0.stereoHeadsetEffects,
|
||||
aEnvMixer(cmd++, dmemSrc, aiBufLen, (sourceReverbVol & 0x80) >> 7, noteSubEu->bitField0.stereoHeadsetEffects,
|
||||
noteSubEu->bitField0.usesHeadsetPanEffects, noteSubEu->bitField0.stereoStrongRight,
|
||||
noteSubEu->bitField0.stereoStrongLeft, phi_a1, D_801304A0);
|
||||
noteSubEu->bitField0.stereoStrongLeft, dmemDests, sEnvMixerOp);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
@ -1242,61 +1265,75 @@ Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS
|
|||
return cmd;
|
||||
}
|
||||
|
||||
Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 bufLen,
|
||||
s32 flags, s32 side) {
|
||||
u16 dest;
|
||||
/**
|
||||
* The Haas Effect gives directionality to sound by appling 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, NoteSubEu* noteSubEu, NoteSynthesisState* synthState, s32 size, s32 flags,
|
||||
s32 haasEffectDelaySide) {
|
||||
u16 dmemDest;
|
||||
u16 pitch;
|
||||
u8 prevPanShift;
|
||||
u8 panShift;
|
||||
u8 prevHaasEffectDelaySize;
|
||||
u8 haasEffectDelaySize;
|
||||
|
||||
switch (side) {
|
||||
case 1:
|
||||
dest = DMEM_LEFT_CH;
|
||||
panShift = noteSubEu->headsetPanRight;
|
||||
prevPanShift = synthState->prevHeadsetPanRight;
|
||||
synthState->prevHeadsetPanLeft = 0;
|
||||
synthState->prevHeadsetPanRight = panShift;
|
||||
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 = noteSubEu->haasEffectLeftDelaySize;
|
||||
prevHaasEffectDelaySize = synthState->prevHaasEffectLeftDelaySize;
|
||||
synthState->prevHaasEffectRightDelaySize = 0;
|
||||
synthState->prevHaasEffectLeftDelaySize = haasEffectDelaySize;
|
||||
break;
|
||||
case 2:
|
||||
dest = DMEM_RIGHT_CH;
|
||||
panShift = noteSubEu->headsetPanLeft;
|
||||
prevPanShift = synthState->prevHeadsetPanLeft;
|
||||
synthState->prevHeadsetPanLeft = panShift;
|
||||
synthState->prevHeadsetPanRight = 0;
|
||||
|
||||
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 = noteSubEu->haasEffectRightDelaySize;
|
||||
prevHaasEffectDelaySize = synthState->prevHaasEffectRightDelaySize;
|
||||
synthState->prevHaasEffectRightDelaySize = haasEffectDelaySize;
|
||||
synthState->prevHaasEffectLeftDelaySize = 0;
|
||||
break;
|
||||
default:
|
||||
|
||||
default: // HAAS_EFFECT_DELAY_NONE
|
||||
return cmd;
|
||||
}
|
||||
|
||||
if (flags != A_INIT) {
|
||||
// Slightly adjust the sample rate in order to fit a change in pan shift
|
||||
if (panShift != prevPanShift) {
|
||||
pitch = (((bufLen << 0xF) / 2) - 1) / ((bufLen + panShift - prevPanShift - 2) / 2);
|
||||
aSetBuffer(cmd++, 0, DMEM_NOTE_PAN_TEMP, DMEM_TEMP, bufLen + panShift - prevPanShift);
|
||||
// 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_NOTE_PAN_TEMP, DMEM_TEMP, bufLen);
|
||||
aDMEMMove(cmd++, DMEM_HAAS_TEMP, DMEM_TEMP, size);
|
||||
}
|
||||
|
||||
if (prevPanShift != 0) {
|
||||
aLoadBuffer(cmd++, &synthState->synthesisBuffers->panResampleState[0x8], DMEM_NOTE_PAN_TEMP,
|
||||
ALIGN16(prevPanShift));
|
||||
aDMEMMove(cmd++, DMEM_TEMP, DMEM_NOTE_PAN_TEMP + prevPanShift, bufLen + panShift - prevPanShift);
|
||||
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_NOTE_PAN_TEMP, bufLen + panShift);
|
||||
aDMEMMove(cmd++, DMEM_TEMP, DMEM_HAAS_TEMP, size + haasEffectDelaySize);
|
||||
}
|
||||
} else {
|
||||
// Just shift right
|
||||
aDMEMMove(cmd++, DMEM_NOTE_PAN_TEMP, DMEM_TEMP, bufLen);
|
||||
aClearBuffer(cmd++, DMEM_NOTE_PAN_TEMP, panShift);
|
||||
aDMEMMove(cmd++, DMEM_TEMP, DMEM_NOTE_PAN_TEMP + panShift, bufLen);
|
||||
// Just apply a delay directly
|
||||
aDMEMMove(cmd++, DMEM_HAAS_TEMP, DMEM_TEMP, size);
|
||||
aClearBuffer(cmd++, DMEM_HAAS_TEMP, haasEffectDelaySize);
|
||||
aDMEMMove(cmd++, DMEM_TEMP, DMEM_HAAS_TEMP + haasEffectDelaySize, size);
|
||||
}
|
||||
|
||||
if (panShift) {
|
||||
if (haasEffectDelaySize) { // != 0
|
||||
// Save excessive samples for next iteration
|
||||
aSaveBuffer(cmd++, DMEM_NOTE_PAN_TEMP + bufLen, &synthState->synthesisBuffers->panResampleState[0x8],
|
||||
ALIGN16(panShift));
|
||||
aSaveBuffer(cmd++, DMEM_HAAS_TEMP + size, synthState->synthesisBuffers->haasEffectDelayState,
|
||||
ALIGN16(haasEffectDelaySize));
|
||||
}
|
||||
aAddMixer(cmd++, ALIGN64(bufLen), DMEM_NOTE_PAN_TEMP, dest, 0x7FFF);
|
||||
|
||||
aAddMixer(cmd++, ALIGN64(size), DMEM_HAAS_TEMP, dmemDest, 0x7FFF);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue