diff --git a/LEGO1/define.cpp b/LEGO1/define.cpp index ea57cbb7..4e592157 100644 --- a/LEGO1/define.cpp +++ b/LEGO1/define.cpp @@ -16,6 +16,9 @@ const char* g_parseExtraTokens = ":;"; // 0x10101edc const char* g_strWORLD = "WORLD"; +// 0x10101f20 +const char* g_strSOUND = "SOUND"; + // 0x10102040 const char* g_strACTION = "ACTION"; diff --git a/LEGO1/define.h b/LEGO1/define.h index 2089032d..82e93375 100644 --- a/LEGO1/define.h +++ b/LEGO1/define.h @@ -6,6 +6,7 @@ extern MxU32 g_mxcoreCount[101]; extern const char* g_parseExtraTokens; extern const char* g_strWORLD; +extern const char* g_strSOUND; extern const char* g_strACTION; extern const char* g_strVISIBILITY; diff --git a/LEGO1/mxaudiopresenter.cpp b/LEGO1/mxaudiopresenter.cpp index fcb8c0ea..e896f857 100644 --- a/LEGO1/mxaudiopresenter.cpp +++ b/LEGO1/mxaudiopresenter.cpp @@ -5,13 +5,13 @@ DECOMP_SIZE_ASSERT(MxAudioPresenter, 0x54); // OFFSET: LEGO1 0x1000d260 -MxU32 MxAudioPresenter::GetVolume() +MxS32 MxAudioPresenter::GetVolume() { return m_volume; } // OFFSET: LEGO1 0x1000d270 -void MxAudioPresenter::SetVolume(MxU32 p_volume) +void MxAudioPresenter::SetVolume(MxS32 p_volume) { m_volume = p_volume; } diff --git a/LEGO1/mxaudiopresenter.h b/LEGO1/mxaudiopresenter.h index 9fc92457..860d6efd 100644 --- a/LEGO1/mxaudiopresenter.h +++ b/LEGO1/mxaudiopresenter.h @@ -23,11 +23,11 @@ class MxAudioPresenter : public MxMediaPresenter { return !strcmp(name, MxAudioPresenter::ClassName()) || MxMediaPresenter::IsA(name); } - virtual MxU32 GetVolume(); // vtable+0x5c - virtual void SetVolume(MxU32 p_volume); // vtable+0x60 + virtual MxS32 GetVolume(); // vtable+0x5c + virtual void SetVolume(MxS32 p_volume); // vtable+0x60 -private: - MxU32 m_volume; +protected: + MxS32 m_volume; }; #endif // MXAUDIOPRESENTER_H diff --git a/LEGO1/mxdschunk.h b/LEGO1/mxdschunk.h index e626d70b..2b1ed51c 100644 --- a/LEGO1/mxdschunk.h +++ b/LEGO1/mxdschunk.h @@ -13,6 +13,8 @@ class MxDSChunk : public MxCore { Flag_Bit1 = 0x01, Flag_Bit2 = 0x02, Flag_Bit3 = 0x04, + Flag_Bit8 = 0x80, + Flag_Bit16 = 0x8000 }; MxDSChunk(); @@ -31,6 +33,7 @@ class MxDSChunk : public MxCore { return !strcmp(name, MxDSChunk::ClassName()) || MxCore::IsA(name); } + inline void SetFlags(MxU16 flags) { m_flags = flags; } inline void SetTime(MxLong p_time) { m_time = p_time; } inline void SetLength(MxU32 p_length) { m_length = p_length; } inline void SetData(MxU8* p_data) { m_data = p_data; } diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 3a9a2fe1..5c4cd79e 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -409,7 +409,7 @@ void MxOmni::StartTimer() { if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) { m_timer->Start(); - m_soundManager->vtable0x34(); + m_soundManager->Pause(); m_timerRunning = TRUE; } } @@ -419,7 +419,7 @@ void MxOmni::StopTimer() { if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) { m_timer->Stop(); - m_soundManager->vtable0x38(); + m_soundManager->Resume(); m_timerRunning = FALSE; } } diff --git a/LEGO1/mxsoundmanager.cpp b/LEGO1/mxsoundmanager.cpp index 8e32345e..5ed0cc7a 100644 --- a/LEGO1/mxsoundmanager.cpp +++ b/LEGO1/mxsoundmanager.cpp @@ -15,6 +15,9 @@ MxSoundManager::MxSoundManager() Init(); } +// OFFSET: LEGO1 0x100ae7b0 TEMPLATE +// MxSoundManager::`scalar deleting destructor' + // OFFSET: LEGO1 0x100ae7d0 MxSoundManager::~MxSoundManager() { @@ -176,7 +179,7 @@ MxS32 MxSoundManager::FUN_100aecf0(MxU32 p_unk) } // OFFSET: LEGO1 0x100aed10 -void MxSoundManager::vtable0x34() +void MxSoundManager::Pause() { MxAutoLocker lock(&m_criticalSection); @@ -185,11 +188,11 @@ void MxSoundManager::vtable0x34() while (cursor.Next(presenter)) if (presenter->IsA("MxWavePresenter")) - ((MxWavePresenter*) presenter)->VTable0x64(); + ((MxWavePresenter*) presenter)->Pause(); } // OFFSET: LEGO1 0x100aee10 -void MxSoundManager::vtable0x38() +void MxSoundManager::Resume() { MxAutoLocker lock(&m_criticalSection); @@ -198,5 +201,5 @@ void MxSoundManager::vtable0x38() while (cursor.Next(presenter)) if (presenter->IsA("MxWavePresenter")) - ((MxWavePresenter*) presenter)->VTable0x68(); + ((MxWavePresenter*) presenter)->Resume(); } diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h index 5cb1f607..671943c6 100644 --- a/LEGO1/mxsoundmanager.h +++ b/LEGO1/mxsoundmanager.h @@ -12,24 +12,22 @@ class MxSoundManager : public MxAudioManager { public: MxSoundManager(); - - // OFFSET: LEGO1 0x100ae7b0 TEMPLATE - // MxSoundManager::`scalar deleting destructor' virtual ~MxSoundManager() override; // vtable+0x0 - virtual void Destroy() override; // vtable+18 - virtual void SetVolume(MxS32 p_volume) override; // vtable+2c + virtual void Destroy() override; // vtable+0x18 + virtual void SetVolume(MxS32 p_volume) override; // vtable+0x2c virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x30 - virtual void vtable0x34(); // vtable+0x34 - virtual void vtable0x38(); // vtable+0x38 + virtual void Pause(); // vtable+0x34 + virtual void Resume(); // vtable+0x38 inline LPDIRECTSOUND GetDirectSound() { return m_directSound; } + MxS32 FUN_100aecf0(MxU32 p_unk); + private: void Init(); void Destroy(MxBool p_fromDestructor); MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId); - MxS32 FUN_100aecf0(MxU32 p_unk); LPDIRECTSOUND m_directSound; // 0x30 LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34 diff --git a/LEGO1/mxwavepresenter.cpp b/LEGO1/mxwavepresenter.cpp index e1ae2782..1df006c1 100644 --- a/LEGO1/mxwavepresenter.cpp +++ b/LEGO1/mxwavepresenter.cpp @@ -1,12 +1,13 @@ #include "mxwavepresenter.h" #include "decomp.h" +#include "define.h" +#include "legoomni.h" +#include "mxautolocker.h" #include "mxdssound.h" #include "mxomni.h" #include "mxsoundmanager.h" -#include - DECOMP_SIZE_ASSERT(MxWavePresenter, 0x6c); DECOMP_SIZE_ASSERT(MxWavePresenter::WaveFormat, 0x1c); @@ -23,9 +24,9 @@ void MxWavePresenter::Destroy() } // OFFSET: LEGO1 0x1000d6b0 -undefined MxWavePresenter::VTable0x6c() +MxBool MxWavePresenter::IsPaused() { - return m_unk68; + return m_paused; } // OFFSET: LEGO1 0x100b1ad0 @@ -33,12 +34,12 @@ void MxWavePresenter::Init() { m_waveFormat = NULL; m_dsBuffer = NULL; - m_length = 0; - m_unk60 = 0; - m_unk64 = 0; - m_unk65 = FALSE; + m_chunkLength = 0; + m_lockSize = 0; + m_writtenChunks = 0; + m_started = FALSE; m_unk66 = FALSE; - m_unk68 = 0; + m_paused = FALSE; } // OFFSET: LEGO1 0x100b1af0 @@ -67,28 +68,62 @@ void MxWavePresenter::Destroy(MxBool p_fromDestructor) } // OFFSET: LEGO1 0x100b1b60 -MxS8 MxWavePresenter::FUN_100b1b60() +MxS8 MxWavePresenter::GetPlayedChunks() { DWORD dwCurrentPlayCursor, dwCurrentWriteCursor; - MxS8 result = -1; + MxS8 playedChunks = -1; if (m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor) == DS_OK) - result = dwCurrentPlayCursor / m_length; + playedChunks = dwCurrentPlayCursor / m_chunkLength; - return result; + return playedChunks; } // OFFSET: LEGO1 0x100b1ba0 MxBool MxWavePresenter::FUN_100b1ba0() { - return !m_unk65 || FUN_100b1b60() != m_unk64; + return !m_started || GetPlayedChunks() != m_writtenChunks; } -// OFFSET: LEGO1 0x100b1bd0 STUB -void MxWavePresenter::FUN_100b1bd0(void* p_audioPtr, MxU32 p_length) +// OFFSET: LEGO1 0x100b1bd0 +void MxWavePresenter::WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length) { - // Lock/Unlock on m_dsBuffer - // TODO + DWORD dwStatus; + LPVOID pvAudioPtr1; + DWORD dwOffset; + LPVOID pvAudioPtr2; + DWORD dwAudioBytes1; + DWORD dwAudioBytes2; + + dwOffset = m_chunkLength * m_writtenChunks; + m_dsBuffer->GetStatus(&dwStatus); + + if (dwStatus == DSBSTATUS_BUFFERLOST) { + m_dsBuffer->Restore(); + m_dsBuffer->GetStatus(&dwStatus); + } + + if (dwStatus != DSBSTATUS_BUFFERLOST) { + if (m_action->GetFlags() & MxDSAction::Flag_Looping) { + m_writtenChunks++; + m_lockSize = p_length; + } + else { + m_writtenChunks = 1 - m_writtenChunks; + m_lockSize = m_chunkLength; + } + + if (m_dsBuffer->Lock(dwOffset, m_lockSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) == + DS_OK) { + memcpy(pvAudioPtr1, p_audioPtr, p_length); + + if (m_lockSize > p_length && !(m_action->GetFlags() & MxDSAction::Flag_Looping)) { + memset((MxU8*) pvAudioPtr1 + p_length, m_silenceData, m_lockSize - p_length); + } + + m_dsBuffer->Unlock(pvAudioPtr1, m_lockSize, pvAudioPtr2, 0); + } + } } // OFFSET: LEGO1 0x100b1cf0 @@ -115,7 +150,7 @@ void MxWavePresenter::StartingTickle() MxU32 length = chunk->GetLength(); WAVEFORMATEX waveFormatEx; - m_length = length; + m_chunkLength = length; memset(&waveFormatEx, 0, sizeof(waveFormatEx)); waveFormatEx.wFormatTag = m_waveFormat->m_waveFormatEx.wFormatTag; @@ -126,17 +161,17 @@ void MxWavePresenter::StartingTickle() waveFormatEx.wBitsPerSample = m_waveFormat->m_waveFormatEx.wBitsPerSample; if (waveFormatEx.wBitsPerSample == 8) - m_unk67 = SCHAR_MAX; + m_silenceData = 0x7F; if (waveFormatEx.wBitsPerSample == 16) - m_unk67 = 0; + m_silenceData = 0; DSBUFFERDESC desc; memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); if (m_unk66) - desc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME; + desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME; else desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME; @@ -159,63 +194,182 @@ void MxWavePresenter::StartingTickle() } } -// OFFSET: LEGO1 0x100b1ea0 STUB +// OFFSET: LEGO1 0x100b1ea0 void MxWavePresenter::StreamingTickle() { - // TODO + if (!m_currentChunk) { + if (!(m_action->GetFlags() & MxDSAction::Flag_Looping)) { + MxStreamChunk* chunk = FUN_100b5650(); + + if (chunk && chunk->GetFlags() & MxDSChunk::Flag_Bit2 && !(chunk->GetFlags() & MxDSChunk::Flag_Bit16)) { + chunk->SetFlags(chunk->GetFlags() | MxDSChunk::Flag_Bit16); + + m_currentChunk = new MxStreamChunk; + MxU8* data = new MxU8[m_chunkLength]; + + memset(data, m_silenceData, m_chunkLength); + + m_currentChunk->SetLength(m_chunkLength); + m_currentChunk->SetData(data); + m_currentChunk->SetTime(chunk->GetTime() + 1000); + m_currentChunk->SetFlags(MxDSChunk::Flag_Bit1); + } + } + + MxMediaPresenter::StreamingTickle(); + } } -// OFFSET: LEGO1 0x100b20c0 STUB +// OFFSET: LEGO1 0x100b20c0 void MxWavePresenter::DoneTickle() { - // TODO + if (m_dsBuffer) { + DWORD dwCurrentPlayCursor, dwCurrentWriteCursor; + m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor); + + MxS8 playedChunks = dwCurrentPlayCursor / m_chunkLength; + if (m_action->GetFlags() & MxDSAction::Flag_Bit7 || m_action->GetFlags() & MxDSAction::Flag_Looping || + m_writtenChunks != playedChunks || m_lockSize + (m_chunkLength * playedChunks) <= dwCurrentPlayCursor) + MxMediaPresenter::DoneTickle(); + } + else + MxMediaPresenter::DoneTickle(); } -// OFFSET: LEGO1 0x100b2130 STUB +// OFFSET: LEGO1 0x100b2130 void MxWavePresenter::AppendChunk(MxStreamChunk* p_chunk) { - // TODO + WriteToSoundBuffer(p_chunk->GetData(), p_chunk->GetLength()); + if (IsEnabled()) + m_subscriber->FUN_100b8390(p_chunk); } -// OFFSET: LEGO1 0x100b2160 STUB +// OFFSET: LEGO1 0x100b2160 undefined4 MxWavePresenter::PutData() { - // TODO + MxAutoLocker lock(&m_criticalSection); + + if (IsEnabled()) { + switch (m_currentTickleState) { + case TickleState_Streaming: + if (m_currentChunk && FUN_100b1ba0()) { + WriteToSoundBuffer(m_currentChunk->GetData(), m_currentChunk->GetLength()); + m_subscriber->FUN_100b8390(m_currentChunk); + m_currentChunk = NULL; + } + + if (!m_started) { + m_dsBuffer->SetCurrentPosition(0); + + if (m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING) == DS_OK) + m_started = TRUE; + } + break; + case TickleState_Repeating: + if (m_started) + break; + + m_dsBuffer->SetCurrentPosition(0); + + if (m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1) == DS_OK) + m_started = TRUE; + } + } + return 0; } -// OFFSET: LEGO1 0x100b2280 STUB +// OFFSET: LEGO1 0x100b2280 void MxWavePresenter::EndAction() { - // TODO + if (m_action) { + MxAutoLocker lock(&m_criticalSection); + MxMediaPresenter::EndAction(); + + if (m_dsBuffer) + m_dsBuffer->Stop(); + } } -// OFFSET: LEGO1 0x100b2300 STUB -void MxWavePresenter::SetVolume(MxU32 p_volume) +// OFFSET: LEGO1 0x100b2300 +void MxWavePresenter::SetVolume(MxS32 p_volume) { - // TODO + m_criticalSection.Enter(); + + m_volume = p_volume; + if (m_dsBuffer != NULL) { + MxS32 volume = p_volume * MxOmni::GetInstance()->GetSoundManager()->GetVolume() / 100; + MxS32 otherVolume = MxOmni::GetInstance()->GetSoundManager()->FUN_100aecf0(volume); + m_dsBuffer->SetVolume(otherVolume); + } + + m_criticalSection.Leave(); } -// OFFSET: LEGO1 0x100b2360 STUB +// OFFSET: LEGO1 0x100b2360 void MxWavePresenter::Enable(MxBool p_enable) { - // TODO + if (IsEnabled() != p_enable) { + MxSoundPresenter::Enable(p_enable); + + if (p_enable) { + m_writtenChunks = 0; + m_started = FALSE; + } + else if (m_dsBuffer) + m_dsBuffer->Stop(); + } } -// OFFSET: LEGO1 0x100b23a0 STUB +// OFFSET: LEGO1 0x100b23a0 void MxWavePresenter::ParseExtra() { - // TODO + char extraCopy[512]; + + MxSoundPresenter::ParseExtra(); + *((MxU16*) &extraCopy[0]) = m_action->GetExtraLength(); + char* extraData = m_action->GetExtraData(); + + if (*((MxU16*) &extraCopy[0])) { + MxU16 len = *((MxU16*) &extraCopy[0]); + memcpy(extraCopy, extraData, len); + extraCopy[len] = '\0'; + + char t_soundValue[512]; + if (KeyValueStringParse(t_soundValue, g_strSOUND, extraCopy)) { + if (!strcmpi(t_soundValue, "FALSE")) + Enable(FALSE); + } + } } -// OFFSET: LEGO1 0x100b2440 STUB -void MxWavePresenter::VTable0x64() +// OFFSET: LEGO1 0x100b2440 +void MxWavePresenter::Pause() { - // TODO + if (!m_paused && m_started) { + if (m_dsBuffer) + m_dsBuffer->Stop(); + m_paused = TRUE; + } } -// OFFSET: LEGO1 0x100b2470 STUB -void MxWavePresenter::VTable0x68() +// OFFSET: LEGO1 0x100b2470 +void MxWavePresenter::Resume() { - // TODO + if (m_paused) { + if (m_dsBuffer && m_started) { + switch (m_currentTickleState) { + case TickleState_Streaming: + m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING); + break; + case TickleState_Repeating: + m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1); + break; + case TickleState_Done: + m_dsBuffer->Play(0, 0, 0); + } + } + + m_paused = FALSE; + } } diff --git a/LEGO1/mxwavepresenter.h b/LEGO1/mxwavepresenter.h index 57e6f007..ca58c03c 100644 --- a/LEGO1/mxwavepresenter.h +++ b/LEGO1/mxwavepresenter.h @@ -37,10 +37,10 @@ class MxWavePresenter : public MxSoundPresenter { virtual undefined4 PutData() override; // vtable+0x4c virtual void Enable(MxBool p_enable) override; // vtable+0x54 virtual void AppendChunk(MxStreamChunk* p_chunk) override; // vtable+0x58 - virtual void SetVolume(MxU32 p_volume) override; // vtable+0x60 - virtual void VTable0x64(); // vtable+0x64 - virtual void VTable0x68(); // vtable+0x68 - virtual undefined VTable0x6c(); // vtable+0x6c + virtual void SetVolume(MxS32 p_volume) override; // vtable+0x60 + virtual void Pause(); // vtable+0x64 + virtual void Resume(); // vtable+0x68 + virtual MxBool IsPaused(); // vtable+0x6c // Reference: https://github.com/itsmattkc/SIEdit/blob/master/lib/othertypes.h // SIZE 0x1c @@ -53,19 +53,19 @@ class MxWavePresenter : public MxSoundPresenter { private: void Init(); void Destroy(MxBool p_fromDestructor); - MxS8 FUN_100b1b60(); + MxS8 GetPlayedChunks(); MxBool FUN_100b1ba0(); - void FUN_100b1bd0(void* p_audioPtr, MxU32 p_length); + void WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length); - WaveFormat* m_waveFormat; - LPDIRECTSOUNDBUFFER m_dsBuffer; - MxU32 m_length; - undefined4 m_unk60; - MxU8 m_unk64; - MxBool m_unk65; - MxBool m_unk66; - MxS8 m_unk67; - undefined m_unk68; + WaveFormat* m_waveFormat; // 0x54 + LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x58 + MxU32 m_chunkLength; // 0x5c + MxU32 m_lockSize; // 0x60 + MxU8 m_writtenChunks; // 0x64 + MxBool m_started; // 0x65 + MxBool m_unk66; // 0x66 + MxS8 m_silenceData; // 0x67 + MxBool m_paused; // 0x68 }; #endif // MXWAVEPRESENTER_H