diff --git a/include/sf64audio_provisional.h b/include/sf64audio_provisional.h index 5bf39141..a24ef52a 100644 --- a/include/sf64audio_provisional.h +++ b/include/sf64audio_provisional.h @@ -29,7 +29,7 @@ typedef void (*AudioCustomUpdateFunction)(void); // Also known as "Pulses Per Quarter Note" or "Tatums Per Beat" #define SEQTICKS_PER_BEAT 48 -#define IS_SEQUENCE_CHANNEL_VALID(ptr) ((u32) (ptr) != (u32) &gSeqChannelNone) +#define IS_SEQUENCE_CHANNEL_VALID(ptr) ((uintptr_t) (ptr) != (uintptr_t) &gSeqChannelNone) #define SEQ_NUM_CHANNELS 16 #define SEQ_IO_VAL_NONE -1 @@ -215,19 +215,21 @@ typedef struct { /* 0x00 */ u32 start; /* 0x04 */ u32 end; /* 0x08 */ u32 count; - /* 0x10 */ u64 predictorState[4]; // only exists if count != 0. 8-byte aligned + /* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned } AdpcmLoop; // size = 0x30 or 0x10, 0x8 aligned typedef struct { /* 0x00 */ s32 order; /* 0x04 */ s32 numPredictors; -#ifdef AVOID_UB - /* 0x08 */ u64 book[]; // size 8 * order * numPredictors. -#else - /* 0x08 */ u64 book[1]; // size 8 * order * numPredictors. -#endif + /* 0x08 */ s16* book; // size 8 * order * numPredictors. } AdpcmBook; // size >= 8, 0x8 aligned +typedef struct { + /* 0x00 */ s32 order; + /* 0x04 */ s32 numPredictors; + /* 0x08 */ u32 book; // size 8 * order * numPredictors. +} AdpcmBook32Bit; // size >= 8, 0x8 aligned + typedef struct { /* 0x00 */ u32 codec : 4; // The state of compression or decompression /* 0x00 */ u32 medium : 2; // Medium where sample is currently stored @@ -242,10 +244,27 @@ typedef struct { book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram } Sample; // size = 0x10 +typedef struct { + /* 0x00 */ u32 codec : 4; // The state of compression or decompression + /* 0x00 */ u32 medium : 2; // Medium where sample is currently stored + /* 0x00 */ u32 unk_bit26 : 1; + /* 0x00 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers) + /* 0x01 */ u32 size : 24; // Size of the sample + /* 0x04 */ u32 sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to + // either rom or ram + /* 0x08 */ u32 loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram + /* 0x0C */ u32 book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram +} Sample32Bit; // size = 0x10 + typedef struct { /* 0x00 */ Sample* sample; /* 0x04 */ f32 tuning; // frequency modulation factor -} TunedSample; // size = 0x8 +} TunedSample;// size = 0x8 + +typedef struct { + /* 0x00 */ u32 sample; + /* 0x04 */ f32 tuning; // frequency modulation factor +} TunedSample32Bit; typedef struct { /* 0x00 */ u8 isRelocated; // have the envelope and all samples been relocated (offsets to pointers) @@ -258,6 +277,17 @@ typedef struct { /* 0x18 */ TunedSample highPitchTunedSample; } Instrument; // size = 0x20 +typedef struct { + /* 0x00 */ u8 isRelocated; // have the envelope and all samples been relocated (offsets to pointers) + /* 0x01 */ u8 normalRangeLo; + /* 0x02 */ u8 normalRangeHi; + /* 0x03 */ u8 adsrDecayIndex; // index used to obtain adsr decay rate from adsrDecayTable + /* 0x04 */ u32 envelope; + /* 0x08 */ TunedSample32Bit lowPitchTunedSample; + /* 0x10 */ TunedSample32Bit normalPitchTunedSample; + /* 0x18 */ TunedSample32Bit highPitchTunedSample; +} Instrument32Bit; // size = 0x20 + typedef struct { /* 0x00 */ u8 adsrDecayIndex; // index used to obtain adsr decay rate from adsrDecayTable /* 0x01 */ u8 pan; @@ -266,6 +296,14 @@ typedef struct { /* 0x0C */ EnvelopePoint* envelope; } Drum; // size = 0x10 +typedef struct { + /* 0x00 */ u8 adsrDecayIndex; // index used to obtain adsr decay rate from adsrDecayTable + /* 0x01 */ u8 pan; + /* 0x02 */ u8 isRelocated; // have tunedSample.sample and envelope been relocated (offsets to pointers) + /* 0x04 */ TunedSample tunedSample; + /* 0x0C */ EnvelopePoint* envelope; +} Drum32Bit; // size = 0x10 + typedef struct { /* 0x00 */ TunedSample tunedSample; } SoundEffect; // size = 0x08 @@ -766,13 +804,13 @@ typedef struct { /* 0x0 */ union { u32 opArgs; struct { - u8 op; - u8 arg0; - u8 arg1; u8 arg2; + u8 arg1; + u8 arg0; + u8 op; }; }; - /* 0x4 */ union { + union { void* data; f32 asFloat; s32 asInt; diff --git a/src/audio/audio_context.c b/src/audio/audio_context.c index 5a34571d..9985b0c0 100644 --- a/src/audio/audio_context.c +++ b/src/audio/audio_context.c @@ -233,9 +233,9 @@ AudioSpec gAudioSpecs[] = { }; s32 D_800C7C28 = 0x20000000; // unused? s16 gSeqTicksPerBeat = 0x30; -s32 gAudioHeapSize = 0xAFE00; -s32 gInitPoolSize = 0x26000; -u32 gPermanentPoolSize = 0x21000; +s32 gAudioHeapSize = 0xAFE00 * 2; +s32 gInitPoolSize = 0x26000 * 2; +u32 gPermanentPoolSize = 0x21000 * 2; u16 gSequenceMedium = 0; u16 gSoundFontMedium = 0; u16 gSampleBankMedium = 0; diff --git a/src/audio/audio_effects.c b/src/audio/audio_effects.c index 61d2ccaa..0a184871 100644 --- a/src/audio/audio_effects.c +++ b/src/audio/audio_effects.c @@ -1,5 +1,6 @@ #include "sys.h" #include "sf64audio_provisional.h" +#include "endianness.h" static const char devstr[] = "Audio:Envp: overflow %f\n"; @@ -199,7 +200,7 @@ f32 func_80013B90(AdsrState* adsr) { adsr->state = ADSR_STATE_LOOP; case_ADSR_STATE_LOOP: case ADSR_STATE_LOOP: - adsr->delay = adsr->envelope[adsr->envIndex].delay; + adsr->delay = BSWAP16(adsr->envelope[adsr->envIndex].delay); switch (adsr->delay) { case ADSR_DISABLE: adsr->state = ADSR_STATE_DISABLED; @@ -208,7 +209,7 @@ f32 func_80013B90(AdsrState* adsr) { adsr->state = ADSR_STATE_HANG; break; case ADSR_GOTO: - adsr->envIndex = adsr->envelope[adsr->envIndex].arg; + adsr->envIndex = BSWAP16(adsr->envelope[adsr->envIndex].arg); goto case_ADSR_STATE_LOOP; case ADSR_RESTART: adsr->state = ADSR_STATE_INITIAL; @@ -221,7 +222,7 @@ f32 func_80013B90(AdsrState* adsr) { adsr->delay = 1; } - adsr->target = adsr->envelope[adsr->envIndex].arg / 32767.0f; + adsr->target = (s16)BE16SWAP(adsr->envelope[adsr->envIndex].arg) / 32767.0f; adsr->target = SQ(adsr->target); adsr->velocity = (adsr->target - adsr->current) / adsr->delay; adsr->state = ADSR_STATE_FADE; diff --git a/src/audio/audio_general.c b/src/audio/audio_general.c index 70b73fc1..3f91fa5e 100644 --- a/src/audio/audio_general.c +++ b/src/audio/audio_general.c @@ -637,7 +637,7 @@ void Audio_ResetSfxChannelState(void) { } void Audio_StartSequence(u8 seqPlayId, u8 seqId, u8 seqArgs, u16 fadeInTime) { - u8 i; + u8 i = 0; s32 pad; if (!sStartSeqDisabled || (seqPlayId == SEQ_PLAYER_SFX)) { @@ -2644,8 +2644,7 @@ void Audio_RestoreVolumeSettings(u8 audioType) { } } -void Audio_SetVolume(u8 audioType, u8 volume) { - return; +void Audio_SetVolume(u8 audioType, u8 volume) { if (volume > 99) { volume = 99; } diff --git a/src/audio/audio_heap.c b/src/audio/audio_heap.c index 663f5fd7..ea35a463 100644 --- a/src/audio/audio_heap.c +++ b/src/audio/audio_heap.c @@ -148,6 +148,7 @@ void* AudioHeap_Alloc(AudioAllocPool* pool, u32 size) { void AudioHeap_InitPool(AudioAllocPool* pool, void* ramAddr, u32 size) { pool->curRamAddr = pool->startRamAddr = (u8*) ramAddr; + size *= 4; pool->size = size - ((uintptr_t) ramAddr & 0xF); pool->numEntries = 0; } diff --git a/src/audio/audio_load.c b/src/audio/audio_load.c index 3cbc7d6d..eedb62f2 100644 --- a/src/audio/audio_load.c +++ b/src/audio/audio_load.c @@ -1,8 +1,12 @@ +#include #include "sys.h" #include "sf64dma.h" #include "sf64audio_provisional.h" #include "assets/ast_audio.h" #include "port/Engine.h" +#include "endianness.h" +#include "port/Engine.h" +#include "port/resource/loaders/AudioLoader.h" s32 D_80146D80; s32 PAD_80146D88[2]; @@ -33,8 +37,8 @@ void AudioLoad_ProcessAsyncLoads(s32 resetStatus); void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus); void AudioLoad_AsyncDma(AudioAsyncLoad* asyncLoad, u32 size); void AudioLoad_AsyncDmaUnkMedium(uintptr_t devAddr, u8* ramAddr, u32 size, s32 unkMediumParam); -void AudioLoad_RelocateSample(TunedSample* tSample, u32 fontDataAddr, SampleBankRelocInfo* relocInfo); -s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, SampleBankRelocInfo* relocData, s32 isAsync); +void AudioLoad_RelocateSample(TunedSample* sample, TunedSample32Bit* tSample, uintptr_t fontDataAddr, SampleBankRelocInfo* relocInfo); +s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, uintptr_t fontDataAddr, SampleBankRelocInfo* relocData, s32 isAsync); s32 AudioLoad_ProcessSamplePreloads(s32 resetStatus); void AudioLoad_DecreaseSampleDmaTtls(void) { @@ -386,13 +390,12 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { func_800144E4(&gSeqPlayers[playerIdx]); - index = *((u16*) gSeqFontTable + seqId); - numFonts = gSeqFontTable[index++]; + index = BSWAP16(*((u16*) gSeqFontTable + seqId)); fontId = 0xFF; - for (numFonts; numFonts > 0; numFonts--) { + for (numFonts = gSeqFontTable[index++]; numFonts > 0; numFonts--) { fontId = gSeqFontTable[index++]; - AudioLoad_SyncLoadFont(fontId); + // AudioLoad_SyncLoadFont(fontId); } seqData = AudioLoad_SyncLoadSeq(seqId); @@ -401,23 +404,17 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { gSeqPlayers[playerIdx].seqId = seqId; gSeqPlayers[playerIdx].defaultFont = fontId; - gSeqPlayers[playerIdx].enabled = true; + gSeqPlayers[playerIdx].enabled = 1; gSeqPlayers[playerIdx].seqData = seqData; gSeqPlayers[playerIdx].scriptState.pc = seqData; gSeqPlayers[playerIdx].scriptState.depth = 0; gSeqPlayers[playerIdx].delay = 0; - gSeqPlayers[playerIdx].finished = false; - - for (i = 0; i < 16; i++) { - ; - } + gSeqPlayers[playerIdx].finished = 0; } void* AudioLoad_SyncLoadSeq(s32 seqId) { - s32 seqIdx = AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId); - s32 didAllocate; - - return AudioLoad_SyncLoad(0, seqIdx, &didAllocate); + AudioTable* table = AudioLoad_GetLoadTable(SEQUENCE_TABLE); + return Audio_LoadBlob(gAudioTable, table->entries[seqId].romAddr); } void* AudioLoad_SyncLoadSampleBank(u32 sampleBankId, s32* outMedium) { @@ -498,7 +495,7 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) { u8* ramAddr; u32 medium; s32 loadStatus; - u32 romAddr; + uintptr_t romAddr; s32 pad; s32 cachePolicy; @@ -621,12 +618,10 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) { return table; } -void AudioLoad_RelocateFont(s32 fontId, u32 fontBaseAddr, void* relocData) { - u32* fontDataPtrs = fontBaseAddr; - u32** drumDataPtrs = fontBaseAddr; +void AudioLoad_RelocateFont(s32 fontId, uintptr_t fontBaseAddr, SampleBankRelocInfo* relocData) { + uint32_t* fontDataPtrs = fontBaseAddr; + uint32_t** drumDataPtrs = fontBaseAddr; s32 numDrums; - Drum* drum; - Instrument* instrument; u32 offset; s32 i; s32 numInstruments; @@ -634,53 +629,41 @@ void AudioLoad_RelocateFont(s32 fontId, u32 fontBaseAddr, void* relocData) { numDrums = gSoundFontList[fontId].numDrums; numInstruments = gSoundFontList[fontId].numInstruments; - if ((fontDataPtrs[0] != 0) && (numDrums != 0)) { - fontDataPtrs[0] += fontBaseAddr; + Drum** relocatedDrums = memalloc(numDrums * sizeof(Drum*)); + Instrument** relocatedInstruments = memalloc((numInstruments + 1) * sizeof(Instrument*)); + if ((fontDataPtrs[0] != 0) && (numDrums != 0)) { for (i = 0; i < numDrums; i++) { offset = *(*drumDataPtrs + i); if (offset != 0) { - drum = offset += fontBaseAddr; - *(*drumDataPtrs + i) = drum; - - if (!drum->isRelocated) { - AudioLoad_RelocateSample(&drum->tunedSample, fontBaseAddr, relocData); - offset = (u32) drum->envelope; - drum->envelope = offset + fontBaseAddr; - drum->isRelocated = true; - } + relocatedDrums[i] = Audio_LoadDrum(BSWAP32(offset) + fontBaseAddr, 0, 0); } } } for (i = 1; i <= numInstruments; i++) { if (fontDataPtrs[i] != 0) { + Instrument* instrument = Audio_LoadInstrument(BSWAP32(fontDataPtrs[i]) + fontBaseAddr, 0); + Instrument32Bit* base = fontBaseAddr + BSWAP32(fontDataPtrs[i]); - fontDataPtrs[i] += fontBaseAddr; - - instrument = fontDataPtrs[i]; - if (!instrument->isRelocated) { - if (instrument->normalRangeLo != 0) { - AudioLoad_RelocateSample(&instrument->lowPitchTunedSample, fontBaseAddr, relocData); - } - AudioLoad_RelocateSample(&instrument->normalPitchTunedSample, fontBaseAddr, relocData); - if (instrument->normalRangeHi != 0x7F) { - AudioLoad_RelocateSample(&instrument->highPitchTunedSample, fontBaseAddr, relocData); - } - offset = (u32) instrument->envelope; - instrument->envelope = offset + fontBaseAddr; - instrument->isRelocated = true; + if (instrument->normalRangeLo != 0) { + AudioLoad_RelocateSample(&instrument->lowPitchTunedSample, &base->lowPitchTunedSample, fontBaseAddr, relocData); } + AudioLoad_RelocateSample(&instrument->normalPitchTunedSample, &base->normalPitchTunedSample, fontBaseAddr, relocData); + if (instrument->normalRangeHi != 0x7F) { + AudioLoad_RelocateSample(&instrument->highPitchTunedSample, &base->highPitchTunedSample, fontBaseAddr, relocData); + } + + relocatedInstruments[i] = instrument; } } - gSoundFontList[fontId].drums = fontDataPtrs[0]; - gSoundFontList[fontId].instruments = (u32) &fontDataPtrs[1]; + gSoundFontList[fontId].drums = relocatedDrums; + gSoundFontList[fontId].instruments = relocatedInstruments; } void AudioLoad_SyncDma(uintptr_t devAddr, u8* ramAddr, u32 size, s32 medium) { size = ALIGN16(size); - osInvalDCache(ramAddr, size); while (true) { @@ -738,7 +721,7 @@ s32 AudioLoad_Dma(OSIoMesg* mesg, u32 priority, s32 direction, uintptr_t devAddr mesg->devAddr = devAddr; mesg->size = size; - handle->transferInfo.cmdType = 2; + // handle->transferInfo.cmdType = 2; // osEPiStartDma(handle, mesg, direction); memcpy(ramAddr, (void*) devAddr, size); @@ -941,19 +924,17 @@ void AudioLoad_Init(void) { gSeqFontTable = gSeqFontTableInit; gNumSequences = gSequenceTable->base.numEntries; - AudioLoad_InitTable(gSequenceTable, LOAD_ASSET(gAudioSeq), gSequenceMedium); - AudioLoad_InitTable(gSoundFontTable, LOAD_ASSET(gAudioBank), gSoundFontMedium); - AudioLoad_InitTable(gSampleBankTable, LOAD_ASSET(gAudioTable), gSampleBankMedium); +// AudioLoad_InitTable(gSequenceTable, LOAD_ASSET(gAudioSeq), gSequenceMedium); +// AudioLoad_InitTable(gSoundFontTable, LOAD_ASSET(gAudioBank), gSoundFontMedium); +// AudioLoad_InitTable(gSampleBankTable, LOAD_ASSET(gAudioTable), gSampleBankMedium); numFonts = gSoundFontTable->base.numEntries; gSoundFontList = AudioHeap_Alloc(&gInitPool, numFonts * sizeof(SoundFont)); for (i = 0; i < numFonts; i++) { - gSoundFontList[i].sampleBankId1 = (gSoundFontTable->entries[i].shortData1 >> 8) & 0xFF; - gSoundFontList[i].sampleBankId2 = gSoundFontTable->entries[i].shortData1 & 0xFF; - gSoundFontList[i].numInstruments = (gSoundFontTable->entries[i].shortData2 >> 8) & 0xFF; - gSoundFontList[i].numDrums = gSoundFontTable->entries[i].shortData2 & 0xFF; + gSoundFontList[i] = Audio_LoadFont(gSoundFontTable->entries[i]); + gFontLoadStatus[i] = 2; } ramAddr = AudioHeap_Alloc(&gInitPool, gPermanentPoolSize); @@ -1277,35 +1258,40 @@ void AudioLoad_AsyncDmaUnkMedium(uintptr_t devAddr, u8* ramAddr, u32 size, s32 u static const char devstr50[] = "Error: Already wavetable is touched %x.\n"; static const char devstr51[] = "Touch Warning: Length zero %x\n"; -void AudioLoad_RelocateSample(TunedSample* tSample, u32 fontDataAddr, SampleBankRelocInfo* relocInfo) { - void* reloc; - Sample* sample; +void AudioLoad_RelocateSample(TunedSample* tunedSample, TunedSample32Bit* tSample, uintptr_t fontDataAddr, SampleBankRelocInfo* relocInfo) { + Sample32Bit* baseSample = fontDataAddr + BSWAP32(tSample->sample); - // "Error: Already wavetable is touched %x.\n"; - if ((u32) tSample->sample <= AUDIO_RELOCATED_ADDRESS_START) { - sample = tSample->sample = reloc = (u32) tSample->sample + fontDataAddr; - // "Touch Warning: Length zero %x\n"; - if ((sample->size != 0) && (sample->isRelocated != 1)) { - sample->loop = reloc = (u32) sample->loop + fontDataAddr; - sample->book = reloc = (u32) sample->book + fontDataAddr; - switch (sample->medium) { - case MEDIUM_RAM: - sample->sampleAddr = reloc = sample->sampleAddr + relocInfo->baseAddr1; - sample->medium = relocInfo->medium1; - break; - case MEDIUM_UNK: - sample->sampleAddr = reloc = sample->sampleAddr + relocInfo->baseAddr2; - sample->medium = relocInfo->medium2; - break; - case MEDIUM_CART: - case MEDIUM_DISK_DRIVE: - break; - } + // "Touch Warning: Length zero %x\n"; + if ((baseSample->size != 0) && (baseSample->isRelocated != 1)) { + Sample* output = memalloc(sizeof(Sample)); - sample->isRelocated = true; - if (sample->unk_bit26 && (sample->medium != 0)) { - gUsedSamples[gNumUsedSamples++] = sample; - } + output->loop = Audio_LoadLoop(fontDataAddr + BSWAP32(baseSample->loop)); + output->book = Audio_LoadBook(fontDataAddr + BSWAP32(baseSample->book)); + output->codec = baseSample->codec; + output->medium = baseSample->medium; + output->unk_bit26 = baseSample->unk_bit26; + output->isRelocated = baseSample->isRelocated; + output->size = baseSample->size; + + output->isRelocated = 1; + switch (baseSample->medium) { + case MEDIUM_RAM: +// baseSample->sampleAddr = Audio_LoadCopy(relocInfo->baseAddr1 + BSWAP32(baseSample->sampleAddr), BSWAP32(baseSample->size)); + baseSample->medium = relocInfo->medium1; + break; + case MEDIUM_UNK: +// baseSample->sampleAddr = Audio_LoadCopy(relocInfo->baseAddr2 + BSWAP32(baseSample->sampleAddr), BSWAP32(baseSample->size)); + baseSample->medium = relocInfo->medium2; + break; + case MEDIUM_CART: + case MEDIUM_DISK_DRIVE: + output->sampleAddr = fontDataAddr + BSWAP32(baseSample->sampleAddr); + break; + } + + baseSample->isRelocated = true; + if (baseSample->unk_bit26 && (baseSample->medium != 0)) { + gUsedSamples[gNumUsedSamples++] = output; } } } @@ -1316,7 +1302,7 @@ static const char devstr54[] = "Warning: Length zero %x\n"; static const char devstr55[] = "Wave Load %d \n"; static const char devstr56[] = "Total Bg Wave Load %d \n"; -s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, SampleBankRelocInfo* relocData, s32 isAsync) { +s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, uintptr_t fontDataAddr, SampleBankRelocInfo* relocData, s32 isAsync) { s32 i; Sample* sample; u8* sampleRamAddr; @@ -1534,4 +1520,4 @@ s32 AudioLoad_GetSamplesForFont(s32 fontId, Sample** sampleSet) { } return numLoaded; -} +} \ No newline at end of file diff --git a/src/audio/audio_playback.c b/src/audio/audio_playback.c index a4b2ae46..05cd56ef 100644 --- a/src/audio/audio_playback.c +++ b/src/audio/audio_playback.c @@ -248,10 +248,6 @@ void func_80011FA8(void) { playbackState = ¬e->playbackState; if ((playbackState->parentLayer != NO_LAYER)) { - if ((u32) playbackState->parentLayer < 0x7FFFFFFF) { - continue; - } - if ((note != playbackState->parentLayer->note) && (playbackState->unk_04 == 0)) { playbackState->adsr.action.asByte |= 0x10; playbackState->adsr.fadeOutVel = gAudioBufferParams.ticksPerUpdateInv; @@ -284,7 +280,6 @@ void func_80011FA8(void) { block_21: if (playbackState->priority != 0) { - if (1) {} noteSub = ¬e->noteSubEu; if ((playbackState->unk_04 > 0) || noteSub->bitField0.finished) { if ((playbackState->adsr.state == 0) || noteSub->bitField0.finished) { diff --git a/src/audio/audio_seqplayer.c b/src/audio/audio_seqplayer.c index dabcb992..62e6ffbe 100644 --- a/src/audio/audio_seqplayer.c +++ b/src/audio/audio_seqplayer.c @@ -268,7 +268,7 @@ void* func_800145FC(AudioListItem* list) { list->prev = item->prev; item->prev = NULL; list->u.count--; - return (void*) item->u.count; + return (void*) item->u.value; } void func_8001463C(void) { diff --git a/src/audio/audio_synthesis.c b/src/audio/audio_synthesis.c index 5ec7c962..7de5dd3f 100644 --- a/src/audio/audio_synthesis.c +++ b/src/audio/audio_synthesis.c @@ -1,6 +1,7 @@ #include "sys.h" #include "sf64audio_provisional.h" #include "audio/mixer.h" +#include "endianness.h" s32 D_80145D40; // unused @@ -745,8 +746,8 @@ Acmd* func_8000A25C(s16* aiBuf, s32 aiBufLen, Acmd* aList, s32 updateIndex) { u8 sp84[0x3C]; NoteSubEu* temp_v0; s16 var_s2; - s16 i; - s32 j; + s16 i = 0; + s32 j = 0; var_s2 = 0; if (gNumSynthReverbs == 0) { @@ -832,7 +833,7 @@ Acmd* func_8000A700(s32 noteIndex, NoteSubEu* noteSub, NoteSynthesisState* synth s32 padD8; s32 padD4; s32 padD0; - u32 sampleAddr; // spCC + uintptr_t sampleAddr; // spCC s32 padC8; s32 samplesLenAdjusted; // spC4 s32 nAdpcmSamplesProcessed; // spC0 @@ -1011,7 +1012,7 @@ Acmd* func_8000A700(s32 noteIndex, NoteSubEu* noteSub, NoteSynthesisState* synth flags, &synthState->sampleDmaIndex, bookSample->medium); } // if (1){} - sampleDataStartPad = (u32) sampleData & 0xF; + sampleDataStartPad = (uintptr_t) sampleData & 0xF; aLoadBuffer(aList++, OS_K0_TO_PHYSICAL(sampleData - sampleDataStartPad), addr, aligned); } else { nSamplesToDecode = 0; diff --git a/src/audio/audio_thread.c b/src/audio/audio_thread.c index fb4144cf..0b42ed33 100644 --- a/src/audio/audio_thread.c +++ b/src/audio/audio_thread.c @@ -42,68 +42,58 @@ static const char devstr14[] = "Error : Queue is not empty ( %x ) \n"; void AudioThread_CreateNextAudioBuffer(s16 *samples, u32 num_samples) { static s32 gMaxAbiCmdCnt = 128; static SPTask* gWaitingAudioTask = NULL; - u32 sp54; - s32 sp50; - s32 sp4C; - s32 pad48; - OSTask_t* task; - u16* sp40; - s32 pad3C; - OSMesg sp38; - OSMesg sp34; - s32 pad30; + s32 abiCmdCount; + u32 specId; + OSMesg msg; + gAudioTaskCountQ++; if ((gAudioTaskCountQ % gAudioBufferParams.count) != 0) { - return; + return gWaitingAudioTask; } - osSendMesg(gAudioTaskStartQueue, OS_MESG_32(gAudioTaskCountQ), 0); + osSendMesg(gAudioTaskStartQueue, OS_MESG_32(gAudioTaskCountQ), OS_MESG_NOBLOCK); gAudioTaskIndexQ ^= 1; - gCurAiBuffIndex++; - gCurAiBuffIndex %= 3; - sp4C = (gCurAiBuffIndex + 1) % 3; - sp54 = osAiGetLength() >> 2; - if ((gAudioResetTimer < 16) && (gAiBuffLengths[sp4C] != 0)) { - osAiSetNextBuffer(gAiBuffers[sp4C], gAiBuffLengths[sp4C] * 4); - } - if (gCurAudioFrameDmaCount && gCurAudioFrameDmaCount) {} + gCurAudioFrameDmaCount = 0; AudioLoad_DecreaseSampleDmaTtls(); - AudioLoad_ProcessLoads(gAudioResetStep); - if (osRecvMesg(&gAudioTaskMesgQueue, &sp38, 0) != -1) { + // AudioLoad_ProcessLoads(gAudioResetStep); + + if (MQ_GET_MESG(gAudioSpecQueue, &specId)) { if (gAudioResetStep == 0) { gAudioResetStep = 5; } - gAudioSpecId = sp38.data32; + gAudioSpecId = specId; } + if ((gAudioResetStep != 0) && (AudioHeap_ResetStep() == 0)) { if (gAudioResetStep == 0) { - osSendMesg(gAudioResetQueue, OS_MESG_32((s32) gAudioSpecId), 0); + osSendMesg(gAudioResetQueue, OS_MESG_32((s32) gAudioSpecId), OS_MESG_NOBLOCK); } gWaitingAudioTask = NULL; - return; + return NULL; } + if (gAudioResetTimer > 16) { - return; + return NULL; } if (gAudioResetTimer != 0) { gAudioResetTimer++; } + gAudioCurTask = &gAudioRspTasks[gAudioTaskIndexQ]; gCurAbiCmdBuffer = gAbiCmdBuffs[gAudioTaskIndexQ]; - sp4C = gCurAiBuffIndex; - sp40 = gAiBuffers[sp4C]; - gAiBuffLengths[sp4C] = num_samples; - if (gAiBuffLengths[sp4C] < gAudioBufferParams.minAiBufferLength) { - gAiBuffLengths[sp4C] = gAudioBufferParams.minAiBufferLength; + + while (MQ_GET_MESG(gThreadCmdProcQueue, &msg)) { + AudioThread_ProcessCmds(msg.data32); } - if (gAiBuffLengths[sp4C] > gAudioBufferParams.maxAiBufferLength) { - gAiBuffLengths[sp4C] = gAudioBufferParams.maxAiBufferLength; - } - while (osRecvMesg(gThreadCmdProcQueue, &sp34, 0) != -1) { - AudioThread_ProcessCmds(sp34.data32); - } - gCurAbiCmdBuffer = func_80009B64(gCurAbiCmdBuffer, &sp50, samples, num_samples); + + gCurAbiCmdBuffer = func_80009B64(gCurAbiCmdBuffer, &abiCmdCount, samples, num_samples); gAudioRandom = osGetCount() * (gAudioRandom + gAudioTaskCountQ); + + gAudioCurTask->msg = OS_MESG_PTR(NULL); + + if (gMaxAbiCmdCnt < abiCmdCount) { + gMaxAbiCmdCnt = abiCmdCount; + } } SPTask* AudioThread_CreateTask() { @@ -233,7 +223,7 @@ void AudioThread_ProcessGlobalCmd(AudioCmd* cmd) { case AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER: case AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_ALT: AudioLoad_SyncInitSeqPlayer(cmd->arg0, cmd->arg1, cmd->arg2); - AudioThread_SetFadeInTimer(cmd->arg0, (s32) cmd->data); + AudioThread_SetFadeInTimer(cmd->arg0, (uintptr_t) cmd->data); break; case AUDIOCMD_OP_GLOBAL_DISABLE_SEQPLAYER: if (gSeqPlayers[cmd->arg0].enabled) { @@ -355,7 +345,7 @@ void AudioThread_ScheduleProcessCmds(void) { D_800C7C70 = (u8) (gThreadCmdWritePos - gThreadCmdReadPos + 0x100); } msg = (((gThreadCmdReadPos & 0xFF) << 8) | (gThreadCmdWritePos & 0xFF)); - osSendMesg(gThreadCmdProcQueue, OS_MESG_32(msg), OS_MESG_NOBLOCK); + osSendMesg32(gThreadCmdProcQueue, msg, OS_MESG_NOBLOCK); gThreadCmdReadPos = gThreadCmdWritePos; } diff --git a/src/audio/note_data.c b/src/audio/note_data.c index c7e2574b..32256fc2 100644 --- a/src/audio/note_data.c +++ b/src/audio/note_data.c @@ -1,4 +1,5 @@ #include "sys.h" +#include "endianness.h" #include "sf64audio_provisional.h" f32 gBendPitchOneOctaveFrequencies[] = { @@ -197,6 +198,7 @@ u8 gDefaultShortNoteVelocityTable[] = { u8 gDefaultShortNoteGateTimeTable[] = { 229, 203, 177, 151, 139, 126, 113, 100, 87, 74, 61, 48, 36, 23, 10, 0, }; + EnvelopePoint gDefaultEnvelope[] = { { 4, 32000 }, { 1000, 32000 }, diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index f140d224..25480a2f 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -41,13 +41,19 @@ void AudioThread_CreateNextAudioBuffer(int16_t *samples, uint32_t num_samples); } GameEngine* GameEngine::Instance; +static GamePool MemoryPool = { + .chunk = 2048, + .cursor = 0, + .length = 0, + .memory = nullptr +}; GameEngine::GameEngine() { std::vector OTRFiles; if (const std::string cube_path = Ship::Context::GetPathRelativeToAppDirectory("starship.otr"); std::filesystem::exists(cube_path)) { OTRFiles.push_back(cube_path); } - if (const std::string sm64_otr_path = Ship::Context::GetPathRelativeToAppBundle("sf64.otr"); std::filesystem::exists(sm64_otr_path)) { + if (const std::string sm64_otr_path = Ship::Context::GetPathRelativeToAppDirectory("sf64.otr"); std::filesystem::exists(sm64_otr_path)) { OTRFiles.push_back(sm64_otr_path); } if (const std::string patches_path = Ship::Context::GetPathRelativeToAppDirectory("mods"); !patches_path.empty() && std::filesystem::exists(patches_path)) { @@ -60,7 +66,7 @@ GameEngine::GameEngine() { } } - this->context = Ship::Context::CreateInstance("Starship", "ship", "starship.cfg.json", OTRFiles, {}, 3); + this->context = Ship::Context::CreateInstance("Starship", "ship", "starship.cfg.json", OTRFiles, {}, 3, { 32000, 1024, 2480 }); auto loader = context->GetResourceManager()->GetResourceLoader(); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Animation", static_cast(SF64::ResourceType::AnimData), 0); @@ -95,7 +101,7 @@ void GameEngine::Create(){ } void GameEngine::Destroy(){ - + free(MemoryPool.memory); } bool ShouldClearTextureCacheAtEndOfFrame = false; @@ -133,7 +139,7 @@ void GameEngine::HandleAudioThread(){ u32 num_audio_samples = samples_left < AudioPlayerGetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; s16 audio_buffer[SAMPLES_PER_FRAME]; for (int i = 0; i < NUM_AUDIO_CHANNELS; i++) { - AudioThread_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples); + AudioThread_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples * 2); } AudioPlayerPlayFrame((u8 *) audio_buffer, 2 * num_audio_samples * 4); audio.processing = false; @@ -427,4 +433,28 @@ extern "C" int32_t OTRConvertHUDXToScreenX(int32_t v) { float screenScaledCoord = gameCoord * gameScreenRatio; int32_t screenScaledCoordInt = screenScaledCoord; return screenScaledCoordInt; +} + +extern "C" void* GameEngine_Malloc(size_t size) { + // This is really wrong + return malloc(size); + + const auto chunk = MemoryPool.chunk; + + if(size == 0) { + return nullptr; + } + + if(MemoryPool.cursor + size < MemoryPool.length) { + const auto res = static_cast(MemoryPool.memory) + MemoryPool.cursor; + MemoryPool.cursor += size; + SPDLOG_INFO("Allocating {} into memory pool", size); + return res; + } + + MemoryPool.length += chunk; + MemoryPool.memory = MemoryPool.memory == nullptr ? malloc(MemoryPool.length) : realloc(MemoryPool.memory, MemoryPool.length); + memset(static_cast(MemoryPool.memory) + MemoryPool.length, 0, MemoryPool.length - chunk); + SPDLOG_INFO("Memory pool resized from {} to {}", MemoryPool.length - chunk, MemoryPool.length); + return GameEngine_Malloc(size); } \ No newline at end of file diff --git a/src/port/Engine.h b/src/port/Engine.h index 4f12a326..e222330d 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -3,6 +3,13 @@ #define LOAD_ASSET(path) (path == NULL ? NULL : (GameEngine_OTRSigCheck((const char*) path) ? ResourceGetDataByName((const char*) path) : path)) #define LOAD_ASSET_RAW(path) ResourceGetDataByName((const char*) path) +struct GamePool { + unsigned long chunk; + unsigned long cursor; + unsigned long length; + void* memory; +}; + #ifdef __cplusplus #include #include @@ -34,7 +41,16 @@ class GameEngine { static void ProcessGfxCommands(Gfx* commands); static uint32_t GetInterpolationFPS(); }; + +extern "C" void* GameEngine_Malloc(size_t size); + + +#define memallocn(type, n) (type*) GameEngine_Malloc(sizeof(type) * n) +#define memalloc(type) memallocn(type, 1) + #else +#include + void GameEngine_ProcessGfxCommands(Gfx* commands); float GameEngine_GetAspectRatio(); uint8_t GameEngine_OTRSigCheck(char* imgData); @@ -48,4 +64,6 @@ int16_t OTRGetRectDimensionFromLeftEdge(float v); int16_t OTRGetRectDimensionFromRightEdge(float v); uint32_t OTRGetGameRenderWidth(); uint32_t OTRGetGameRenderHeight(); +void* GameEngine_Malloc(size_t size); +#define memalloc(size) GameEngine_Malloc(size) #endif \ No newline at end of file diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 63f15981..18a4c312 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -21,9 +21,9 @@ void Graphics_PushFrame(Gfx* data) { extern "C" void Timer_Update(); void push_frame() { + Graphics_ThreadUpdate(); GameEngine::StartAudioFrame(); GameEngine::Instance->StartFrame(); - Graphics_ThreadUpdate(); Timer_Update(); // thread5_iteration(); GameEngine::EndAudioFrame(); diff --git a/src/port/resource/loaders/AudioLoader.cpp b/src/port/resource/loaders/AudioLoader.cpp new file mode 100644 index 00000000..ba3609ab --- /dev/null +++ b/src/port/resource/loaders/AudioLoader.cpp @@ -0,0 +1,192 @@ +#include "AudioLoader.h" +#include "utils/binarytools/BinaryReader.h" +#include "assets/ast_audio.h" +#include "BitConverter.h" +#include "port/Engine.h" +#include + +Ship::BinaryReader Audio_MakeReader(const char* resource, u32 offset = 0){ + auto data = (char*)ResourceGetDataByName(resource); + auto size = ResourceGetSizeByName(resource); + + Ship::BinaryReader reader(data, size); + reader.SetEndianness(Ship::Endianness::Big); + reader.Seek(offset, Ship::SeekOffsetType::Start); + + return reader; +} + +char* Audio_LoadBlob(const char* resource, u32 offset){ + auto data = (char*)ResourceGetDataByName(resource); + + return data + offset; +} + +EnvelopePoint* Audio_LoadEnvelope(uint32_t addr) { + auto reader = Audio_MakeReader(gAudioBank, addr); + + std::vector temp; + while(true) { + int16_t delay = reader.ReadInt16(); + int16_t arg = reader.ReadInt16(); + + temp.push_back({delay, arg}); + + if (delay < 0){ + break; + } + } + + EnvelopePoint* envelopes = memallocn(EnvelopePoint, temp.size()); + memcpy(envelopes, temp.data(), sizeof(EnvelopePoint) * temp.size()); + + return envelopes; +} + +extern "C" SoundFont Audio_LoadFont(AudioTableEntry entry) { + auto reader = Audio_MakeReader(gAudioBank, entry.romAddr); + + SoundFont font = { + .numInstruments = (entry.shortData2 >> 8) & 0xFF, + .numDrums = entry.shortData2 & 0xFF, + .sampleBankId1 = (entry.shortData1 >> 8) & 0xFF, + .sampleBankId2 = entry.shortData1 & 0xFF, + }; + + font.instruments = memallocn(Instrument*, font.numInstruments); + font.drums = memallocn(Drum*, font.numDrums); + + uint32_t drumBaseAddr = entry.romAddr + reader.ReadUInt32(); + uint32_t instBaseAddr = 4; + + if(font.drums != nullptr && drumBaseAddr != 0){ + reader.Seek(drumBaseAddr, Ship::SeekOffsetType::Start); + for(size_t i = 0; i < font.numDrums; i++){ + font.drums[i] = Audio_LoadDrum(entry.romAddr + reader.ReadUInt32(), entry.romAddr, font.sampleBankId1); + } + } + + if(font.instruments != nullptr){ + reader.Seek(instBaseAddr, Ship::SeekOffsetType::Start); + for(size_t i = 1; i < font.numInstruments; i++){ + font.instruments[i] = Audio_LoadInstrument(reader.ReadUInt32(), font.sampleBankId1); + } + } + + gSampleFontLoadStatus[font.sampleBankId1] = 2; + + return font; +} + +extern "C" AdpcmLoop* Audio_LoadLoop(uint32_t addr) { + auto reader = Audio_MakeReader(gAudioBank, addr); + AdpcmLoop* loop = memalloc(AdpcmLoop); + + loop->start = reader.ReadInt32(); + loop->end = reader.ReadUInt32(); + loop->count = reader.ReadUInt32(); + + if(loop->count != 0){ + for(size_t i = 0; i < 16; i++){ + loop->predictorState[i] = reader.ReadInt16(); + } + } + + return loop; +} + +extern "C" AdpcmBook* Audio_LoadBook(uint32_t addr) { + auto reader = Audio_MakeReader(gAudioBank, addr); + + AdpcmBook* book = memalloc(AdpcmBook); + book->order = reader.ReadInt32(); + book->numPredictors = reader.ReadInt32(); + + size_t length = 8 * book->order * book->numPredictors; + book->book = memallocn(int16_t, length); + + if(length > 16){ + return nullptr; + } + + for(size_t i = 0; i < length; i++){ + book->book[i] = reader.ReadInt16(); + } + + return book; +} + +Sample* Audio_LoadSample(uint32_t sampleAddr, uint32_t baseAddr = 0, uint32_t sampleBankID = 0) { + auto reader = Audio_MakeReader(gAudioBank, sampleAddr); + + Sample* sample = memalloc(Sample); + sample->size = reader.ReadUInt32(); + uint32_t addr = reader.ReadUInt32(); + sample->loop = Audio_LoadLoop(baseAddr + reader.ReadUInt32()); + sample->book = Audio_LoadBook(baseAddr + reader.ReadUInt32()); + + sample->isRelocated = 1; + sample->sampleAddr = (uint8_t*) Audio_LoadBlob(gAudioTable, gSeqTableInit.entries[sampleBankID].romAddr) + addr; + + return sample; +} + +TunedSample Audio_LoadTunedSample(uint32_t addr, uint32_t baseAddr = 0, uint32_t sampleBankID = 0) { + auto reader = Audio_MakeReader(gAudioBank, addr); + auto sampleAddr = reader.ReadUInt32(); + auto tuning = reader.ReadFloat(); + + if(sampleAddr == 0){ + assert(tuning == 0.0f); + return { nullptr, 0.0f }; + } + + return { + .sample = Audio_LoadSample(baseAddr + sampleAddr, baseAddr, sampleBankID), + .tuning = tuning + }; +} + +extern "C" Instrument* Audio_LoadInstrument(uint32_t addr, uint32_t sampleBankID) { + if (addr == 0) { + return nullptr; + } + + auto reader = Audio_MakeReader(gAudioBank, addr); + + Instrument* instrument = memalloc(Instrument); + instrument->isRelocated = reader.ReadUByte(); + instrument->normalRangeLo = reader.ReadUByte(); + instrument->normalRangeHi = reader.ReadUByte(); + instrument->adsrDecayIndex = reader.ReadUByte(); + instrument->envelope = Audio_LoadEnvelope(reader.ReadUInt32()); + instrument->lowPitchTunedSample = Audio_LoadTunedSample(addr + 8, 0, sampleBankID); + instrument->normalPitchTunedSample = Audio_LoadTunedSample(addr + 16, 0, sampleBankID); + instrument->highPitchTunedSample = Audio_LoadTunedSample(addr + 24, 0, sampleBankID); + instrument->isRelocated = 1; + + return instrument; +} + +extern "C" Drum* Audio_LoadDrum(uint32_t addr, uint32_t baseAddr, uint32_t sampleBankID) { + + if(baseAddr != 0 && addr >= baseAddr){ + return nullptr; + } + + auto reader = Audio_MakeReader(gAudioBank, addr); + Drum* drum = memalloc(Drum); + + drum->adsrDecayIndex = reader.ReadInt8(); + drum->pan = reader.ReadInt8(); + drum->isRelocated = reader.ReadUByte(); + reader.ReadUByte(); + drum->isRelocated = 1; + + + drum->tunedSample = Audio_LoadTunedSample(addr + 4, baseAddr, sampleBankID); + reader.Seek(0x8, Ship::SeekOffsetType::Current); + drum->envelope = Audio_LoadEnvelope(reader.ReadUInt32()); + + return drum; +} \ No newline at end of file diff --git a/src/port/resource/loaders/AudioLoader.h b/src/port/resource/loaders/AudioLoader.h new file mode 100644 index 00000000..8f2f81da --- /dev/null +++ b/src/port/resource/loaders/AudioLoader.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "sf64audio_provisional.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char* Audio_LoadBlob(const char* resource, u32 offset); +AdpcmBook* Audio_LoadBook(uint32_t addr); +AdpcmLoop* Audio_LoadLoop(uint32_t addr); +Instrument* Audio_LoadInstrument(uint32_t addr, uint32_t sampleBankID); +Drum* Audio_LoadDrum(uint32_t addr, uint32_t baseAddr, uint32_t sampleBankID); +Sample* Audio_LoadSample(uint32_t addr, uint32_t sampleBankID); +SoundFont Audio_LoadFont(AudioTableEntry entry); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c index 867f0d74..dbe173a4 100644 --- a/src/sys/sys_main.c +++ b/src/sys/sys_main.c @@ -103,31 +103,10 @@ void Main_Initialize(void) { } void Audio_ThreadEntry(void* arg0) { - // SPTask* task; + SPTask* task; AudioLoad_Init(); Audio_InitSounds(); - - // task = AudioThread_CreateTask(); - // if (task != NULL) { - // task->msgQueue = &gAudioTaskMsgQueue; - // task->msg = OS_MESG_32(TASK_MESG_1); - // osWritebackDCacheAll(); - // osSendMesg(&gTaskMsgQueue, OS_MESG_PTR(task), OS_MESG_PRI_NORMAL); - // } - // while (true) { - // task = AudioThread_CreateTask(); - // if (task != NULL) { - // task->msgQueue = &gAudioTaskMsgQueue; - // task->msg = OS_MESG_32(TASK_MESG_1); - // osWritebackDCacheAll(); - // } - // MQ_GET_MESG(&gAudioTaskMesgQueue, NULL); - // if (task != NULL) { - // osSendMesg(&gTaskMsgQueue, OS_MESG_PTR(task), OS_MESG_PRI_NORMAL); - // } - // MQ_WAIT_FOR_MESG(&gAudioVImesgQueue, NULL); - // } } void Graphics_SetTask(void) { @@ -299,7 +278,8 @@ void Graphics_ThreadUpdate() { // } // LTODO: There is no audio for now :P - // Audio_Update(); + osSendMesg(&gTaskMesgQueue, OS_MESG_PTR(NULL), OS_MESG_NOBLOCK); + Audio_Update(); } void Main_InitMesgQueues(void) { @@ -388,6 +368,8 @@ void Main_ThreadEntry(void* arg0) { Graphics_ThreadEntry(NULL); Controller_Init(); + Main_InitMesgQueues(); + // LTODO: Implement timers // Timer_ThreadEntry(NULL);