mirror of
https://github.com/HarbourMasters/Starship.git
synced 2025-04-28 20:37:58 +03:00
Add 6-channel audio support.
This commit is contained in:
parent
94553db6c1
commit
798f6fbe1f
13 changed files with 433 additions and 326 deletions
|
@ -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
|
|
@ -454,13 +454,17 @@ 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;
|
||||
}
|
||||
|
||||
if (GetNumAudioChannels() == 2) {
|
||||
float pan;
|
||||
absx = MIN(1200.0f, absx);
|
||||
absz = MIN(1200.0f, absz);
|
||||
|
||||
|
@ -474,6 +478,13 @@ s8 Audio_GetSfxPan(f32 xPos, f32 zPos, u8 mode) {
|
|||
pan = (xPos / (2.5f * absz)) + 0.5f;
|
||||
}
|
||||
return ROUND(pan * 127.0f);
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
} 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:
|
||||
|
|
|
@ -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,6 +85,8 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
|
|||
pan = noteAttr->pan;
|
||||
reverb = noteAttr->reverb;
|
||||
stereo = noteAttr->stereo;
|
||||
|
||||
if (GetNumAudioChannels() == 2) {
|
||||
pan %= ARRAY_COUNTU(gHeadsetPanVolume);
|
||||
if ((noteSub->bitField0.stereoHeadsetEffects) && (gAudioSoundMode == SOUNDMODE_HEADSET)) {
|
||||
var_a0 = pan >> 1;
|
||||
|
@ -97,16 +98,14 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
|
|||
noteSub->bitField0.stereoStrongRight = false;
|
||||
noteSub->bitField0.stereoStrongLeft = false;
|
||||
noteSub->bitField0.usesHeadsetPanEffects = true;
|
||||
|
||||
panVolumeLeft = gHeadsetPanVolume[pan];
|
||||
pamVolumeRight = gHeadsetPanVolume[ARRAY_COUNT(gHeadsetPanVolume) - 1 - 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];
|
||||
pamVolumeRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan];
|
||||
panVolumeRight = gStereoPanVolume[ARRAY_COUNT(gStereoPanVolume) - 1 - pan];
|
||||
strongRight = false;
|
||||
strongLeft = false;
|
||||
if (pan < 32) {
|
||||
|
@ -134,11 +133,47 @@ void Audio_InitNoteSub(Note* note, NoteAttributes* noteAttr) {
|
|||
}
|
||||
} else if (gAudioSoundMode == SOUNDMODE_MONO) {
|
||||
panVolumeLeft = 0.707f;
|
||||
pamVolumeRight = 0.707f;
|
||||
panVolumeRight = 0.707f;
|
||||
} else {
|
||||
panVolumeLeft = gDefaultPanVolume[pan];
|
||||
pamVolumeRight = gDefaultPanVolume[ARRAY_COUNT(gDefaultPanVolume) - 1 - pan];
|
||||
panVolumeRight = gDefaultPanVolume[ARRAY_COUNT(gDefaultPanVolume) - 1 - pan];
|
||||
}
|
||||
} else {
|
||||
// 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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
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) {
|
||||
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;
|
||||
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);
|
||||
|
@ -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);
|
||||
|
||||
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];
|
||||
// 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;
|
||||
}
|
||||
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]++;
|
||||
|
||||
// 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]++;
|
||||
}
|
||||
}
|
||||
vols[0] += rates[0];
|
||||
vols[1] += rates[1];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
n -= 8;
|
||||
} while (n > 0);
|
||||
if (haas_addr_left) {
|
||||
dry[0] = BUF_S16(haas_addr_left);
|
||||
} else if (haas_addr_right) {
|
||||
dry[1] = BUF_S16(haas_addr_right);
|
||||
}
|
||||
|
||||
#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);
|
||||
int16_t negs[2] = {neg_left ? 0 : 0xFFFF, neg_right ? 0 : 0xFFFF};
|
||||
|
||||
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;
|
||||
for (int i = 0; i < n / 8; i++) {
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int16_t samples[2] = {0};
|
||||
|
||||
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] };
|
||||
samples[0] = *in;
|
||||
samples[1] = *in;
|
||||
in++;
|
||||
|
||||
// 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
|
||||
// Apply volume
|
||||
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];
|
||||
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]++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
vols[j] += rspa.rate[j];
|
||||
}
|
||||
vol_wet += rate_wet;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SSE2_AVAILABLE
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -172,6 +172,8 @@ void DrawSettingsMenu(){
|
|||
UIWidgets::ReEnableComponent("");
|
||||
}
|
||||
|
||||
UIWidgets::PaddedEnhancementCheckbox("Surround 5.1 (needs reload)", "gSurroundAudio", true, false);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
|
1
tools/SDL3
Submodule
1
tools/SDL3
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 69d28027adb70daf962621bb5e8ab00a069cbe30
|
|
@ -1 +1 @@
|
|||
Subproject commit 228a17c68282092b6c3937c46b943229388931fe
|
||||
Subproject commit db4cb9a493e0dfee8e8fa6dc529390bb3321a771
|
Loading…
Add table
Add a link
Reference in a new issue