From f7cf2ec2f0d530b2d97090b9c92a734b78f8a6b0 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 18 Jan 2024 12:11:52 -0500 Subject: [PATCH] finish MusicManager --- LEGO1/omni/include/mxmusicmanager.h | 30 +++-- LEGO1/omni/include/mxstreamcontroller.h | 3 + .../omni/src/audio/mxloopingmidipresenter.cpp | 2 +- LEGO1/omni/src/audio/mxmidipresenter.cpp | 2 +- LEGO1/omni/src/audio/mxmusicmanager.cpp | 121 ++++++++++++++++-- 5 files changed, 136 insertions(+), 22 deletions(-) diff --git a/LEGO1/omni/include/mxmusicmanager.h b/LEGO1/omni/include/mxmusicmanager.h index f2afe437..f26a4c9b 100644 --- a/LEGO1/omni/include/mxmusicmanager.h +++ b/LEGO1/omni/include/mxmusicmanager.h @@ -16,9 +16,17 @@ class MxMusicManager : public MxAudioManager { virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+30 inline MxBool GetMIDIInitialized() { return m_midiInitialized; } + inline void GetMIDIVolume(DWORD& p_volume) + { + if (midiOutGetVolume(m_midiStreamH, &p_volume)) { + p_volume = CalculateVolume(100); + } + } + MxResult ResetStream(); + void ResetBuffer(); + undefined4 InitializeMIDI(MxU8* p_data, MxS32 p_loopCount); void DeinitializeMIDI(); - undefined4 FUN_100c09c0(MxU8* p_data, MxS32 p_loopCount); void SetMultiplier(MxS32 p_multiplier); private: @@ -27,16 +35,16 @@ class MxMusicManager : public MxAudioManager { MxS32 CalculateVolume(MxS32 p_volume); void SetMIDIVolume(); - HMIDISTRM m_midiStreamH; // 0x30 - MxBool m_midiInitialized; // 0x34 - undefined4 m_unk0x38; // 0x38 - undefined4 m_unk0x3c; // 0x3c - undefined4 m_unk0x40; // 0x40 - undefined4 m_unk0x44; // 0x44 - undefined4 m_unk0x48; // 0x48 - MIDIHDR* m_midiHdrP; // 0x4c - MxS32 m_multiplier; // 0x50 - DWORD m_midiVolume; // 0x54 + HMIDISTRM m_midiStreamH; // 0x30 + MxBool m_midiInitialized; // 0x34 + MxU32 m_bufferSize; // 0x38 + MxU32 m_bufferCurrentSize; // 0x3c + MxU8* m_bufferOffset; // 0x40 + MxU8* m_bufferCurrentOffset; // 0x44 + MxU32 m_loopCount; // 0x48 + MIDIHDR* m_midiHdrP; // 0x4c + MxS32 m_multiplier; // 0x50 + DWORD m_midiVolume; // 0x54 // SYNTHETIC: LEGO1 0x100c0610 // MxMusicManager::`scalar deleting destructor' diff --git a/LEGO1/omni/include/mxstreamcontroller.h b/LEGO1/omni/include/mxstreamcontroller.h index 790856c1..e852d099 100644 --- a/LEGO1/omni/include/mxstreamcontroller.h +++ b/LEGO1/omni/include/mxstreamcontroller.h @@ -118,4 +118,7 @@ class MxStreamController : public MxCore { // TEMPLATE: LEGO1 0x100c1240 // List::~List +// TEMPLATE: LEGO1 0x100c1bc0 +// List::insert + #endif // MXSTREAMCONTROLLER_H diff --git a/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp b/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp index 2ad286e1..77b32506 100644 --- a/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp +++ b/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp @@ -40,7 +40,7 @@ MxResult MxLoopingMIDIPresenter::PutData() if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) { SetVolume(((MxDSSound*) m_action)->GetVolume()); - MusicManager()->FUN_100c09c0(m_chunk->GetData(), !m_action->GetLoopCount() ? -1 : m_action->GetLoopCount()); + MusicManager()->InitializeMIDI(m_chunk->GetData(), !m_action->GetLoopCount() ? -1 : m_action->GetLoopCount()); } m_criticalSection.Leave(); diff --git a/LEGO1/omni/src/audio/mxmidipresenter.cpp b/LEGO1/omni/src/audio/mxmidipresenter.cpp index 8757e6af..db65574a 100644 --- a/LEGO1/omni/src/audio/mxmidipresenter.cpp +++ b/LEGO1/omni/src/audio/mxmidipresenter.cpp @@ -95,7 +95,7 @@ MxResult MxMIDIPresenter::PutData() if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) { SetVolume(((MxDSSound*) m_action)->GetVolume()); - if (MusicManager()->FUN_100c09c0(m_chunk->GetData(), 1)) + if (MusicManager()->InitializeMIDI(m_chunk->GetData(), 1)) EndAction(); } diff --git a/LEGO1/omni/src/audio/mxmusicmanager.cpp b/LEGO1/omni/src/audio/mxmusicmanager.cpp index 244e3861..485aa21b 100644 --- a/LEGO1/omni/src/audio/mxmusicmanager.cpp +++ b/LEGO1/omni/src/audio/mxmusicmanager.cpp @@ -31,11 +31,11 @@ void MxMusicManager::InitData() { m_midiStreamH = 0; m_midiInitialized = FALSE; - m_unk0x38 = 0; - m_unk0x3c = 0; - m_unk0x40 = 0; - m_unk0x44 = 0; - m_unk0x48 = 0; + m_bufferSize = 0; + m_bufferCurrentSize = 0; + m_bufferOffset = 0; + m_bufferCurrentOffset = 0; + m_loopCount = 0; m_midiHdrP = NULL; } @@ -62,6 +62,52 @@ void MxMusicManager::Destroy(MxBool p_fromDestructor) } } +// FUNCTION: LEGO1 0x100c0720 +MxResult MxMusicManager::ResetStream() +{ + MxResult result = FAILURE; + if (m_midiInitialized) { + if (m_bufferCurrentSize == 0) { + if (m_loopCount != -1) { + m_loopCount += -1; + if (!m_loopCount) { + DeinitializeMIDI(); + return result; + } + } + ResetBuffer(); + } + do { + if (m_midiHdrP->dwFlags & (MHDR_DONE | MHDR_PREPARED)) { + if (midiOutUnprepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR))) + break; + memset(m_midiHdrP, 0, sizeof(MIDIHDR)); + } + m_bufferCurrentOffset += 4; + DWORD length = *((DWORD*) m_bufferCurrentOffset); + m_bufferCurrentOffset += 4; + m_midiHdrP->lpData = (LPSTR) m_bufferCurrentOffset; + m_midiHdrP->dwBufferLength = length; + m_midiHdrP->dwBytesRecorded = length; + if (!midiOutPrepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR))) { + if (!midiStreamOut(m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR))) { + result = SUCCESS; + m_bufferCurrentOffset += length; + m_bufferCurrentSize--; + } + } + } while (FALSE); + } + return result; +} + +// FUNCTION: LEGO1 0x100c07e0 +void MxMusicManager::ResetBuffer() +{ + m_bufferCurrentOffset = m_bufferOffset; + m_bufferCurrentSize = m_bufferSize; +} + // FUNCTION: LEGO1 0x100c07f0 void MxMusicManager::SetMIDIVolume() { @@ -74,6 +120,14 @@ void MxMusicManager::SetMIDIVolume() } } +// FUNCTION: LEGO1 0x100c0820 +static void CALLBACK +MidiCallbackProc(HMIDIOUT p_hmo, UINT p_wMsg, MxMusicManager* p_dwInstance, MxU32* p_dwParam1, MxU32* p_dwParam2) +{ + if (p_wMsg == MOM_DONE) + p_dwInstance->ResetStream(); +} + // FUNCTION: LEGO1 0x100c0840 MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { @@ -136,11 +190,60 @@ MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume) return (result << 0x10) | result; } -// STUB: LEGO1 0x100c09c0 -undefined4 MxMusicManager::FUN_100c09c0(MxU8* p_data, MxS32 p_loopCount) +// FUNCTION: LEGO1 0x100c09c0 +undefined4 MxMusicManager::InitializeMIDI(MxU8* p_data, MxS32 p_loopCount) { - // TODO - return 0; + MxResult result = FAILURE; + m_criticalSection.Enter(); + do { + if (m_midiInitialized) + break; + MxU32 total = midiOutGetNumDevs(); + MxU32 device = 0; + for (; device < total; device++) { + MIDIOUTCAPSA caps; + midiOutGetDevCapsA(device, &caps, sizeof(MIDIOUTCAPSA)); + if (caps.wTechnology == MOD_FMSYNTH) + break; + } + if (device == total) + device = -1; + if (midiStreamOpen( + (LPHMIDIOUT) &m_midiStreamH, + &device, + 1, + (DWORD) MidiCallbackProc, + (DWORD) this, + CALLBACK_FUNCTION + )) + break; + GetMIDIVolume(m_midiVolume); + m_midiHdrP = new MIDIHDR(); + if (!m_midiHdrP) + break; + memset(m_midiHdrP, 0, sizeof(MIDIHDR)); + MIDIPROPTIMEDIV timediv; + timediv.cbStruct = 8; + m_bufferOffset = p_data; + m_bufferOffset += 0x14; + timediv.dwTimeDiv = *((DWORD*) m_bufferOffset); + if (midiStreamProperty(m_midiStreamH, (LPBYTE) &timediv, MIDIPROP_SET | MIDIPROP_TIMEDIV)) + break; + m_bufferOffset += 0x14; + m_bufferSize = *((MxU32*) m_bufferOffset); + m_bufferOffset += 0x4; + m_loopCount = p_loopCount; + m_midiInitialized = TRUE; + ResetBuffer(); + if (ResetStream() != SUCCESS) + break; + SetMIDIVolume(); + if (midiStreamRestart(m_midiStreamH)) + break; + result = SUCCESS; + } while (FALSE); + m_criticalSection.Leave(); + return result; } // FUNCTION: LEGO1 0x100c0b20