Add 6-channel audio support.

This commit is contained in:
Tortuga veloz 2025-03-12 14:20:15 +01:00 committed by Alejandro Asenjo Nitti
parent 94553db6c1
commit 798f6fbe1f
13 changed files with 433 additions and 326 deletions

View file

@ -52,10 +52,14 @@ typedef void (*AudioCustomUpdateFunction)(void);
// Samples are processed in groups of 16 called a "frame"
#define SAMPLES_PER_FRAME ADPCMFSIZE
// The length of one left/right channel is 12 frames
#define MAX_NUM_AUDIO_CHANNELS 6
// The length of one channel is 12 frames
#define DMEM_1CH_SIZE (12 * SAMPLES_PER_FRAME * SAMPLE_SIZE)
// Both left and right channels
#define DMEM_2CH_SIZE (2 * DMEM_1CH_SIZE)
// 6 channels
#define DMEM_6CH_SIZE (6 * DMEM_1CH_SIZE)
#define AIBUF_LEN (170 * SAMPLES_PER_FRAME) // number of samples
#define AIBUF_SIZE (AIBUF_LEN * SAMPLE_SIZE) // number of bytes
@ -399,7 +403,8 @@ typedef struct {
typedef struct {
/* 0x00 */ u8 strongLeft : 1;
/* 0x00 */ u8 strongRight : 1;
/* 0x00 */ u8 bit2 : 2;
/* 0x00 */ u8 is_voice : 1;
/* 0x00 */ u8 is_sfx : 1;
/* 0x00 */ u8 unused : 2;
/* 0x00 */ u8 usesHeadsetPanEffects : 1;
/* 0x00 */ u8 stereoHeadsetEffects : 1;
@ -428,7 +433,8 @@ typedef struct SequenceChannel {
/* 0x00 */ u8 hasInstrument : 1;
/* 0x00 */ u8 stereoHeadsetEffects : 1;
/* 0x00 */ u8 largeNotes : 1; // notes specify duration and velocity
/* 0x00 */ u8 unused : 1;
/* 0x00 */ u8 is_voice : 1;
/* 0x00 */ u8 is_sfx : 1;
union {
struct {
/* 0x4 */ char pad_4 : 1;
@ -551,8 +557,12 @@ typedef struct {
/* 0x0C */ NoteSynthesisBuffers* synthesisBuffers;
/* 0x10 */ s16 curVolLeft;
/* 0x12 */ s16 curVolRight;
/* 0x14 */ char unk_14[0xC];
} NoteSynthesisState; // size = 0x20
/* 0x14 */ s16 curVolCenter;
/* 0x16 */ s16 curVolLfe;
/* 0x18 */ s16 curVolRLeft;
/* 0x1A */ s16 curVolRRight;
/* 0x1C */ char unk_14[0xC];
} NoteSynthesisState; // size = 0x1E
typedef struct {
/* 0x00 */ struct SequenceChannel* channel;
@ -609,9 +619,13 @@ typedef struct {
/* 0x05 */ u8 reverb;
/* 0x06 */ u16 panVolLeft;
/* 0x08 */ u16 panVolRight;
/* 0x0A */ u16 resampleRate;
/* 0x0C */ Sample** waveSampleAddr;
} NoteSubEu; // size = 0x10
/* 0x0A */ u16 panVolCenter;
/* 0x0C */ u16 panVolLfe;
/* 0x0E */ u16 panVolRLeft;
/* 0x10 */ u16 panVolRRight;
/* 0x12 */ u16 resampleRate;
/* 0x14 */ Sample** waveSampleAddr;
} NoteSubEu; // size = 0x16
typedef struct Note {
/* 0x00 */ AudioListItem listItem;

@ -1 +1 @@
Subproject commit c6bd64c5da0e55a1c00e969bc01046f9335cda43
Subproject commit e1db49367bb3743a304d763be34830b4c1999873

View file

@ -454,26 +454,37 @@ s8 Audio_GetSfxReverb(u8 bankId, u8 entryIndex, u8 channelId) {
s8 Audio_GetSfxPan(f32 xPos, f32 zPos, u8 mode) {
if (sSfxChannelLayout != SFXCHAN_3) {
f32 absx = ABSF(xPos);
f32 absz = ABSF(zPos);
f32 pan;
float absx = ABSF(xPos);
float absz = ABSF(zPos);
if ((absx < 1.0f) && (absz < 1.0f)) {
// [0, 0] would be a degenerate value
// Consider these to be close to zero and put in center
if (absx < 1.f && absz < 1.f) {
return 64;
}
absx = MIN(1200.0f, absx);
absz = MIN(1200.0f, absz);
if ((xPos == 0) && (zPos == 0)) {
pan = 0.5f;
} else if ((xPos >= 0.f) && (absz <= absx)) {
pan = 1.0f - ((2400.0f - absx) / (10.0f * (2400.0f - absz)));
} else if ((xPos < 0.0f) && (absz <= absx)) {
pan = (2400.0f - absx) / (10.0f * (2400.0f - absz));
if (GetNumAudioChannels() == 2) {
float pan;
absx = MIN(1200.0f, absx);
absz = MIN(1200.0f, absz);
if ((xPos == 0) && (zPos == 0)) {
pan = 0.5f;
} else if ((xPos >= 0.f) && (absz <= absx)) {
pan = 1.0f - ((2400.0f - absx) / (10.0f * (2400.0f - absz)));
} else if ((xPos < 0.0f) && (absz <= absx)) {
pan = (2400.0f - absx) / (10.0f * (2400.0f - absz));
} else {
pan = (xPos / (2.5f * absz)) + 0.5f;
}
return ROUND(pan * 127.0f);
} else {
pan = (xPos / (2.5f * absz)) + 0.5f;
// Calculate the angle in radians
float angle = atan2f(xPos, -zPos);
float normalized_angle = (angle / (2 * M_PI)) + 0.5f;
s8 pan = (s8) (normalized_angle * 127);
return pan;
}
return ROUND(pan * 127.0f);
} else if (mode != 4) {
return ((mode & 1) * 127);
}
@ -507,7 +518,6 @@ void Audio_SetSfxProperties(u8 bankId, u8 entryIndex, u8 channelId) {
f32 freqMod = 1.0f;
s8 pan = 64;
SfxBankEntry* entry = &sSfxBanks[bankId][entryIndex];
switch (bankId) {
case SFX_BANK_PLAYER:
case SFX_BANK_1:

View file

@ -67,8 +67,7 @@ int testBits(void) {
void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
NoteSubEu* noteSub;
f32 panVolumeLeft;
f32 pamVolumeRight;
f32 panVolumeLeft = 0, panVolumeRight = 0, panVolumeRearLeft = 0, panVolumeRearRight = 0, panVolumeCenter = 0;
f32 velocity;
s32 temp_t0;
s32 var_a0;
@ -86,59 +85,95 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
pan = noteAttr->pan;
reverb = noteAttr->reverb;
stereo = noteAttr->stereo;
pan %= ARRAY_COUNTU(gHeadsetPanVolume);
if ((noteSub->bitField0.stereoHeadsetEffects) && (gAudioSoundMode == SOUNDMODE_HEADSET)) {
var_a0 = pan >> 1;
if (var_a0 >= ARRAY_COUNT(gHaasEffectDelaySizes)) {
var_a0 = ARRAY_COUNT(gHaasEffectDelaySizes) - 1;
}
noteSub->rightDelaySize = gHaasEffectDelaySizes[var_a0];
noteSub->leftDelaySize = gHaasEffectDelaySizes[ARRAY_COUNT(gHaasEffectDelaySizes) - 1 - var_a0];
noteSub->bitField0.stereoStrongRight = false;
noteSub->bitField0.stereoStrongLeft = false;
noteSub->bitField0.usesHeadsetPanEffects = true;
panVolumeLeft = gHeadsetPanVolume[pan];
pamVolumeRight = gHeadsetPanVolume[ARRAY_COUNT(gHeadsetPanVolume) - 1 - pan];
} else if (noteSub->bitField0.stereoHeadsetEffects && (gAudioSoundMode == SOUNDMODE_STEREO)) {
noteSub->leftDelaySize = 0;
noteSub->rightDelaySize = 0;
noteSub->bitField0.usesHeadsetPanEffects = false;
panVolumeLeft = gStereoPanVolume[pan];
pamVolumeRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan];
strongRight = false;
strongLeft = false;
if (pan < 32) {
strongLeft = true;
} else if (pan > 96) {
strongRight = true;
if (GetNumAudioChannels() == 2) {
pan %= ARRAY_COUNTU(gHeadsetPanVolume);
if ((noteSub->bitField0.stereoHeadsetEffects) && (gAudioSoundMode == SOUNDMODE_HEADSET)) {
var_a0 = pan >> 1;
if (var_a0 >= ARRAY_COUNT(gHaasEffectDelaySizes)) {
var_a0 = ARRAY_COUNT(gHaasEffectDelaySizes) - 1;
}
noteSub->rightDelaySize = gHaasEffectDelaySizes[var_a0];
noteSub->leftDelaySize = gHaasEffectDelaySizes[ARRAY_COUNT(gHaasEffectDelaySizes) - 1 - var_a0];
noteSub->bitField0.stereoStrongRight = false;
noteSub->bitField0.stereoStrongLeft = false;
noteSub->bitField0.usesHeadsetPanEffects = true;
panVolumeLeft = gHeadsetPanVolume[pan];
panVolumeRight = gHeadsetPanVolume[ARRAY_COUNT(gHeadsetPanVolume) - 1 - pan];
} else if (noteSub->bitField0.stereoHeadsetEffects && (gAudioSoundMode == SOUNDMODE_STEREO)) {
noteSub->leftDelaySize = 0;
noteSub->rightDelaySize = 0;
noteSub->bitField0.usesHeadsetPanEffects = false;
panVolumeLeft = gStereoPanVolume[pan];
panVolumeRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan];
strongRight = false;
strongLeft = false;
if (pan < 32) {
strongLeft = true;
} else if (pan > 96) {
strongRight = true;
}
noteSub->bitField0.stereoStrongRight = strongRight;
noteSub->bitField0.stereoStrongLeft = strongLeft;
switch (stereo.s.bit2) {
case 0:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft;
break;
case 1:
break;
case 2:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight | strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft | strongLeft;
break;
case 3:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight ^ strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft ^ strongLeft;
break;
}
} else if (gAudioSoundMode == SOUNDMODE_MONO) {
panVolumeLeft = 0.707f;
panVolumeRight = 0.707f;
} else {
panVolumeLeft = gDefaultPanVolume[pan];
panVolumeRight = gDefaultPanVolume[ARRAY_COUNT(gDefaultPanVolume) - 1 - pan];
}
noteSub->bitField0.stereoStrongRight = strongRight;
noteSub->bitField0.stereoStrongLeft = strongLeft;
switch (stereo.s.bit2) {
case 0:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft;
break;
case 1:
break;
case 2:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight | strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft | strongLeft;
break;
case 3:
noteSub->bitField0.stereoStrongRight = stereo.s.strongRight ^ strongRight;
noteSub->bitField0.stereoStrongLeft = stereo.s.strongLeft ^ strongLeft;
break;
}
} else if (gAudioSoundMode == SOUNDMODE_MONO) {
panVolumeLeft = 0.707f;
pamVolumeRight = 0.707f;
} else {
panVolumeLeft = gDefaultPanVolume[pan];
pamVolumeRight = gDefaultPanVolume[ARRAY_COUNT(gDefaultPanVolume) - 1 - pan];
// Surround 5.1
const float vol_voice = 0.8f;
const float vol_music = 0.707f;
if (stereo.s.is_voice) { // VOICE
panVolumeCenter = vol_voice;
}
else if (stereo.s.is_sfx) { // SFX
float pan_angle = (float)(pan + 64) / 128 * 2 * M_PI;
// Speaker angles in radians
const float front_left = -0.5236;
const float front_right = 0.5236;
const float rear_left = -1.92;
const float rear_right = 1.92;
// Normalize pan_angle to [0, 2π]
pan_angle = fmodf(pan_angle, 2 * M_PI);
if (pan_angle < 0) pan_angle += 2 * M_PI;
// Calculate volumes using cosine panning law
panVolumeLeft = fmaxf(0, cosf(pan_angle - front_left)); // Front Left
panVolumeRight = fmaxf(0, cosf(pan_angle - front_right)); // Front Right
panVolumeRearLeft = fmaxf(0, cosf(pan_angle - rear_left)); // Rear Left
panVolumeRearRight = fmaxf(0, cosf(pan_angle - rear_right)); // Rear Right
// printf("pan: %d, pan_angle: %f, left: %f, right: %f, rleft: %f, rright: %f\n", pan, pan_angle, panVolumeLeft, panVolumeRight, panVolumeRearLeft, panVolumeRearRight);
} else { // MUSIC
panVolumeLeft = vol_music;
panVolumeRight = vol_music;
panVolumeRearLeft = vol_music;
panVolumeRearRight = vol_music;
}
}
if (velocity < 0.0f) {
velocity = 0.0f;
}
@ -148,16 +183,15 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
float master_vol = CVarGetFloat("gGameMasterVolume", 1.0f);
noteSub->panVolLeft = (s32) (velocity * panVolumeLeft * 4095.999f) * master_vol;
noteSub->panVolRight = (s32) (velocity * pamVolumeRight * 4095.999f) * master_vol;
noteSub->panVolRight = (s32) (velocity * panVolumeRight * 4095.999f) * master_vol;
noteSub->panVolRLeft = (s32) (velocity * panVolumeRearLeft * 4095.999f) * master_vol;
noteSub->panVolRRight = (s32) (velocity * panVolumeRearRight * 4095.999f) * master_vol;
noteSub->panVolCenter = (s32) (velocity * panVolumeCenter * 4095.999f) * master_vol;
noteSub->panVolLfe = (s32) (velocity * 4095.999f) * master_vol;
noteSub->gain = noteAttr->gain;
if (noteSub->reverb != reverb) {
noteSub->reverb = reverb;
noteSub->bitField0.unused = true;
} else if (noteSub->bitField0.needsInit) {
noteSub->bitField0.unused = true;
} else {
noteSub->bitField0.unused = false;
}
}
@ -367,6 +401,8 @@ void Audio_ProcessNotes(void) {
sp70.velocity = playbackState->parentLayer->noteVelocity;
sp70.pan = playbackState->parentLayer->notePan;
sp70.stereo = playbackState->parentLayer->stereo;
sp70.stereo.s.is_voice = playbackState->parentLayer->channel->is_voice;
sp70.stereo.s.is_sfx = playbackState->parentLayer->channel->is_sfx;
sp70.reverb = playbackState->parentLayer->channel->targetReverbVol;
sp70.gain = playbackState->parentLayer->channel->reverbIndex;

View file

@ -89,7 +89,8 @@ void AudioSeq_InitSequenceChannel(SequenceChannel* channel) {
for (i = 0; i < 8; i++) {
channel->seqScriptIO[i] = -1;
}
channel->unused = 0;
channel->is_sfx = 0;
channel->is_voice = 0;
Audio_InitNoteLists(&channel->notePool);
}

View file

@ -5,14 +5,23 @@
#include "port/Engine.h"
#define DMEM_WET_SCRATCH 0x470
#define DMEM_COMPRESSED_ADPCM_DATA 0x990
#define DMEM_LEFT_CH 0x990
#define DMEM_RIGHT_CH 0xB10
#define DMEM_COMPRESSED_ADPCM_DATA 0xD50
#define DMEM_LEFT_CH 0xD50
#define DMEM_RIGHT_CH (DMEM_LEFT_CH + DMEM_1CH_SIZE)
#define DMEM_CENTER_CH (DMEM_LEFT_CH + 2 * DMEM_1CH_SIZE)
#define DMEM_SUBWOOFER_CH (DMEM_LEFT_CH + 3 * DMEM_1CH_SIZE)
#define DMEM_REAR_LEFT_CH (DMEM_LEFT_CH + 4 * DMEM_1CH_SIZE)
#define DMEM_REAR_RIGHT_CH (DMEM_LEFT_CH + 5 * DMEM_1CH_SIZE)
#define DMEM_HAAS_TEMP 0x650
#define DMEM_TEMP 0x450
#define DMEM_UNCOMPRESSED_NOTE 0x5F0
#define DMEM_WET_LEFT_CH 0xC90
#define DMEM_WET_RIGHT_CH 0xE10 // = DMEM_WET_LEFT_CH + DMEM_1CH_SIZE
#define DMEM_WET_LEFT_CH (DMEM_LEFT_CH + 6 * DMEM_1CH_SIZE)
#define DMEM_WET_RIGHT_CH (DMEM_WET_LEFT_CH + DMEM_1CH_SIZE)
#define DMEM_WET_CENTER_CH (DMEM_WET_LEFT_CH + 2 * DMEM_1CH_SIZE)
#define DMEM_WET_SUBWOOFER_CH (DMEM_WET_LEFT_CH + 3 * DMEM_1CH_SIZE)
#define DMEM_WET_REAR_LEFT_CH (DMEM_WET_LEFT_CH + 4 * DMEM_1CH_SIZE)
#define DMEM_WET_REAR_RIGHT_CH (DMEM_WET_LEFT_CH + 5 * DMEM_1CH_SIZE)
#define SAMPLE_SIZE sizeof(s16)
typedef enum {
@ -77,7 +86,7 @@ void AudioSynth_InitNextRingBuf(s32 sampleCount, s32 itemIndex, s32 reverbIndex)
if ((reverb->downsampleRate != 1) && (reverb->framesToIgnore == 0)) {
ringItem = &reverb->items[reverb->curFrame][itemIndex];
osInvalDCache(ringItem->toDownsampleLeft, 0x300);
osInvalDCache(ringItem->toDownsampleLeft, DMEM_1CH_SIZE * MAX_NUM_AUDIO_CHANNELS);
j = 0;
for (i = 0; i < ringItem->lengthA / 2; i++, j += reverb->downsampleRate) {
reverb->leftRingBuf[ringItem->startPos + i] = ringItem->toDownsampleLeft[j];
@ -675,6 +684,7 @@ Acmd* AudioSynth_Update(Acmd* aList, s32* cmdCount, s16* aiBufStart, s32 aiBufLe
}
aiBufPtr = aiBufStart;
for (i = gAudioBufferParams.ticksPerUpdate; i > 0; i--) {
if (i == 1) {
chunkLen = aiBufLen;
@ -693,9 +703,11 @@ Acmd* AudioSynth_Update(Acmd* aList, s32* cmdCount, s16* aiBufStart, s32 aiBufLe
}
aCmdPtr =
AudioSynth_DoOneAudioUpdate((s16*) aiBufPtr, chunkLen, aCmdPtr, gAudioBufferParams.ticksPerUpdate - i);
AudioSynth_DoOneAudioUpdate(aiBufPtr, chunkLen, aCmdPtr, gAudioBufferParams.ticksPerUpdate - i);
aiBufLen -= chunkLen;
aiBufPtr += chunkLen * 2;
int num_audio_channels = GetNumAudioChannels();
aiBufPtr += chunkLen * num_audio_channels;
}
for (j = 0; j < gNumSynthReverbs; j++) {
@ -723,7 +735,7 @@ Acmd* AudioSynth_LoadReverbSamples(Acmd* aList, s32 aiBufLen, s16 reverbIndex, s
aList =
AudioSynth_LoadRingBufferPart(aList, sp64->lengthA + DMEM_WET_LEFT_CH, 0, sp64->lengthB, reverbIndex);
}
aAddMixer(aList++, 0x300, DMEM_WET_LEFT_CH, DMEM_LEFT_CH);
aAddMixer(aList++, DMEM_2CH_SIZE, DMEM_WET_LEFT_CH, DMEM_LEFT_CH);
aMix(aList++, 0x30, gSynthReverbs[reverbIndex].decayRatio + 0x8000, DMEM_WET_LEFT_CH, DMEM_WET_LEFT_CH);
} else {
sp62 = (sp64->startPos & 7) * 2;
@ -739,7 +751,7 @@ Acmd* AudioSynth_LoadReverbSamples(Acmd* aList, s32 aiBufLen, s16 reverbIndex, s
aSetBuffer(aList++, 0, sp62 + DMEM_UNCOMPRESSED_NOTE, DMEM_WET_RIGHT_CH, aiBufLen * 2);
aResample(aList++, gSynthReverbs[reverbIndex].resampleFlags, gSynthReverbs[reverbIndex].unk_0A,
OS_K0_TO_PHYSICAL(gSynthReverbs[reverbIndex].unk_34));
aAddMixer(aList++, 0x300, DMEM_WET_LEFT_CH, DMEM_LEFT_CH);
aAddMixer(aList++, DMEM_2CH_SIZE, DMEM_WET_LEFT_CH, DMEM_LEFT_CH);
aMix(aList++, 0x30, gSynthReverbs[reverbIndex].decayRatio + 0x8000, DMEM_WET_LEFT_CH, DMEM_WET_LEFT_CH);
}
@ -768,7 +780,7 @@ Acmd* AudioSynth_SaveReverbSamples(Acmd* aList, s16 reverbIndex, s16 updateIndex
OS_K0_TO_PHYSICAL(gSynthReverbs[reverbIndex]
.items[gSynthReverbs[reverbIndex].curFrame][updateIndex]
.toDownsampleLeft),
0x300);
DMEM_2CH_SIZE);
gSynthReverbs[reverbIndex].resampleFlags = 0;
break;
}
@ -807,7 +819,7 @@ Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* aList, s32 upd
}
}
aClearBuffer(aList++, DMEM_LEFT_CH, DMEM_2CH_SIZE);
aClearBuffer(aList++, DMEM_LEFT_CH, DMEM_6CH_SIZE);
j = 0;
for (i = 0; i < gNumSynthReverbs; i++) {
@ -834,10 +846,13 @@ Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* aList, s32 upd
j++;
}
j = aiBufLen * 2;
int num_audio_channels = GetNumAudioChannels();
j = aiBufLen * num_audio_channels * sizeof(s16);
// Set rsp output buffer to DMEM_TEMP with size j
aSetBuffer(aList++, 0, 0, DMEM_TEMP, j);
aInterleave(aList++, DMEM_LEFT_CH, DMEM_RIGHT_CH);
aSaveBuffer(aList++, DMEM_TEMP, OS_K0_TO_PHYSICAL(aiBuf), j * 2);
aInterleave(aList++, DMEM_LEFT_CH, DMEM_RIGHT_CH, DMEM_CENTER_CH, DMEM_SUBWOOFER_CH, DMEM_REAR_LEFT_CH, DMEM_REAR_RIGHT_CH, num_audio_channels);
// Copy j bytes from DMEM_TEMP to aiBuf
aSaveBuffer(aList++, DMEM_TEMP, OS_K0_TO_PHYSICAL(aiBuf), j);
return aList;
}
@ -908,6 +923,10 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSub, NoteSynthesisSta
synthState->samplePosFrac = 0;
synthState->curVolLeft = 0;
synthState->curVolRight = 0;
synthState->curVolCenter = 0;
synthState->curVolLfe = 0;
synthState->curVolRLeft = 0;
synthState->curVolRRight = 0;
synthState->numParts = synthState->prevHaasEffectRightDelaySize = synthState->prevHaasEffectLeftDelaySize = 0;
note->noteSubEu.bitField0.finished = 0;
}
@ -1288,74 +1307,90 @@ Acmd* AudioSynth_FinalResample(Acmd* aList, NoteSynthesisState* synthState, s32
Acmd* AudioSynth_ProcessEnvelope(Acmd* aList, NoteSubEu* noteSub, NoteSynthesisState* synthState, s32 aiBufLen,
u16 dmemSrc, s32 delaySide, s32 flags) {
s16 rampReverb;
s16 rampRight;
s16 rampLeft;
u16 panVolLeft;
u16 panVolRight;
u16 curVolLeft;
u16 curVolRight;
s16 rampRight = 0, rampLeft = 0, rampCenter = 0, rampLfe = 0, rampRLeft = 0, rampRRight = 0;
u16 panVolLeft, panVolRight, panVolCenter, panVolLfe, panVolRLeft, panVolRRight;
u16 curVolLeft, curVolRight, curVolCenter, curVolLfe, curVolRLeft, curVolRRight;
s32 sourceReverbVol;
s32 temp = 0;
curVolLeft = synthState->curVolLeft;
curVolRight = synthState->curVolRight;
curVolCenter = synthState->curVolCenter;
curVolLfe = synthState->curVolLfe;
curVolRLeft = synthState->curVolRLeft;
curVolRRight = synthState->curVolRRight;
panVolLeft = noteSub->panVolLeft;
panVolRight = noteSub->panVolRight;
panVolLeft <<= 4;
panVolRight <<= 4;
panVolLeft = 16 * noteSub->panVolLeft;
panVolRight = 16 * noteSub->panVolRight;
panVolCenter = 16 * noteSub->panVolCenter;
panVolLfe = 16 * noteSub->panVolLfe;
panVolRLeft = 16 * noteSub->panVolRLeft;
panVolRRight = 16 * noteSub->panVolRRight;
s32 aiBufLenSmall = aiBufLen >> 3;
if (panVolLeft != curVolLeft) {
rampLeft = (panVolLeft - curVolLeft) / (aiBufLen >> 3);
} else {
rampLeft = 0;
rampLeft = (panVolLeft - curVolLeft) / aiBufLenSmall;
}
if (panVolRight != curVolRight) {
rampRight = (panVolRight - curVolRight) / (aiBufLen >> 3);
} else {
rampRight = 0;
rampRight = (panVolRight - curVolRight) / aiBufLenSmall;
}
if (panVolRLeft != curVolRLeft) {
rampRLeft = (panVolRLeft - curVolRLeft) / aiBufLenSmall;
}
if (panVolRRight != curVolRRight) {
rampRRight = (panVolRRight - curVolRRight) / aiBufLenSmall;
}
if (panVolCenter != curVolCenter) {
rampCenter = (panVolCenter - curVolCenter) / aiBufLenSmall;
}
if (panVolLfe != curVolLfe) {
rampLfe = (panVolLfe - curVolLfe) / aiBufLenSmall;
}
sourceReverbVol = synthState->reverbVol;
if (noteSub->reverb != sourceReverbVol) {
temp = (((noteSub->reverb & 0x7F) - (sourceReverbVol & 0x7F)) << 8);
rampReverb = temp / (aiBufLen >> 3);
rampReverb = temp / aiBufLenSmall;
synthState->reverbVol = noteSub->reverb;
} else {
rampReverb = 0;
}
synthState->curVolLeft = curVolLeft + (rampLeft * (aiBufLen >> 3));
synthState->curVolRight = curVolRight + (rampRight * (aiBufLen >> 3));
synthState->curVolLeft = curVolLeft + (rampLeft * aiBufLenSmall);
synthState->curVolRight = curVolRight + (rampRight * aiBufLenSmall);
synthState->curVolCenter = curVolCenter + (rampCenter * aiBufLenSmall);
synthState->curVolLfe = curVolLfe + (rampLfe * aiBufLenSmall);
synthState->curVolRLeft = curVolRLeft + (rampRLeft * aiBufLenSmall);
synthState->curVolRRight = curVolRRight + (rampRRight * aiBufLenSmall);
if (noteSub->bitField0.usesHeadsetPanEffects) {
int32_t num_audio_channels = 2;
aClearBuffer(aList++, DMEM_HAAS_TEMP, DMEM_1CH_SIZE);
aEnvSetup1(aList++, (sourceReverbVol & 0x7F), rampReverb, rampLeft, rampRight);
aEnvSetup2(aList++, curVolLeft, curVolRight);
aEnvSetup1(aList++, (sourceReverbVol & 0x7F), rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight);
aEnvSetup2(aList++, curVolLeft, curVolRight, curVolCenter, curVolLfe, curVolRLeft, curVolRRight);
switch (delaySide) {
case HAAS_EFFECT_DELAY_LEFT:
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x65B1C9E1, 0);
aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP << 16, num_audio_channels);
break;
case HAAS_EFFECT_DELAY_RIGHT:
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x9965C9E1, 0);
aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, DMEM_HAAS_TEMP, num_audio_channels);
break;
default: // HAAS_EFFECT_DELAY_NONE
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1, 0);
aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, num_audio_channels);
break;
}
} else {
aEnvSetup1(aList++, (sourceReverbVol & 0x7F), rampReverb, rampLeft, rampRight);
aEnvSetup2(aList++, curVolLeft, curVolRight);
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1, 0);
aEnvSetup1(aList++, (sourceReverbVol & 0x7F), rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight);
aEnvSetup2(aList++, curVolLeft, curVolRight, curVolCenter, curVolLfe, curVolRLeft, curVolRRight);
aEnvMixer(aList++, dmemSrc, aiBufLen, ((sourceReverbVol & 0x80) >> 7),
noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, (DMEM_WET_LEFT_CH << 16) | DMEM_LEFT_CH, 0, GetNumAudioChannels());
}
return aList;

View file

@ -82,7 +82,7 @@ void AudioThread_CreateNextAudioBuffer(s16* samples, u32 num_samples) {
AudioSynth_Update(gCurAbiCmdBuffer, &abiCmdCount, samples, num_samples);
// Spectrum Analyzer fix
memcpy(gAiBuffers[gCurAiBuffIndex], samples, num_samples);
memcpy(gAiBuffers[gCurAiBuffIndex], samples, num_samples * sizeof(s16));
gAudioRandom = osGetCount() * (gAudioRandom + gAudioTaskCountQ);
}
@ -186,7 +186,7 @@ SPTask* AudioThread_CreateTask() {
task->output_buff = NULL;
task->output_buff_size = NULL;
if (1) {}
task->data_ptr = (u64*) gAbiCmdBuffs[aiBuffIndex];
task->data_size = abiCmdCount * sizeof(Acmd);
@ -438,6 +438,14 @@ void AudioThread_ProcessCmds(u32 msg) {
case AUDIOCMD_OP_CHANNEL_SET_IO:
if (cmd->arg2 < 8) {
channel->seqScriptIO[cmd->arg2] = cmd->asSbyte;
// Mark the audio as voice, sfx or bgm
channel->is_voice = 0;
channel->is_sfx = 0;
if (cmd->arg0 == SEQ_PLAYER_VOICE) {
channel->is_voice = 1;
} else if (cmd->arg0 == SEQ_PLAYER_SFX) {
channel->is_sfx = 1;
}
}
break;
case AUDIOCMD_OP_CHANNEL_SET_MUTE:

View file

@ -2,6 +2,7 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <macros.h>
@ -71,18 +72,20 @@ static __m128i m256i_clamp_to_m128i(m256i a) {
#define ROUND_UP_8(v) (((v) + 7) & ~7)
#define ROUND_DOWN_16(v) ((v) & ~0xf)
#define DMEM_BUF_SIZE (0x1000)
// #define DMEM_BUF_SIZE 0xC90
#define BUF_U8(a) (rspa.buf.as_u8 + ((a)-0x450))
#define BUF_S16(a) (rspa.buf.as_s16 + ((a)-0x450) / sizeof(int16_t))
#define DMEM_BUF_SIZE (0x1B90) // 7056 B
#define BUF_U8(a) (rspa.buf + ((a)-0x450))
#define BUF_S16(a) (int16_t*) BUF_U8(a)
#define SAMPLE_RATE 32000 // Adjusted to match the actual sample rate of 32 kHz
#define CUTOFF_FREQ_LFE 80 // Cutoff frequency of 80 Hz
static struct {
uint16_t in;
uint16_t out;
uint16_t nbytes;
uint16_t vol[2];
uint16_t rate[2];
uint16_t vol[6];
uint16_t rate[6];
uint16_t vol_wet;
uint16_t rate_wet;
@ -93,10 +96,7 @@ static struct {
uint16_t filter_count;
int16_t filter[8];
union {
int16_t as_s16[DMEM_BUF_SIZE / sizeof(int16_t)];
uint8_t as_u8[DMEM_BUF_SIZE];
} buf;
uint8_t buf[DMEM_BUF_SIZE];
} rspa;
static int16_t resample_table[64][4] = {
@ -183,87 +183,38 @@ void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes) {
rspa.nbytes = nbytes;
}
#if 1
// old abi impl
void aInterleaveImpl(uint16_t left, uint16_t right) {
if(rspa.nbytes == 0) { // Added
void aInterleaveImpl(uint16_t left, uint16_t right, uint16_t center, uint16_t lfe, uint16_t surround_left, uint16_t surround_right, uint16_t num_channels) {
if (rspa.nbytes == 0) {
return;
}
int count = ROUND_UP_16(rspa.nbytes) >> 3;
int16_t *l = BUF_S16(left);
int16_t *r = BUF_S16(right);
int16_t *d = BUF_S16(rspa.out);
while (count > 0) {
int16_t l0 = *l++;
int16_t l1 = *l++;
int16_t l2 = *l++;
int16_t l3 = *l++;
int16_t l4 = *l++;
int16_t l5 = *l++;
int16_t l6 = *l++;
int16_t l7 = *l++;
int16_t r0 = *r++;
int16_t r1 = *r++;
int16_t r2 = *r++;
int16_t r3 = *r++;
int16_t r4 = *r++;
int16_t r5 = *r++;
int16_t r6 = *r++;
int16_t r7 = *r++;
*d++ = l0;
*d++ = r0;
*d++ = l1;
*d++ = r1;
*d++ = l2;
*d++ = r2;
*d++ = l3;
*d++ = r3;
*d++ = l4;
*d++ = r4;
*d++ = l5;
*d++ = r5;
*d++ = l6;
*d++ = r6;
*d++ = l7;
*d++ = r7;
--count;
}
}
#else
// new abi
void aInterleaveImpl(uint16_t dest, uint16_t left, uint16_t right, uint16_t c) {
if(rspa.nbytes == 0){
return;
}
int count = ROUND_UP_16(rspa.nbytes) >> 3;
int count = rspa.nbytes / (num_channels * sizeof(int16_t));
int16_t *l = BUF_S16(left);
int16_t *r = BUF_S16(right);
int16_t *d = BUF_S16(rspa.out);
while (count > 0) {
int16_t l0 = *l++;
int16_t l1 = *l++;
int16_t l2 = *l++;
int16_t l3 = *l++;
int16_t r0 = *r++;
int16_t r1 = *r++;
int16_t r2 = *r++;
int16_t r3 = *r++;
*d++ = l0;
*d++ = r0;
*d++ = l1;
*d++ = r1;
*d++ = l2;
*d++ = r2;
*d++ = l3;
*d++ = r3;
--count;
if (num_channels == 2) {
for (int i = 0; i < count; i++) {
*d++ = *l++;
*d++ = *r++;
}
} else {
int16_t *c = BUF_S16(center);
int16_t *lf = BUF_S16(lfe);
int16_t *sl = BUF_S16(surround_left);
int16_t *sr = BUF_S16(surround_right);
for (int i = 0; i < count; i++) {
*d++ = *l++;
*d++ = *r++;
*d++ = *c++;
*d++ = *lf++;
*d++ = *sl++;
*d++ = *sr++;
}
}
}
#endif
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) {
nbytes = ROUND_UP_16(nbytes);
@ -300,19 +251,19 @@ void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state) {
int16_t prev1 = out[-1];
int16_t prev2 = out[-2];
int j, k;
if (flags & 4) {
for (j = 0; j < 2; j++) {
ins[j * 4] = (((*in >> 6) << 30) >> 30) << shift;
ins[j * 4 + 1] = ((((*in >> 4) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 2] = ((((*in >> 2) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 3] = (((*in++ & 0x3) << 30) >> 30) << shift;
}
} else {
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
}
if (flags & 4) {
for (j = 0; j < 2; j++) {
ins[j * 4] = (((*in >> 6) << 30) >> 30) << shift;
ins[j * 4 + 1] = ((((*in >> 4) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 2] = ((((*in >> 2) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 3] = (((*in++ & 0x3) << 30) >> 30) << shift;
}
} else {
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
}
for (j = 0; j < 8; j++) {
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
for (k = 0; k < j; k++) {
@ -670,111 +621,152 @@ void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state) {
#endif
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right) {
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right,
uint16_t rate_center, uint16_t rate_lfe, uint16_t rate_rear_left, uint16_t rate_rear_right) {
rspa.vol_wet = (uint16_t)(initial_vol_wet << 8);
rspa.rate_wet = rate_wet;
rspa.rate[0] = rate_left;
rspa.rate[1] = rate_right;
rspa.rate[2] = rate_center;
rspa.rate[3] = rate_lfe;
rspa.rate[4] = rate_rear_left;
rspa.rate[5] = rate_rear_right;
}
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right) {
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right, int16_t initial_vol_center,
int16_t initial_vol_lfe, int16_t initial_vol_rear_left, int16_t initial_vol_rear_right) {
rspa.vol[0] = initial_vol_left;
rspa.vol[1] = initial_vol_right;
rspa.vol[2] = initial_vol_center;
rspa.vol[3] = initial_vol_lfe;
rspa.vol[4] = initial_vol_rear_left;
rspa.vol[5] = initial_vol_rear_right;
}
#ifndef SSE2_AVAILABLE
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb,
bool neg_3, bool neg_2,
bool neg_left, bool neg_right,
int32_t wet_dry_addr, uint32_t unk)
uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels)
{
// Note: max number of samples is 192 (192 * 2 = 384 bytes = 0x180)
int max_num_samples = 192;
int16_t *in = BUF_S16(in_addr);
int16_t *dry[2] = {BUF_S16(((wet_dry_addr >> 24) & 0xFF) << 4), BUF_S16(((wet_dry_addr >> 16) & 0xFF) << 4)};
int16_t *wet[2] = {BUF_S16(((wet_dry_addr >> 8) & 0xFF) << 4), BUF_S16(((wet_dry_addr) & 0xFF) << 4)};
int16_t negs[4] = {neg_left ? -1 : 0, neg_right ? -1 : 0, neg_3 ? -4 : 0, neg_2 ? -2 : 0};
int n = ROUND_UP_16(n_samples);
if (n > max_num_samples) {
printf("Warning: n_samples is too large: %d\n", n_samples);
}
uint16_t rate_wet = rspa.rate_wet;
uint16_t vol_wet = rspa.vol_wet;
// All speakers
int dry_addr_start = wet_dry_addr & 0xFFFF;
int wet_addr_start = wet_dry_addr >> 16;
int16_t *dry[6];
int16_t *wet[6];
for (int i = 0; i < 6; i++) {
dry[i] = BUF_S16(dry_addr_start + max_num_samples * i * sizeof(int16_t));
wet[i] = BUF_S16(wet_addr_start + max_num_samples * i * sizeof(int16_t));
}
uint16_t vols[6] = {rspa.vol[0], rspa.vol[1], rspa.vol[2], rspa.vol[3], rspa.vol[4], rspa.vol[5]};
int swapped[2] = {swap_reverb ? 1 : 0, swap_reverb ? 0 : 1};
int n = ROUND_UP_16(n_samples);
uint16_t vols[2] = {rspa.vol[0], rspa.vol[1]};
uint16_t rates[2] = {rspa.rate[0], rspa.rate[1]};
uint16_t vol_wet = rspa.vol_wet;
uint16_t rate_wet = rspa.rate_wet;
if (num_channels == 6) {
// Calculate the filter coefficient
float RC = 1.f / (2 * M_PI * CUTOFF_FREQ_LFE);
float dt = 1.f / SAMPLE_RATE;
float alpha = dt / (RC + dt);
// Low-pass filter state for the subwoofer channel
static float prev_lfe_sample = 0.0f;
for (int i = 0; i < n / 8; i++) {
for (int k = 0; k < 8; k++) {
int16_t samples[6] = {0};
samples[0] = *in;
samples[1] = *in;
samples[2] = *in;
samples[3] = *in; // LFE channel
samples[4] = *in;
samples[5] = *in;
in++;
// Apply volume
for (int j = 0; j < 6; j++) {
samples[j] = samples[j] * vols[j] >> 16;
}
// Apply low-pass filter to the LFE channel (index 3)
float lfe_sample = samples[3];
lfe_sample = alpha * lfe_sample + (1.0f - alpha) * prev_lfe_sample;
prev_lfe_sample = lfe_sample;
samples[3] = (int16_t)lfe_sample;
// Mix dry and wet signals
for (int j = 0; j < 6; j++) {
*dry[j] = clamp16(*dry[j] + samples[j]);
dry[j]++;
if (j >= 4) {
// Apply reverb only to the rear channels (4 and 5)
*wet[j] = clamp16(*wet[j] + (samples[swapped[j % 2]] * vol_wet >> 16));
wet[j]++;
}
}
}
for (int j = 0; j < 6; j++) {
vols[j] += rspa.rate[j];
}
vol_wet += rate_wet;
}
} else {
// Account for haas effect
int haas_addr_left = haas_temp_addr >> 16;
int haas_addr_right = haas_temp_addr & 0xFFFF;
if (haas_addr_left) {
dry[0] = BUF_S16(haas_addr_left);
} else if (haas_addr_right) {
dry[1] = BUF_S16(haas_addr_right);
}
int16_t negs[2] = {neg_left ? 0 : 0xFFFF, neg_right ? 0 : 0xFFFF};
for (int i = 0; i < n / 8; i++) {
for (int k = 0; k < 8; k++) {
int16_t samples[2] = {0};
samples[0] = *in;
samples[1] = *in;
in++;
// Apply volume
for (int j = 0; j < 2; j++) {
samples[j] = (samples[j] * vols[j] >> 16) & negs[j];
}
// Mix dry and wet signals
for (int j = 0; j < 2; j++) {
*dry[j] = clamp16(*dry[j] + samples[j]);
dry[j]++;
// Apply reverb
*wet[j] = clamp16(*wet[j] + (samples[swapped[j]] * vol_wet >> 16));
wet[j]++;
}
}
do {
for (int i = 0; i < 8; i++) {
int16_t samples[2] = {*in, *in}; in++;
for (int j = 0; j < 2; j++) {
samples[j] = (samples[j] * vols[j] >> 16) ^ negs[j];
}
for (int j = 0; j < 2; j++) {
*dry[j] = clamp16(*dry[j] + samples[j]); dry[j]++;
*wet[j] = clamp16(*wet[j] + ((samples[swapped[j]] * vol_wet >> 16) ^ negs[2 + j])); wet[j]++;
vols[j] += rspa.rate[j];
}
vol_wet += rate_wet;
}
vols[0] += rates[0];
vols[1] += rates[1];
vol_wet += rate_wet;
n -= 8;
} while (n > 0);
}
#else
// SSE2 optimized version of algorithm
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb,
bool neg_3, bool neg_2,
bool neg_left, bool neg_right,
int32_t wet_dry_addr, u32 unk)
{
int16_t *in = BUF_S16(in_addr);
int16_t *dry[2] = {BUF_S16(((wet_dry_addr >> 24) & 0xFF) << 4), BUF_S16(((wet_dry_addr >> 16) & 0xFF) << 4)};
int16_t *wet[2] = {BUF_S16(((wet_dry_addr >> 8) & 0xFF) << 4), BUF_S16(((wet_dry_addr) & 0xFF) << 4)};
int16_t negs[4] = {neg_left ? -1 : 0, neg_right ? -1 : 0, neg_3 ? -4 : 0, neg_2 ? -2 : 0};
int n = ROUND_UP_16(n_samples);
const int n_aligned = n - (n % 8);
uint16_t vols[2] = {rspa.vol[0], rspa.vol[1]};
uint16_t rates[2] = {rspa.rate[0], rspa.rate[1]};
uint16_t vol_wet = rspa.vol_wet;
uint16_t rate_wet = rspa.rate_wet;
const __m128i* in_ptr = (__m128i*)in;
const __m128i* d_ptr[2] = { (__m128i*) dry[0], (__m128i*) dry[1] };
const __m128i* w_ptr[2] = { (__m128i*) wet[0], (__m128i*) wet[1] };
// Aligned loop
for (int N = 0; N < n_aligned; N+=8) {
// Init vectors
const __m128i in_channels = _mm_loadu_si128(in_ptr++);
__m128i d[2] = { _mm_loadu_si128(d_ptr[0]), _mm_loadu_si128(d_ptr[1]) };
__m128i w[2] = { _mm_loadu_si128(w_ptr[0]), _mm_loadu_si128(w_ptr[1]) };
// Compute base samples
// sample = ((in * vols) >> 16) ^ negs
__m128i s[2] = {
_mm_xor_si128(_mm_mulhi_epi16(in_channels, _mm_set1_epi16(vols[0])), _mm_set1_epi16(negs[0])),
_mm_xor_si128(_mm_mulhi_epi16(in_channels, _mm_set1_epi16(vols[1])), _mm_set1_epi16(negs[1]))
};
// Compute left swapped samples
// (sample * vol_wet) >> 16) ^ negs
__m128i ss[2] = {
_mm_xor_si128(_mm_mulhi_epi16(s[swap_reverb], _mm_set1_epi16(vol_wet)), _mm_set1_epi16(negs[2])),
_mm_xor_si128(_mm_mulhi_epi16(s[!swap_reverb], _mm_set1_epi16(vol_wet)), _mm_set1_epi16(negs[3]))
};
// Store values to buffers
for (int j = 0; j < 2; j++) {
_mm_storeu_si128((__m128i*) d_ptr[j]++, _mm_adds_epi16(s[j], d[j]));
_mm_storeu_si128((__m128i*) w_ptr[j]++, _mm_adds_epi16(ss[j], w[j]));
vols[j] += rates[j];
}
vol_wet += rate_wet;
}
}
#endif
#ifndef SSE2_AVAILABLE

View file

@ -37,15 +37,17 @@ void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbyte
void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes);
void aLoadADPCMImpl(int num_entries_times_16, const int16_t* book_source_addr);
void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes);
void aInterleaveImpl(uint16_t left, uint16_t right);
void aInterleaveImpl(uint16_t left, uint16_t right, uint16_t center, uint16_t lfe, uint16_t surround_left, uint16_t surround_right, uint16_t num_audio_channels);
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes);
void aSetLoopImpl(ADPCM_STATE* adpcm_loop_state);
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state);
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state);
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right);
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right);
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool neg_3, bool neg_2, bool neg_left,
bool neg_right, int32_t wet_dry_addr, u32 unk);
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right,
uint16_t rate_center, uint16_t rate_lfe, uint16_t rate_rear_left, uint16_t rate_rear_right);
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right, int16_t initial_vol_center,
int16_t initial_vol_lfe, int16_t initial_vol_rear_left, int16_t initial_vol_rear_right);
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool neg_left,
bool neg_right, uint32_t wet_dry_addr, uint32_t haas_temp_addr, uint32_t num_channels);
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
void aS8DecImpl(uint8_t flags, ADPCM_STATE state);
void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr);
@ -65,16 +67,17 @@ void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_add
#define aSaveBuffer(pkt, s, d, c) aSaveBufferImpl(s, d, c)
#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, d)
#define aSetBuffer(pkt, f, i, o, c) aSetBufferImpl(f, i, o, c)
#define aInterleave(pkt, l, r) aInterleaveImpl(l, r)
#define aInterleave(pkt, l, r, c, lfe, sl, sr, num_channels) aInterleaveImpl(l, r, c, lfe, sl, sr, num_channels)
#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c)
#define aSetLoop(pkt, a) aSetLoopImpl(a)
#define aADPCMdec(pkt, f, s) aADPCMdecImpl(f, s)
#define aResample(pkt, f, p, s) aResampleImpl(f, p, s)
#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight) \
aEnvSetup1Impl(initialVolReverb, rampReverb, rampLeft, rampRight)
#define aEnvSetup2(pkt, initialVolLeft, initialVolRight) aEnvSetup2Impl(initialVolLeft, initialVolRight)
#define aEnvMixer(pkt, inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight) \
aEnvMixerImpl(inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight)
#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight) \
aEnvSetup1Impl(initialVolReverb, rampReverb, rampLeft, rampRight, rampCenter, rampLfe, rampRLeft, rampRRight)
#define aEnvSetup2(pkt, initialVolLeft, initialVolRight, initialVolCenter, initialVolLfe, initialVolRLeft, initialVolRRight) \
aEnvSetup2Impl(initialVolLeft, initialVolRight, initialVolCenter, initialVolLfe, initialVolRLeft, initialVolRRight)
#define aEnvMixer(pkt, inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels) \
aEnvMixerImpl(inAddr, nSamples, swapReverb, negLeft, negRight, wetDryAddr, haasTempAddr, numChannels)
#define aMix(pkt, c, g, i, o) aMixImpl(c, g, i, o)
#define aS8Dec(pkt, f, s) aS8DecImpl(f, s)
#define aAddMixer(pkt, s, d, c) aAddMixerImpl(s, d, c)

View file

@ -166,7 +166,8 @@ GameEngine::GameEngine() {
auto window = std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({}));
this->context->Init(archiveFiles, {}, 3, { 32000, 1024, 1680 }, window, controlDeck);
AudioSurroundSetting surroundSetting = Ship::Context::GetInstance()->GetConfig()->GetCurrentAudioSurround();
this->context->Init(archiveFiles, {}, 3, { 32000, 1024, 1680, surroundSetting }, window, controlDeck);
#ifndef __SWITCH__
Ship::Context::GetInstance()->GetLogger()->set_level(
@ -341,7 +342,7 @@ void GameEngine::StartFrame() const {
#endif
#define NUM_AUDIO_CHANNELS 2
#define MAX_NUM_AUDIO_CHANNELS 6
extern "C" u16 audBuffer = 0;
#include <sf64audio_provisional.h>
@ -371,6 +372,7 @@ void GameEngine::HandleAudioThread() {
// gVIsPerFrame = 2;
#define AUDIO_FRAMES_PER_UPDATE (gVIsPerFrame > 0 ? gVIsPerFrame : 1)
#define MAX_AUDIO_FRAMES_PER_UPDATE 3 // Compile-time constant with max value of gVIsPerFrame
std::unique_lock<std::mutex> Lock(audio.mutex);
int samples_left = AudioPlayerBuffered();
@ -382,19 +384,22 @@ void GameEngine::HandleAudioThread() {
countermin++;
}
s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3] = { 0 };
const int32_t num_audio_channels = GetNumAudioChannels();
s16 audio_buffer[SAMPLES_HIGH * MAX_NUM_AUDIO_CHANNELS * MAX_AUDIO_FRAMES_PER_UPDATE] = { 0 };
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
AudioThread_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS),
AudioThread_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * num_audio_channels),
num_audio_samples);
}
#ifdef PIPE_DEBUG
if (outfile.is_open()) {
outfile.write(reinterpret_cast<char*>(audio_buffer),
num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
num_audio_samples * (sizeof(int16_t) * num_audio_channels * AUDIO_FRAMES_PER_UPDATE));
}
#endif
AudioPlayerPlayFrame((u8*) audio_buffer,
num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
num_audio_samples * (sizeof(int16_t) * num_audio_channels * AUDIO_FRAMES_PER_UPDATE));
audio.processing = false;
audio.cv_from_thread.notify_one();
}

View file

@ -172,6 +172,8 @@ void DrawSettingsMenu(){
UIWidgets::ReEnableComponent("");
}
UIWidgets::PaddedEnhancementCheckbox("Surround 5.1 (needs reload)", "gSurroundAudio", true, false);
ImGui::EndMenu();
}

1
tools/SDL3 Submodule

@ -0,0 +1 @@
Subproject commit 69d28027adb70daf962621bb5e8ab00a069cbe30

@ -1 +1 @@
Subproject commit 228a17c68282092b6c3937c46b943229388931fe
Subproject commit db4cb9a493e0dfee8e8fa6dc529390bb3321a771