Backport 2ship streamed audio (#5457)

* Bring over changes from 2ship

# Conflicts:
#	.github/workflows/apt-deps.txt
#	soh/CMakeLists.txt
#	soh/soh/resource/importer/AudioSampleFactory.h
#	soh/soh/resource/importer/AudioSequenceFactory.cpp
#	soh/soh/resource/importer/AudioSequenceFactory.h
#	soh/soh/resource/importer/AudioSoundFontFactory.h

* Update xml format

* Format and fix mixer for Windows

* Fixes for new LUS

* Good ole clang-format
This commit is contained in:
louist103
2025-06-28 00:15:02 +00:00
committed by GitHub
parent 9e686ae6f6
commit e15f8d395b
47 changed files with 8478 additions and 19613 deletions

View File

@@ -41,7 +41,7 @@ void func_800DDE3C(void) {
void AudioHeap_ResetLoadStatus(void) {
s32 i;
for (i = 0; i < 0x30; i++) {
for (i = 0; i < fontMapSize; i++) {
if (gAudioContext.fontLoadStatus[i] != 5) {
gAudioContext.fontLoadStatus[i] = 0;
}
@@ -940,7 +940,7 @@ void AudioHeap_Init(void) {
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
reverb->loop.start = 0;
reverb->loop.count = 1;
reverb->loop.end = reverb->windowSize;
reverb->loop.loopEnd = reverb->windowSize;
if (reverb->downsampleRate != 1) {
reverb->unk_0E = 0x8000 / reverb->downsampleRate;

View File

@@ -8,6 +8,10 @@
#include "soh/Enhancements/audio/AudioCollection.h"
#include "soh/Enhancements/audio/AudioEditor.h"
#include "soh/ResourceManagerHelpers.h"
#include <stdio.h>
#ifdef _MSC_VER
#define strdup _strdup
#endif
#define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status))
#define ASYNC_TBLTYPE(v) ((u8)(v >> 16))
@@ -82,7 +86,8 @@ char** sequenceMap;
size_t sequenceMapSize;
// A map of authentic sequence IDs to their cache policies, for use with sequence swapping.
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
char* fontMap[256];
size_t fontMapSize;
char** fontMap;
uintptr_t fontStart;
uint32_t fontOffsets[8192];
@@ -419,7 +424,7 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 arg1) {
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
void* sampleAddr;
if (sample->unk_bit25 == 1) {
if (sample->isRelocated == 1) {
if (sample->medium != MEDIUM_RAM) {
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
CACHE_PERSISTENT);
@@ -701,7 +706,7 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
sampleBankId1 = sf->sampleBankId1;
sampleBankId2 = sf->sampleBankId2;
@@ -759,7 +764,7 @@ uintptr_t AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
cachePolicy = sData.cachePolicy;
romAddr = 0;
} else if (tableType == FONT_TABLE) {
fnt = ResourceMgr_LoadAudioSoundFont(fontMap[id]);
fnt = ResourceMgr_LoadAudioSoundFontByName(fontMap[id]);
size = sizeof(SoundFont);
medium = 2;
cachePolicy = 0;
@@ -887,6 +892,7 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) {
}
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo) {
return;
uintptr_t reloc;
uintptr_t reloc2;
Instrument* inst;
@@ -898,7 +904,7 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
s32 numInstruments = 0;
s32 numSfx = 0;
sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
@@ -1247,12 +1253,13 @@ int strcmp_sort(const void* str1, const void* str2) {
}
void AudioLoad_Init(void* heap, size_t heapSize) {
char pad[0x48];
s32 pad1[9];
s32 numFonts;
void* temp_v0_3;
s32 pad2[2];
u8* audioCtxPtr;
void* addr;
s32 i;
u64* heapP;
s16* u2974p;
s32 j;
D_801755D0 = NULL;
gAudioContext.resetTimer = 0;
@@ -1266,10 +1273,12 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.unk_2960 = 20.03042f;
gAudioContext.refreshRate = 50;
break;
case OS_TV_MPAL:
gAudioContext.unk_2960 = 16.546f;
gAudioContext.refreshRate = 60;
break;
case OS_TV_NTSC:
default:
gAudioContext.unk_2960 = 16.713f;
@@ -1278,7 +1287,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
Audio_InitMesgQueues();
for (i = 0; i < 3; i++) {
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) {
gAudioContext.aiBufLengths[i] = 0xA0;
}
@@ -1289,12 +1298,14 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.currTask = NULL;
gAudioContext.rspTask[0].task.t.data_size = 0;
gAudioContext.rspTask[1].task.t.data_size = 0;
osCreateMesgQueue(&gAudioContext.syncDmaQueue, &gAudioContext.syncDmaMesg, 1);
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf, 0x40);
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf,
ARRAY_COUNT(gAudioContext.currAudioFrameDmaMesgBuf));
osCreateMesgQueue(&gAudioContext.externalLoadQueue, gAudioContext.externalLoadMesgBuf,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
osCreateMesgQueue(&gAudioContext.preloadSampleQueue, gAudioContext.preloadSampleMesgBuf,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
ARRAY_COUNT(gAudioContext.preloadSampleMesgBuf));
gAudioContext.curAudioFrameDmaCount = 0;
gAudioContext.sampleDmaCount = 0;
gAudioContext.cartHandle = osCartRomInit();
@@ -1304,20 +1315,24 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.audioHeapSize = D_8014A6C4.heapSize;
} else {
void** hp = &heap;
gAudioContext.audioHeap = *hp;
gAudioContext.audioHeapSize = heapSize;
}
for (i = 0; i < gAudioContext.audioHeapSize / 8; i++) {
for (i = 0; i < ((s32)gAudioContext.audioHeapSize / (s32)sizeof(u64)); i++) {
((u64*)gAudioContext.audioHeap)[i] = 0;
}
// Main Pool Split (split entirety of audio heap into initPool and sessionPool)
AudioHeap_InitMainPools(D_8014A6C4.initPoolSize);
for (i = 0; i < 3; i++) {
// Initialize the audio interface buffers
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBuffers); i++) {
gAudioContext.aiBuffers[i] = AudioHeap_AllocZeroed(&gAudioContext.audioInitPool, AIBUF_LEN * sizeof(s16));
}
// Connect audio tables to their tables in memory
// gAudioContext.sequenceTable = (AudioTable*)gSequenceTable;
// gAudioContext.soundFontTable = (AudioTable*)gSoundFontTable;
// gAudioContext.sampleBankTable = (AudioTable*)gSampleBankTable;
@@ -1325,31 +1340,60 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
// gAudioContext.numSequences = gAudioContext.sequenceTable->numEntries;
gAudioContext.audioResetSpecIdToLoad = 0;
gAudioContext.resetStatus = 1;
gAudioContext.resetStatus = 1; // Set reset to immediately initialize the audio heap
AudioHeap_ResetStep();
// Initialize audio tables
// AudioLoad_InitTable(gAudioContext.sequenceTable, SEGMENT_ROM_START(Audioseq), 0);
// AudioLoad_InitTable(gAudioContext.soundFontTable, SEGMENT_ROM_START(Audiobank), 0);
// AudioLoad_InitTable(gAudioContext.sampleBankTable, SEGMENT_ROM_START(Audiotable), 0);
// #region 2S2H [Port] Audio in the archive and custom sequences
// Only load the original sequences right now because custom songs may require data from sound fonts and samples
int seqListSize = 0;
int customSeqListSize = 0;
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize);
sequenceMapSize = (size_t)(AudioCollection_SequenceMapSize() + customSeqListSize);
sequenceMap = malloc(sequenceMapSize * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize * sizeof(char*));
sequenceMapSize = (size_t)(seqListSize + customSeqListSize);
sequenceMap = malloc((sequenceMapSize + 0xF) * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize);
memset(gAudioContext.seqLoadStatus, 5, sequenceMapSize);
for (size_t i = 0; i < seqListSize; i++) {
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
char* str = malloc(strlen(seqList[i]) + 1);
strcpy(str, seqList[i]);
sequenceMap[sDat.seqNumber] = str;
sequenceMap[sDat.seqNumber] = strdup(seqList[i]);
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
}
free(seqList);
int startingSeqNum = MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
// 2S2H [Streamed Audio] We need to load the custom songs after the fonts because streamed songs will use a hash to
// find its soundfont
int fntListSize = 0;
int customFntListSize = 0;
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
char** customFntList = ResourceMgr_ListFiles("custom/fonts/*", &customFntListSize);
gAudioContext.fontLoadStatus = malloc(customFntListSize + fntListSize);
fontMap = calloc(customFntListSize + fntListSize, sizeof(char*));
fontMapSize = customFntListSize + fntListSize;
for (int i = 0; i < fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fntList[i]);
fontMap[sf->fntIndex] = strdup(fntList[i]);
}
free(fntList);
int customFontStart = fntListSize;
for (int i = customFontStart; i < customFntListSize + fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(customFntList[i - customFontStart]);
sf->fntIndex = i;
fontMap[i] = strdup(customFntList[i - customFontStart]);
}
free(customFntList);
// 2S2H Port I think we need to take use seqListSize because entry 0x7A is missing.
int startingSeqNum = seqListSize; // MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort);
// Because AudioCollection's sequenceMap actually has more than sequences (including instruments from 130-135 and
@@ -1361,48 +1405,61 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) {
// ensure that what would be the next sequence number is actually unassigned in AudioCollection
int j = i - startingSeqNum;
SequenceData* sDat = ResourceMgr_LoadSeqPtrByName(customSeqList[j]);
if (sDat->numFonts == -1) {
uint64_t crc;
memcpy(&crc, sDat->fonts, sizeof(uint64_t));
const char* res = ResourceGetNameByCrc(crc);
if (res == NULL) {
// Passing a null buffer and length of 0 to snprintf will return the required numbers of characters the
// buffer needs to be.
int len =
snprintf(NULL, 0, "Could not find sound font for sequence %s. It will not be in the audio editor.",
customSeqList[j]);
char* error = malloc(len + 1);
snprintf(error, len, "Could not find sound font for sequence %s. It will not be in the audio editor.",
customSeqList[j]);
LUSLOG_ERROR("%s", error);
Messagebox_ShowErrorBox("Invalid Sequence", error);
free(error);
continue;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(res);
memset(&sDat->fonts[0], 0, sizeof(sDat->fonts));
sDat->fonts[0] = sf->fntIndex;
sDat->numFonts = 1;
}
while (AudioCollection_HasSequenceNum(seqNum)) {
seqNum++;
}
int j = i - startingSeqNum;
AudioCollection_AddToCollection(customSeqList[j], seqNum);
SequenceData sDat = ResourceMgr_LoadSeqByName(customSeqList[j]);
sDat.seqNumber = seqNum;
char* str = malloc(strlen(customSeqList[j]) + 1);
strcpy(str, customSeqList[j]);
sequenceMap[sDat.seqNumber] = str;
sDat->seqNumber = seqNum;
printf("%d\n", seqNum);
sequenceMap[sDat->seqNumber] = strdup(customSeqList[j]);
seqNum++;
}
free(customSeqList);
int fntListSize = 0;
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
for (int i = 0; i < fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fntList[i]);
char* str = malloc(strlen(fntList[i]) + 1);
strcpy(str, fntList[i]);
fontMap[sf->fntIndex] = str;
}
numFonts = fntListSize;
free(fntList);
// #end region
gAudioContext.soundFonts = AudioHeap_Alloc(&gAudioContext.audioInitPool, numFonts * sizeof(SoundFont));
if (temp_v0_3 = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), temp_v0_3 == NULL) {
if (addr = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), addr == NULL) {
// cast away const from D_8014A6C4
// *((u32*)&D_8014A6C4.permanentPoolSize) = 0;
*((u32*)&D_8014A6C4.permanentPoolSize) = 0;
}
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, temp_v0_3, D_8014A6C4.permanentPoolSize);
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, addr, D_8014A6C4.permanentPoolSize);
gAudioContextInitalized = true;
osSendMesg32(gAudioContext.taskStartQueueP, gAudioContext.totalTaskCnt, OS_MESG_NOBLOCK);
osSendMesg(gAudioContext.taskStartQueueP, OS_MESG_32(gAudioContext.totalTaskCnt), OS_MESG_NOBLOCK);
}
void AudioLoad_InitSlowLoads(void) {
@@ -2059,7 +2116,7 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
gAudioContext.numUsedSamples = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
@@ -2188,7 +2245,7 @@ void AudioLoad_LoadPermanentSamples(void) {
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioContext.permanentCache[i].id);
// fontId = gAudioContext.permanentCache[i].id;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
relocInfo.sampleBankId1 = sf->sampleBankId1;
relocInfo.sampleBankId2 = sf->sampleBankId2;

View File

@@ -147,6 +147,7 @@ void Audio_NoteInit(Note* note) {
note->noteSubEu = gDefaultNoteSub;
}
extern void aOPUSFree(struct OggOpusFile* opusFile);
void Audio_NoteDisable(Note* note) {
if (note->noteSubEu.bitField0.needsInit == true) {
note->noteSubEu.bitField0.needsInit = false;
@@ -159,6 +160,10 @@ void Audio_NoteDisable(Note* note) {
note->playbackState.prevParentLayer = NO_LAYER;
note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED;
note->playbackState.adsr.current = 0;
if (note->synthesisState.opusFile != NULL) {
aOPUSFree(note->synthesisState.opusFile);
note->synthesisState.opusFile = NULL;
}
}
void Audio_ProcessNotes(void) {
@@ -293,13 +298,6 @@ void Audio_ProcessNotes(void) {
f32 resampRate = gAudioContext.audioBufferParameters.resampleRate;
// CUSTOM SAMPLE CHECK
if (!noteSubEu2->bitField1.isSyntheticWave && noteSubEu2->sound.soundFontSound != NULL &&
noteSubEu2->sound.soundFontSound->sample != NULL &&
noteSubEu2->sound.soundFontSound->sample->sampleRateMagicValue == 'RIFF') {
resampRate = CALC_RESAMPLE_FREQ(noteSubEu2->sound.soundFontSound->sample->sampleRate);
}
subAttrs.frequency *= resampRate;
subAttrs.velocity *= scale;
@@ -335,7 +333,7 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
}
int instCnt = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (instId >= sf->numInstruments)
return NULL;
@@ -362,7 +360,7 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (drumId < sf->numDrums) {
drum = sf->drums[drumId];
}
@@ -386,7 +384,7 @@ SoundFontSound* Audio_GetSfx(s32 fontId, s32 sfxId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (sfxId < sf->numSfx) {
sfx = &sf->soundEffects[sfxId];
}

View File

@@ -789,7 +789,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd) {
layer->freqScale *= layer->unk_34;
if (layer->delay == 0) {
if (layer->sound != NULL) {
time = (f32)layer->sound->sample->loop->end;
time = (f32)layer->sound->sample->loop->loopEnd;
} else {
time = 0.0f;
}

View File

@@ -761,7 +761,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
audioFontSample = noteSubEu->sound.soundFontSound->sample;
loopInfo = audioFontSample->loop;
loopEndPos = loopInfo->end;
loopEndPos = loopInfo->loopEnd;
sampleAddr = audioFontSample->sampleAddr;
resampledTempLen = 0;
@@ -853,14 +853,27 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
s5 = samplesLenAdjusted;
goto skip;
case CODEC_S16:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted * 2) + 0x20);
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2),
audioFontSample->sampleAddr + (synthState->samplePosInt * 2));
case CODEC_OPUS:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted + 16) * 2);
flags = A_CONTINUE;
skipBytes = 0;
nSamplesProcessed = samplesLenAdjusted;
s5 = samplesLenAdjusted;
size_t bytesToRead;
nSamplesProcessed += samplesLenAdjusted;
if (((synthState->samplePosInt * 2) + (samplesLenAdjusted)*2) < audioFontSample->size) {
bytesToRead = (samplesLenAdjusted)*2;
} else {
bytesToRead = audioFontSample->size - (synthState->samplePosInt * 2);
}
// 2S2H [Port] [Custom audio] Handle decoding OPUS data
if (audioFontSample->codec == CODEC_OPUS) {
aOPUSdecImpl(sampleAddr, DMEM_UNCOMPRESSED_NOTE, bytesToRead, &synthState->opusFile,
synthState->samplePosInt, audioFontSample->fileSize);
} else {
aLoadBuffer(cmd++, sampleAddr + (synthState->samplePosInt * 2), DMEM_UNCOMPRESSED_NOTE,
bytesToRead);
}
goto skip;
case CODEC_REVERB:
break;
@@ -886,6 +899,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
sampleDataStartPad = (uintptr_t)sampleData & 0xF;
aligned = ALIGN16((nFramesToDecode * frameSize) + 16);
addr = DMEM_COMPRESSED_ADPCM_DATA - aligned;
aLoadBuffer(cmd++, sampleData - sampleDataStartPad, addr, aligned);
} else {
nSamplesToDecode = 0;
@@ -893,7 +907,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
}
if (synthState->restart) {
aSetLoop(cmd++, audioFontSample->loop->state);
aSetLoop(cmd++, audioFontSample->loop->predictorState);
flags = A_LOOP;
synthState->restart = false;
}

View File

@@ -792,7 +792,7 @@ s32 func_800E6590(s32 playerIdx, s32 arg1, s32 arg2) {
if (sound == NULL) {
return 0;
}
loopEnd = sound->sample->loop->end;
loopEnd = sound->sample->loop->loopEnd;
samplePos = note->synthesisState.samplePosInt;
return loopEnd - samplePos;
}