mirror of
https://github.com/isledecomp/isle-portable.git
synced 2024-12-03 12:47:05 -05:00
Replace DirectSound with miniaudio (#21)
* Add miniaudio * WIP * static const * Fix missing looping * Fix volume * Implement 3D sound, WIP * Remove unused WinMM code * Update README.md * Fixes * Fix naming * Fix naming * disable ma threading * Invert Z axis for OpenGL system * Update comment * Set rolloff * Fix minimize/maximize suspension * Rename function * SDL3: changed macro name
This commit is contained in:
parent
419bc2a44e
commit
8a802bcf85
34 changed files with 342 additions and 1188 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +1,6 @@
|
||||||
[submodule "3rdparty/libsmacker"]
|
[submodule "3rdparty/libsmacker"]
|
||||||
path = 3rdparty/libsmacker
|
path = 3rdparty/libsmacker
|
||||||
url = https://github.com/foxtacles/libsmacker
|
url = https://github.com/foxtacles/libsmacker
|
||||||
|
[submodule "3rdparty/miniaudio"]
|
||||||
|
path = 3rdparty/miniaudio
|
||||||
|
url = https://github.com/mackron/miniaudio
|
||||||
|
|
1
3rdparty/miniaudio
vendored
Submodule
1
3rdparty/miniaudio
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4a5b74bef029b3592c54b6048650ee5f972c1a48
|
|
@ -122,6 +122,27 @@ set_property(TARGET libsmacker PROPERTY ARCHIVE_OUTPUT_NAME "libsmacker$<$<CONFI
|
||||||
set_property(TARGET libsmacker PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/libsmacker")
|
set_property(TARGET libsmacker PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/libsmacker")
|
||||||
target_include_directories(libsmacker PRIVATE "${CMAKE_SOURCE_DIR}/3rdparty/libsmacker")
|
target_include_directories(libsmacker PRIVATE "${CMAKE_SOURCE_DIR}/3rdparty/libsmacker")
|
||||||
|
|
||||||
|
add_library(miniaudio STATIC
|
||||||
|
3rdparty/miniaudio/extras/miniaudio_split/miniaudio.c
|
||||||
|
)
|
||||||
|
register_lego1_target(miniaudio)
|
||||||
|
set_property(TARGET miniaudio PROPERTY ARCHIVE_OUTPUT_NAME "miniaudio$<$<CONFIG:Debug>:d>")
|
||||||
|
set_property(TARGET miniaudio PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/miniaudio/extras/miniaudio_split")
|
||||||
|
target_include_directories(miniaudio PRIVATE "${CMAKE_SOURCE_DIR}/3rdparty/miniaudio/extras/miniaudio_split")
|
||||||
|
# Disable most features since we don't need them.
|
||||||
|
target_compile_definitions(miniaudio PUBLIC
|
||||||
|
MA_ENABLE_ONLY_SPECIFIC_BACKENDS
|
||||||
|
MA_NO_DECODING
|
||||||
|
MA_NO_ENCODING
|
||||||
|
MA_NO_WAV
|
||||||
|
MA_NO_FLAC
|
||||||
|
MA_NO_MP3
|
||||||
|
MA_NO_DEVICE_IO
|
||||||
|
MA_NO_RESOURCE_MANAGER
|
||||||
|
MA_NO_GENERATION
|
||||||
|
MA_NO_THREADING
|
||||||
|
)
|
||||||
|
|
||||||
add_library(tglrl STATIC
|
add_library(tglrl STATIC
|
||||||
LEGO1/tgl/d3drm/camera.cpp
|
LEGO1/tgl/d3drm/camera.cpp
|
||||||
LEGO1/tgl/d3drm/device.cpp
|
LEGO1/tgl/d3drm/device.cpp
|
||||||
|
@ -243,10 +264,6 @@ add_library(omni STATIC
|
||||||
LEGO1/omni/src/action/mxdsstreamingaction.cpp
|
LEGO1/omni/src/action/mxdsstreamingaction.cpp
|
||||||
LEGO1/omni/src/audio/mxaudiomanager.cpp
|
LEGO1/omni/src/audio/mxaudiomanager.cpp
|
||||||
LEGO1/omni/src/audio/mxaudiopresenter.cpp
|
LEGO1/omni/src/audio/mxaudiopresenter.cpp
|
||||||
LEGO1/omni/src/audio/mxloopingmidipresenter.cpp
|
|
||||||
LEGO1/omni/src/audio/mxmidipresenter.cpp
|
|
||||||
LEGO1/omni/src/audio/mxmusicmanager.cpp
|
|
||||||
LEGO1/omni/src/audio/mxmusicpresenter.cpp
|
|
||||||
LEGO1/omni/src/audio/mxsoundmanager.cpp
|
LEGO1/omni/src/audio/mxsoundmanager.cpp
|
||||||
LEGO1/omni/src/audio/mxsoundpresenter.cpp
|
LEGO1/omni/src/audio/mxsoundpresenter.cpp
|
||||||
LEGO1/omni/src/audio/mxwavepresenter.cpp
|
LEGO1/omni/src/audio/mxwavepresenter.cpp
|
||||||
|
@ -314,7 +331,7 @@ add_library(omni STATIC
|
||||||
register_lego1_target(omni)
|
register_lego1_target(omni)
|
||||||
set_property(TARGET omni PROPERTY ARCHIVE_OUTPUT_NAME "omni$<$<CONFIG:Debug>:d>")
|
set_property(TARGET omni PROPERTY ARCHIVE_OUTPUT_NAME "omni$<$<CONFIG:Debug>:d>")
|
||||||
target_include_directories(omni PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/util")
|
target_include_directories(omni PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/util")
|
||||||
target_link_libraries(omni PRIVATE dsound winmm libsmacker)
|
target_link_libraries(omni PRIVATE winmm libsmacker miniaudio)
|
||||||
|
|
||||||
add_library(lego1 SHARED
|
add_library(lego1 SHARED
|
||||||
LEGO1/define.cpp
|
LEGO1/define.cpp
|
||||||
|
@ -454,7 +471,7 @@ target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/lego/legoomni
|
||||||
target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/lego/legoomni/include/actions")
|
target_include_directories(lego1 PUBLIC "${CMAKE_SOURCE_DIR}/LEGO1/lego/legoomni/include/actions")
|
||||||
|
|
||||||
# Link libraries
|
# Link libraries
|
||||||
target_link_libraries(lego1 PRIVATE tglrl viewmanager realtime mxdirectx roi geom anim Vec::Vec dxguid misc 3dmanager omni)
|
target_link_libraries(lego1 PRIVATE tglrl viewmanager realtime mxdirectx roi geom anim Vec::Vec dxguid misc 3dmanager miniaudio omni)
|
||||||
|
|
||||||
foreach(tgt IN LISTS lego1_targets)
|
foreach(tgt IN LISTS lego1_targets)
|
||||||
target_link_libraries(${tgt} PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5> SDL3::SDL3)
|
target_link_libraries(${tgt} PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5> SDL3::SDL3)
|
||||||
|
@ -480,7 +497,7 @@ if (ISLE_BUILD_APP)
|
||||||
target_link_libraries(isle PRIVATE SDL3::SDL3 iniparser-static)
|
target_link_libraries(isle PRIVATE SDL3::SDL3 iniparser-static)
|
||||||
|
|
||||||
# Link DSOUND, WINMM, and LEGO1
|
# Link DSOUND, WINMM, and LEGO1
|
||||||
target_link_libraries(isle PRIVATE dsound winmm lego1)
|
target_link_libraries(isle PRIVATE winmm lego1)
|
||||||
|
|
||||||
# Make sure filenames are ALL CAPS
|
# Make sure filenames are ALL CAPS
|
||||||
set_property(TARGET isle PROPERTY OUTPUT_NAME ISLE)
|
set_property(TARGET isle PROPERTY OUTPUT_NAME ISLE)
|
||||||
|
|
|
@ -237,8 +237,7 @@ int SDL_AppInit(void** appstate, int argc, char** argv)
|
||||||
{
|
{
|
||||||
*appstate = NULL;
|
*appstate = NULL;
|
||||||
|
|
||||||
// Add subsystems as necessary later
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) {
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) != 0 || SDL_Init(SDL_INIT_TIMER) != 0) {
|
|
||||||
SDL_ShowSimpleMessageBox(
|
SDL_ShowSimpleMessageBox(
|
||||||
SDL_MESSAGEBOX_ERROR,
|
SDL_MESSAGEBOX_ERROR,
|
||||||
"LEGO® Island Error",
|
"LEGO® Island Error",
|
||||||
|
@ -311,15 +310,17 @@ int SDL_AppEvent(void* appstate, const SDL_Event* event)
|
||||||
|
|
||||||
// [library:window]
|
// [library:window]
|
||||||
// Remaining functionality to be implemented:
|
// Remaining functionality to be implemented:
|
||||||
// Full screen - crashes when minimizing/maximizing
|
// Full screen - crashes when minimizing/maximizing, but this will probably be fixed once DirectDraw is replaced
|
||||||
// WM_TIMER - use SDL_Timer functionality instead
|
// WM_TIMER - use SDL_Timer functionality instead
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
g_isle->SetWindowActive(TRUE);
|
g_isle->SetWindowActive(TRUE);
|
||||||
|
Lego()->Resume();
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||||
g_isle->SetWindowActive(FALSE);
|
g_isle->SetWindowActive(FALSE);
|
||||||
|
Lego()->Pause();
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
if (!g_closed) {
|
if (!g_closed) {
|
||||||
|
|
|
@ -82,7 +82,6 @@ EXPORTS
|
||||||
?MSoundManager@@YAPAVMxSoundManager@@XZ
|
?MSoundManager@@YAPAVMxSoundManager@@XZ
|
||||||
?MakeSourceName@@YAXPADPBD@Z
|
?MakeSourceName@@YAXPADPBD@Z
|
||||||
?MoveCursor@LegoVideoManager@@QAEXHH@Z
|
?MoveCursor@LegoVideoManager@@QAEXHH@Z
|
||||||
?MusicManager@@YAPAVMxMusicManager@@XZ
|
|
||||||
?NotificationManager@@YAPAVMxNotificationManager@@XZ
|
?NotificationManager@@YAPAVMxNotificationManager@@XZ
|
||||||
?Notify@MxCore@@UAEJAAVMxParam@@@Z
|
?Notify@MxCore@@UAEJAAVMxParam@@@Z
|
||||||
?Open@MxDSFile@@UAEJK@Z
|
?Open@MxDSFile@@UAEJK@Z
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "decomp.h"
|
#include "decomp.h"
|
||||||
#include "mxtypes.h"
|
#include "mxtypes.h"
|
||||||
|
|
||||||
#include <dsound.h>
|
#include <miniaudio.h>
|
||||||
|
|
||||||
class LegoActor;
|
class LegoActor;
|
||||||
class LegoROI;
|
class LegoROI;
|
||||||
|
@ -17,10 +17,10 @@ class Lego3DSound {
|
||||||
virtual ~Lego3DSound();
|
virtual ~Lego3DSound();
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
MxResult Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char* p_name, MxS32 p_volume);
|
MxResult Create(ma_sound* p_sound, const char* p_name, MxS32 p_volume);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
MxU32 UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer);
|
MxU32 UpdatePosition(ma_sound* p_sound);
|
||||||
void FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char* p_name);
|
void FUN_10011a60(ma_sound* p_sound, const char* p_name);
|
||||||
void Reset();
|
void Reset();
|
||||||
MxS32 SetDistance(MxS32 p_min, MxS32 p_max);
|
MxS32 SetDistance(MxS32 p_min, MxS32 p_max);
|
||||||
|
|
||||||
|
@ -28,14 +28,13 @@ class Lego3DSound {
|
||||||
// Lego3DSound::`scalar deleting destructor'
|
// Lego3DSound::`scalar deleting destructor'
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LPDIRECTSOUND3DBUFFER m_ds3dBuffer; // 0x08
|
ma_sound* m_sound;
|
||||||
LegoROI* m_roi; // 0x0c
|
LegoROI* m_roi; // 0x0c
|
||||||
LegoROI* m_positionROI; // 0x10
|
LegoROI* m_positionROI; // 0x10
|
||||||
MxBool m_enabled; // 0x14
|
MxBool m_enabled; // 0x14
|
||||||
MxBool m_isActor; // 0x15
|
MxBool m_isActor; // 0x15
|
||||||
LegoActor* m_actor; // 0x18
|
LegoActor* m_actor; // 0x18
|
||||||
double m_frequencyFactor; // 0x20
|
double m_frequencyFactor; // 0x20
|
||||||
DWORD m_dwFrequency; // 0x28
|
|
||||||
MxS32 m_volume; // 0x2c
|
MxS32 m_volume; // 0x2c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "lego3dsound.h"
|
#include "lego3dsound.h"
|
||||||
#include "mxcore.h"
|
#include "mxcore.h"
|
||||||
#include "mxstring.h"
|
#include "mxstring.h"
|
||||||
|
#include "mxwavepresenter.h"
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d4718
|
// VTABLE: LEGO1 0x100d4718
|
||||||
// SIZE 0x88
|
// SIZE 0x88
|
||||||
|
@ -27,7 +28,7 @@ class LegoCacheSound : public MxCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MxResult Create(
|
virtual MxResult Create(
|
||||||
LPPCMWAVEFORMAT p_pwfx,
|
MxWavePresenter::WaveFormat& p_pwfx,
|
||||||
MxString p_mediaSrcPath,
|
MxString p_mediaSrcPath,
|
||||||
MxS32 p_volume,
|
MxS32 p_volume,
|
||||||
MxU8* p_data,
|
MxU8* p_data,
|
||||||
|
@ -54,14 +55,18 @@ class LegoCacheSound : public MxCore {
|
||||||
void CopyData(MxU8* p_data, MxU32 p_dataSize);
|
void CopyData(MxU8* p_data, MxU32 p_dataSize);
|
||||||
MxString FUN_10006d80(const MxString& p_str);
|
MxString FUN_10006d80(const MxString& p_str);
|
||||||
|
|
||||||
LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x08
|
// [library:audio] WAVE_FORMAT_PCM (audio in .SI files only used this format)
|
||||||
|
static const MxU32 g_supportedFormatTag = 1;
|
||||||
|
|
||||||
|
ma_audio_buffer m_buffer;
|
||||||
|
ma_sound m_cacheSound;
|
||||||
undefined m_unk0x0c[4]; // 0x0c
|
undefined m_unk0x0c[4]; // 0x0c
|
||||||
Lego3DSound m_sound; // 0x10
|
Lego3DSound m_sound; // 0x10
|
||||||
MxU8* m_data; // 0x40
|
MxU8* m_data; // 0x40
|
||||||
MxU32 m_dataSize; // 0x44
|
MxU32 m_dataSize; // 0x44
|
||||||
MxString m_unk0x48; // 0x48
|
MxString m_unk0x48; // 0x48
|
||||||
MxBool m_unk0x58; // 0x58
|
MxBool m_unk0x58; // 0x58
|
||||||
PCMWAVEFORMAT m_wfx; // 0x59
|
MxWavePresenter::WaveFormat m_wfx; // 0x59
|
||||||
MxBool m_looping; // 0x69
|
MxBool m_looping; // 0x69
|
||||||
MxBool m_unk0x6a; // 0x6a
|
MxBool m_unk0x6a; // 0x6a
|
||||||
MxS32 m_volume; // 0x6c
|
MxS32 m_volume; // 0x6c
|
||||||
|
|
|
@ -41,7 +41,7 @@ class LegoLoadCacheSoundPresenter : public MxWavePresenter {
|
||||||
MxU8* m_pData; // 0x74
|
MxU8* m_pData; // 0x74
|
||||||
MxU32 m_dataSize; // 0x78
|
MxU32 m_dataSize; // 0x78
|
||||||
MxBool m_unk0x7c; // 0x7c
|
MxBool m_unk0x7c; // 0x7c
|
||||||
PCMWAVEFORMAT m_pcmWaveFormat; // 0x7d
|
WaveFormat m_waveFormat; // 0x7d
|
||||||
};
|
};
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x10018460
|
// SYNTHETIC: LEGO1 0x10018460
|
||||||
|
|
|
@ -27,7 +27,6 @@ class LegoSoundManager : public MxSoundManager {
|
||||||
void Init();
|
void Init();
|
||||||
void Destroy(MxBool p_fromDestructor);
|
void Destroy(MxBool p_fromDestructor);
|
||||||
|
|
||||||
LPDIRECTSOUND3DLISTENER m_listener; // 0x3c
|
|
||||||
LegoCacheSoundManager* m_cacheSoundManager; // 0x40
|
LegoCacheSoundManager* m_cacheSoundManager; // 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ Lego3DSound::~Lego3DSound()
|
||||||
// FUNCTION: LEGO1 0x10011680
|
// FUNCTION: LEGO1 0x10011680
|
||||||
void Lego3DSound::Init()
|
void Lego3DSound::Init()
|
||||||
{
|
{
|
||||||
m_ds3dBuffer = NULL;
|
m_sound = NULL;
|
||||||
m_roi = NULL;
|
m_roi = NULL;
|
||||||
m_positionROI = NULL;
|
m_positionROI = NULL;
|
||||||
m_actor = NULL;
|
m_actor = NULL;
|
||||||
|
@ -37,23 +37,20 @@ void Lego3DSound::Init()
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100116a0
|
// FUNCTION: LEGO1 0x100116a0
|
||||||
// FUNCTION: BETA10 0x10039647
|
// FUNCTION: BETA10 0x10039647
|
||||||
MxResult Lego3DSound::Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char* p_name, MxS32 p_volume)
|
MxResult Lego3DSound::Create(ma_sound* p_sound, const char* p_name, MxS32 p_volume)
|
||||||
{
|
{
|
||||||
m_volume = p_volume;
|
m_volume = p_volume;
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
if (MxOmni::IsSound3D()) {
|
||||||
p_directSoundBuffer->QueryInterface(IID_IDirectSound3DBuffer, (LPVOID*) &m_ds3dBuffer);
|
m_sound = p_sound;
|
||||||
if (m_ds3dBuffer == NULL) {
|
|
||||||
return FAILURE;
|
ma_sound_set_min_distance(m_sound, 15.0f);
|
||||||
|
ma_sound_set_max_distance(m_sound, 100.0f);
|
||||||
|
ma_sound_set_position(m_sound, 0.0f, 0.0f, 40.0f);
|
||||||
|
ma_sound_set_rolloff(m_sound, 10.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ds3dBuffer->SetMinDistance(15.0f, DS3D_IMMEDIATE);
|
if (m_sound == NULL || p_name == NULL) {
|
||||||
m_ds3dBuffer->SetMaxDistance(100.0f, DS3D_IMMEDIATE);
|
|
||||||
m_ds3dBuffer->SetPosition(0.0f, 0.0f, -40.0f, DS3D_IMMEDIATE);
|
|
||||||
m_ds3dBuffer->SetConeOutsideVolume(-10000, DS3D_IMMEDIATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ds3dBuffer == NULL || p_name == NULL) {
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +83,7 @@ MxResult Lego3DSound::Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
if (MxOmni::IsSound3D()) {
|
||||||
const float* position = m_positionROI->GetWorldPosition();
|
const float* position = m_positionROI->GetWorldPosition();
|
||||||
m_ds3dBuffer->SetPosition(position[0], position[1], position[2], DS3D_IMMEDIATE);
|
ma_sound_set_position(m_sound, position[0], position[1], -position[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
LegoEntity* entity = m_roi->GetEntity();
|
LegoEntity* entity = m_roi->GetEntity();
|
||||||
|
@ -94,13 +91,11 @@ MxResult Lego3DSound::Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char
|
||||||
m_actor = ((LegoActor*) entity);
|
m_actor = ((LegoActor*) entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_directSoundBuffer->GetFrequency(&m_dwFrequency);
|
|
||||||
|
|
||||||
if (m_actor != NULL) {
|
if (m_actor != NULL) {
|
||||||
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
||||||
|
|
||||||
if (m_frequencyFactor != 0.0) {
|
if (m_frequencyFactor != 0.0) {
|
||||||
p_directSoundBuffer->SetFrequency(m_frequencyFactor * m_dwFrequency);
|
ma_sound_set_pitch(p_sound, m_frequencyFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +105,7 @@ MxResult Lego3DSound::Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char
|
||||||
// FUNCTION: LEGO1 0x10011880
|
// FUNCTION: LEGO1 0x10011880
|
||||||
void Lego3DSound::Destroy()
|
void Lego3DSound::Destroy()
|
||||||
{
|
{
|
||||||
if (m_ds3dBuffer) {
|
m_sound = NULL;
|
||||||
m_ds3dBuffer->Release();
|
|
||||||
m_ds3dBuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_enabled && m_roi && CharacterManager()) {
|
if (m_enabled && m_roi && CharacterManager()) {
|
||||||
if (m_isActor) {
|
if (m_isActor) {
|
||||||
|
@ -129,7 +121,7 @@ void Lego3DSound::Destroy()
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100118e0
|
// FUNCTION: LEGO1 0x100118e0
|
||||||
// FUNCTION: BETA10 0x10039a2a
|
// FUNCTION: BETA10 0x10039a2a
|
||||||
MxU32 Lego3DSound::UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
|
MxU32 Lego3DSound::UpdatePosition(ma_sound* p_sound)
|
||||||
{
|
{
|
||||||
MxU32 updated = FALSE;
|
MxU32 updated = FALSE;
|
||||||
|
|
||||||
|
@ -146,8 +138,8 @@ MxU32 Lego3DSound::UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ds3dBuffer != NULL) {
|
if (m_sound != NULL) {
|
||||||
m_ds3dBuffer->SetPosition(position[0], position[1], position[2], DS3D_IMMEDIATE);
|
ma_sound_set_position(m_sound, position[0], position[1], -position[2]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MxS32 newVolume = m_volume;
|
MxS32 newVolume = m_volume;
|
||||||
|
@ -165,8 +157,7 @@ MxU32 Lego3DSound::UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
newVolume = newVolume * SoundManager()->GetVolume() / 100;
|
newVolume = newVolume * SoundManager()->GetVolume() / 100;
|
||||||
newVolume = SoundManager()->GetAttenuation(newVolume);
|
ma_sound_set_volume(p_sound, SoundManager()->GetAttenuation(newVolume));
|
||||||
p_directSoundBuffer->SetVolume(newVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updated = TRUE;
|
updated = TRUE;
|
||||||
|
@ -175,7 +166,7 @@ MxU32 Lego3DSound::UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
|
||||||
if (m_actor != NULL) {
|
if (m_actor != NULL) {
|
||||||
if (abs(m_frequencyFactor - m_actor->GetSoundFrequencyFactor()) > 0.0001) {
|
if (abs(m_frequencyFactor - m_actor->GetSoundFrequencyFactor()) > 0.0001) {
|
||||||
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
||||||
p_directSoundBuffer->SetFrequency(m_frequencyFactor * m_dwFrequency);
|
ma_sound_set_pitch(p_sound, m_frequencyFactor);
|
||||||
updated = TRUE;
|
updated = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,13 +176,13 @@ MxU32 Lego3DSound::UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10011a60
|
// FUNCTION: LEGO1 0x10011a60
|
||||||
// FUNCTION: BETA10 0x10039d04
|
// FUNCTION: BETA10 0x10039d04
|
||||||
void Lego3DSound::FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char* p_name)
|
void Lego3DSound::FUN_10011a60(ma_sound* p_sound, const char* p_name)
|
||||||
{
|
{
|
||||||
assert(p_directSoundBuffer);
|
assert(p_sound);
|
||||||
|
|
||||||
if (p_name == NULL) {
|
if (p_name == NULL) {
|
||||||
if (m_ds3dBuffer != NULL) {
|
if (m_sound != NULL) {
|
||||||
m_ds3dBuffer->SetMode(DS3DMODE_DISABLE, DS3D_IMMEDIATE);
|
ma_sound_set_spatialization_enabled(m_sound, MA_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -222,16 +213,10 @@ void Lego3DSound::FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const ch
|
||||||
m_positionROI = m_roi;
|
m_positionROI = m_roi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ds3dBuffer != NULL) {
|
if (m_sound != NULL) {
|
||||||
DWORD dwMode;
|
ma_sound_set_spatialization_enabled(m_sound, MA_TRUE);
|
||||||
m_ds3dBuffer->GetMode(&dwMode);
|
|
||||||
|
|
||||||
if (dwMode & DS3DMODE_DISABLE) {
|
|
||||||
m_ds3dBuffer->SetMode(DS3DMODE_NORMAL, DS3D_IMMEDIATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* position = m_positionROI->GetWorldPosition();
|
const float* position = m_positionROI->GetWorldPosition();
|
||||||
m_ds3dBuffer->SetPosition(position[0], position[1], position[2], DS3D_IMMEDIATE);
|
ma_sound_set_position(m_sound, position[0], position[1], -position[2]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const float* position = m_positionROI->GetWorldPosition();
|
const float* position = m_positionROI->GetWorldPosition();
|
||||||
|
@ -256,8 +241,7 @@ void Lego3DSound::FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const ch
|
||||||
}
|
}
|
||||||
|
|
||||||
newVolume = newVolume * SoundManager()->GetVolume() / 100;
|
newVolume = newVolume * SoundManager()->GetVolume() / 100;
|
||||||
newVolume = SoundManager()->GetAttenuation(newVolume);
|
ma_sound_set_volume(p_sound, SoundManager()->GetAttenuation(newVolume));
|
||||||
p_directSoundBuffer->SetVolume(newVolume);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,13 +250,11 @@ void Lego3DSound::FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const ch
|
||||||
m_actor = ((LegoActor*) entity);
|
m_actor = ((LegoActor*) entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_directSoundBuffer->GetFrequency(&m_dwFrequency);
|
|
||||||
|
|
||||||
if (m_actor != NULL) {
|
if (m_actor != NULL) {
|
||||||
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
m_frequencyFactor = m_actor->GetSoundFrequencyFactor();
|
||||||
|
|
||||||
if (m_frequencyFactor != 0.0) {
|
if (m_frequencyFactor != 0.0) {
|
||||||
p_directSoundBuffer->SetFrequency(m_frequencyFactor * m_dwFrequency);
|
ma_sound_set_pitch(p_sound, m_frequencyFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,12 +281,12 @@ void Lego3DSound::Reset()
|
||||||
MxS32 Lego3DSound::SetDistance(MxS32 p_min, MxS32 p_max)
|
MxS32 Lego3DSound::SetDistance(MxS32 p_min, MxS32 p_max)
|
||||||
{
|
{
|
||||||
if (MxOmni::IsSound3D()) {
|
if (MxOmni::IsSound3D()) {
|
||||||
if (m_ds3dBuffer == NULL) {
|
if (m_sound == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ds3dBuffer->SetMinDistance(p_min, DS3D_IMMEDIATE);
|
ma_sound_set_min_distance(m_sound, p_min);
|
||||||
m_ds3dBuffer->SetMaxDistance(p_max, DS3D_IMMEDIATE);
|
ma_sound_set_max_distance(m_sound, p_max);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ void Lego3DWavePresenter::StartingTickle()
|
||||||
|
|
||||||
MxWavePresenter::StartingTickle();
|
MxWavePresenter::StartingTickle();
|
||||||
|
|
||||||
if (m_dsBuffer != NULL) {
|
if (ma_sound_get_engine(&(MxWavePresenter::m_sound))) {
|
||||||
MxU16 extraLength;
|
MxU16 extraLength;
|
||||||
char* buff;
|
char* buff;
|
||||||
m_action->GetExtra(extraLength, buff);
|
m_action->GetExtra(extraLength, buff);
|
||||||
|
@ -49,9 +49,7 @@ void Lego3DWavePresenter::StartingTickle()
|
||||||
m_compositePresenter->GetAction()->GetExtra(extraLength, buff);
|
m_compositePresenter->GetAction()->GetExtra(extraLength, buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_sound.Create(m_dsBuffer, buff, m_volume) != SUCCESS) {
|
if (m_sound.Create(&(MxWavePresenter::m_sound), buff, m_volume) != SUCCESS) {
|
||||||
m_dsBuffer->Release();
|
|
||||||
m_dsBuffer = NULL;
|
|
||||||
EndAction();
|
EndAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,5 +60,5 @@ void Lego3DWavePresenter::StartingTickle()
|
||||||
void Lego3DWavePresenter::StreamingTickle()
|
void Lego3DWavePresenter::StreamingTickle()
|
||||||
{
|
{
|
||||||
MxWavePresenter::StreamingTickle();
|
MxWavePresenter::StreamingTickle();
|
||||||
m_sound.UpdatePosition(m_dsBuffer);
|
m_sound.UpdatePosition(&(MxWavePresenter::m_sound));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "mxomni.h"
|
#include "mxomni.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(LegoCacheSound, 0x88)
|
DECOMP_SIZE_ASSERT(LegoCacheSound, 0x88)
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100064d0
|
// FUNCTION: LEGO1 0x100064d0
|
||||||
|
@ -21,7 +23,8 @@ LegoCacheSound::~LegoCacheSound()
|
||||||
// FUNCTION: LEGO1 0x100066d0
|
// FUNCTION: LEGO1 0x100066d0
|
||||||
void LegoCacheSound::Init()
|
void LegoCacheSound::Init()
|
||||||
{
|
{
|
||||||
m_dsBuffer = NULL;
|
SDL_zero(m_buffer);
|
||||||
|
SDL_zero(m_cacheSound);
|
||||||
m_data = NULL;
|
m_data = NULL;
|
||||||
m_unk0x58 = FALSE;
|
m_unk0x58 = FALSE;
|
||||||
memset(&m_wfx, 0, sizeof(m_wfx));
|
memset(&m_wfx, 0, sizeof(m_wfx));
|
||||||
|
@ -35,59 +38,53 @@ void LegoCacheSound::Init()
|
||||||
// FUNCTION: LEGO1 0x10006710
|
// FUNCTION: LEGO1 0x10006710
|
||||||
// FUNCTION: BETA10 0x10066505
|
// FUNCTION: BETA10 0x10066505
|
||||||
MxResult LegoCacheSound::Create(
|
MxResult LegoCacheSound::Create(
|
||||||
LPPCMWAVEFORMAT p_pwfx,
|
MxWavePresenter::WaveFormat& p_pwfx,
|
||||||
MxString p_mediaSrcPath,
|
MxString p_mediaSrcPath,
|
||||||
MxS32 p_volume,
|
MxS32 p_volume,
|
||||||
MxU8* p_data,
|
MxU8* p_data,
|
||||||
MxU32 p_dataSize
|
MxU32 p_dataSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
WAVEFORMATEX wfx;
|
// [library:audio] These should never be null
|
||||||
wfx.wFormatTag = p_pwfx->wf.wFormatTag;
|
assert(p_data != NULL && p_dataSize != 0);
|
||||||
wfx.nChannels = p_pwfx->wf.nChannels;
|
|
||||||
wfx.nSamplesPerSec = p_pwfx->wf.nSamplesPerSec;
|
|
||||||
wfx.nAvgBytesPerSec = p_pwfx->wf.nAvgBytesPerSec;
|
|
||||||
wfx.nBlockAlign = p_pwfx->wf.nBlockAlign;
|
|
||||||
wfx.wBitsPerSample = p_pwfx->wBitsPerSample;
|
|
||||||
wfx.cbSize = 0;
|
|
||||||
|
|
||||||
DSBUFFERDESC desc;
|
assert(p_pwfx.m_formatTag == g_supportedFormatTag);
|
||||||
memset(&desc, 0, sizeof(desc));
|
assert(p_pwfx.m_bitsPerSample == 8 || p_pwfx.m_bitsPerSample == 16);
|
||||||
desc.dwSize = sizeof(desc);
|
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
CopyData(p_data, p_dataSize);
|
||||||
desc.dwFlags =
|
|
||||||
DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME;
|
ma_format format = p_pwfx.m_bitsPerSample == 16 ? ma_format_s16 : ma_format_u8;
|
||||||
}
|
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(format, p_pwfx.m_channels);
|
||||||
else {
|
ma_uint32 bufferSizeInFrames = p_dataSize / bytesPerFrame;
|
||||||
desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
|
ma_audio_buffer_config config =
|
||||||
|
ma_audio_buffer_config_init(format, p_pwfx.m_channels, bufferSizeInFrames, m_data, NULL);
|
||||||
|
config.sampleRate = p_pwfx.m_samplesPerSec;
|
||||||
|
|
||||||
|
if (ma_audio_buffer_init(&config, &m_buffer) != MA_SUCCESS) {
|
||||||
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
desc.dwBufferBytes = p_dataSize;
|
if (ma_sound_init_from_data_source(
|
||||||
desc.lpwfxFormat = &wfx;
|
SoundManager()->GetEngine(),
|
||||||
|
&m_buffer,
|
||||||
if (SoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
|
MxOmni::IsSound3D() ? 0 : MA_SOUND_FLAG_NO_SPATIALIZATION,
|
||||||
|
NULL,
|
||||||
|
&m_cacheSound
|
||||||
|
) != MA_SUCCESS) {
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_volume = p_volume;
|
m_volume = p_volume;
|
||||||
|
|
||||||
MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
|
MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
|
||||||
MxS32 attenuation = SoundManager()->GetAttenuation(volume);
|
ma_sound_set_volume(&m_cacheSound, SoundManager()->GetAttenuation(volume));
|
||||||
m_dsBuffer->SetVolume(attenuation);
|
|
||||||
|
|
||||||
if (m_sound.Create(m_dsBuffer, NULL, m_volume) != SUCCESS) {
|
if (m_sound.Create(&m_cacheSound, NULL, m_volume) != SUCCESS) {
|
||||||
m_dsBuffer->Release();
|
|
||||||
m_dsBuffer = NULL;
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_data != NULL && p_dataSize != 0) {
|
|
||||||
CopyData(p_data, p_dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_unk0x48 = FUN_10006d80(p_mediaSrcPath);
|
m_unk0x48 = FUN_10006d80(p_mediaSrcPath);
|
||||||
m_wfx = *p_pwfx;
|
m_wfx = p_pwfx;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +101,8 @@ void LegoCacheSound::CopyData(MxU8* p_data, MxU32 p_dataSize)
|
||||||
// FUNCTION: LEGO1 0x10006920
|
// FUNCTION: LEGO1 0x10006920
|
||||||
void LegoCacheSound::Destroy()
|
void LegoCacheSound::Destroy()
|
||||||
{
|
{
|
||||||
if (m_dsBuffer) {
|
ma_sound_uninit(&m_cacheSound);
|
||||||
m_dsBuffer->Stop();
|
ma_audio_buffer_uninit(&m_buffer);
|
||||||
m_dsBuffer->Release();
|
|
||||||
m_dsBuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
Init();
|
Init();
|
||||||
|
@ -120,7 +114,7 @@ LegoCacheSound* LegoCacheSound::Clone()
|
||||||
{
|
{
|
||||||
LegoCacheSound* pnew = new LegoCacheSound();
|
LegoCacheSound* pnew = new LegoCacheSound();
|
||||||
|
|
||||||
if (pnew->Create(&m_wfx, m_unk0x48, m_volume, m_data, m_dataSize) == SUCCESS) {
|
if (pnew->Create(m_wfx, m_unk0x48, m_volume, m_data, m_dataSize) == SUCCESS) {
|
||||||
return pnew;
|
return pnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,35 +131,20 @@ MxResult LegoCacheSound::Play(const char* p_name, MxBool p_looping)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_unk0x6a = FALSE;
|
m_unk0x6a = FALSE;
|
||||||
m_sound.FUN_10011a60(m_dsBuffer, p_name);
|
m_sound.FUN_10011a60(&m_cacheSound, p_name);
|
||||||
|
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
m_unk0x74 = p_name;
|
m_unk0x74 = p_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD dwStatus;
|
if (ma_sound_seek_to_pcm_frame(&m_cacheSound, 0) != MA_SUCCESS) {
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
return FAILURE;
|
||||||
|
|
||||||
if (dwStatus == DSBSTATUS_BUFFERLOST) {
|
|
||||||
m_dsBuffer->Restore();
|
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwStatus != DSBSTATUS_BUFFERLOST) {
|
ma_sound_set_looping(&m_cacheSound, p_looping);
|
||||||
LPVOID pvAudioPtr1, pvAudioPtr2;
|
|
||||||
DWORD dwAudioBytes1, dwAudioBytes2;
|
|
||||||
|
|
||||||
if (m_dsBuffer->Lock(0, m_dataSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) == DS_OK) {
|
if (ma_sound_start(&m_cacheSound) != MA_SUCCESS) {
|
||||||
memcpy(pvAudioPtr1, m_data, dwAudioBytes1);
|
return FAILURE;
|
||||||
|
|
||||||
if (dwAudioBytes2 != 0) {
|
|
||||||
memcpy(pvAudioPtr2, m_data + dwAudioBytes1, dwAudioBytes2);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dsBuffer->Unlock(pvAudioPtr1, dwAudioBytes1, pvAudioPtr2, dwAudioBytes2);
|
|
||||||
m_dsBuffer->SetCurrentPosition(0);
|
|
||||||
m_dsBuffer->Play(0, 0, p_looping);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_looping == FALSE) {
|
if (p_looping == FALSE) {
|
||||||
|
@ -183,12 +162,7 @@ MxResult LegoCacheSound::Play(const char* p_name, MxBool p_looping)
|
||||||
// FUNCTION: LEGO1 0x10006b80
|
// FUNCTION: LEGO1 0x10006b80
|
||||||
void LegoCacheSound::FUN_10006b80()
|
void LegoCacheSound::FUN_10006b80()
|
||||||
{
|
{
|
||||||
DWORD dwStatus;
|
ma_sound_stop(&m_cacheSound);
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
|
||||||
|
|
||||||
if (dwStatus) {
|
|
||||||
m_dsBuffer->Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_unk0x58 = FALSE;
|
m_unk0x58 = FALSE;
|
||||||
m_unk0x6a = FALSE;
|
m_unk0x6a = FALSE;
|
||||||
|
@ -203,19 +177,16 @@ void LegoCacheSound::FUN_10006b80()
|
||||||
void LegoCacheSound::FUN_10006be0()
|
void LegoCacheSound::FUN_10006be0()
|
||||||
{
|
{
|
||||||
if (!m_looping) {
|
if (!m_looping) {
|
||||||
DWORD dwStatus;
|
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
|
||||||
|
|
||||||
if (m_unk0x70) {
|
if (m_unk0x70) {
|
||||||
if (dwStatus == 0) {
|
if (!ma_sound_is_playing(&m_cacheSound)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_unk0x70 = FALSE;
|
m_unk0x70 = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwStatus == 0) {
|
if (!ma_sound_is_playing(&m_cacheSound)) {
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_cacheSound);
|
||||||
m_sound.Reset();
|
m_sound.Reset();
|
||||||
if (m_unk0x74.GetLength() != 0) {
|
if (m_unk0x74.GetLength() != 0) {
|
||||||
m_unk0x74 = "";
|
m_unk0x74 = "";
|
||||||
|
@ -227,16 +198,16 @@ void LegoCacheSound::FUN_10006be0()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_unk0x74.GetLength() != 0 && !m_muted) {
|
if (m_unk0x74.GetLength() != 0 && !m_muted) {
|
||||||
if (!m_sound.UpdatePosition(m_dsBuffer)) {
|
if (!m_sound.UpdatePosition(&m_cacheSound)) {
|
||||||
if (m_unk0x6a) {
|
if (m_unk0x6a) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_cacheSound);
|
||||||
m_unk0x6a = TRUE;
|
m_unk0x6a = TRUE;
|
||||||
}
|
}
|
||||||
else if (m_unk0x6a) {
|
else if (m_unk0x6a) {
|
||||||
m_dsBuffer->Play(0, 0, m_looping);
|
ma_sound_start(&m_cacheSound);
|
||||||
m_unk0x6a = FALSE;
|
m_unk0x6a = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,10 +232,10 @@ void LegoCacheSound::Mute(MxBool p_muted)
|
||||||
m_muted = p_muted;
|
m_muted = p_muted;
|
||||||
|
|
||||||
if (m_muted) {
|
if (m_muted) {
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_cacheSound);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_dsBuffer->Play(0, 0, m_looping);
|
ma_sound_start(&m_cacheSound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ void LegoLoadCacheSoundPresenter::ReadyTickle()
|
||||||
m_pData = data;
|
m_pData = data;
|
||||||
|
|
||||||
m_cacheSound = new LegoCacheSound();
|
m_cacheSound = new LegoCacheSound();
|
||||||
m_pcmWaveFormat = header->m_pcmWaveFormat;
|
m_waveFormat = *header;
|
||||||
|
|
||||||
m_subscriber->FreeDataChunk(chunk);
|
m_subscriber->FreeDataChunk(chunk);
|
||||||
ProgressTickleState(e_streaming);
|
ProgressTickleState(e_streaming);
|
||||||
|
@ -69,7 +69,7 @@ void LegoLoadCacheSoundPresenter::StreamingTickle()
|
||||||
if (chunk) {
|
if (chunk) {
|
||||||
if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) {
|
if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) {
|
||||||
m_cacheSound->Create(
|
m_cacheSound->Create(
|
||||||
&m_pcmWaveFormat,
|
m_waveFormat,
|
||||||
((MxDSSound*) m_action)->GetMediaSrcPath(),
|
((MxDSSound*) m_action)->GetMediaSrcPath(),
|
||||||
((MxDSSound*) m_action)->GetVolume(),
|
((MxDSSound*) m_action)->GetVolume(),
|
||||||
m_data + 2,
|
m_data + 2,
|
||||||
|
|
|
@ -22,7 +22,6 @@ LegoSoundManager::~LegoSoundManager()
|
||||||
void LegoSoundManager::Init()
|
void LegoSoundManager::Init()
|
||||||
{
|
{
|
||||||
m_cacheSoundManager = NULL;
|
m_cacheSoundManager = NULL;
|
||||||
m_listener = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100299b0
|
// FUNCTION: LEGO1 0x100299b0
|
||||||
|
@ -45,27 +44,6 @@ MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
||||||
if (MxSoundManager::Create(10, FALSE) == SUCCESS) {
|
if (MxSoundManager::Create(10, FALSE) == SUCCESS) {
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
locked = TRUE;
|
locked = TRUE;
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
|
||||||
if (m_dsBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID*) &m_listener) != DS_OK) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
MxOmni* omni = MxOmni::GetInstance();
|
|
||||||
LPDIRECTSOUND sound;
|
|
||||||
|
|
||||||
if (omni && omni->GetSoundManager() && (sound = omni->GetSoundManager()->GetDirectSound())) {
|
|
||||||
DSCAPS caps;
|
|
||||||
memset(&caps, 0, sizeof(DSCAPS));
|
|
||||||
caps.dwSize = sizeof(DSCAPS);
|
|
||||||
|
|
||||||
if (sound->GetCaps(&caps) == S_OK && caps.dwMaxHw3DAllBuffers == 0) {
|
|
||||||
m_listener->SetDistanceFactor(0.026315790f, 0);
|
|
||||||
m_listener->SetRolloffFactor(10, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cacheSoundManager = new LegoCacheSoundManager;
|
m_cacheSoundManager = new LegoCacheSoundManager;
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -106,29 +84,22 @@ void LegoSoundManager::UpdateListener(
|
||||||
const float* p_velocity
|
const float* p_velocity
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (m_listener != NULL) {
|
if (MxOmni::IsSound3D()) {
|
||||||
|
// [library:audio]
|
||||||
|
// miniaudio expects the right-handed OpenGL coordinate system, while LEGO Island
|
||||||
|
// uses DirectX' left-handed system. The Z-axis needs to be inverted.
|
||||||
|
|
||||||
if (p_position != NULL) {
|
if (p_position != NULL) {
|
||||||
m_listener->SetPosition(p_position[0], p_position[1], p_position[2], DS3D_DEFERRED);
|
ma_engine_listener_set_position(&m_engine, 0, p_position[0], p_position[1], -p_position[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_direction != NULL && p_up != NULL) {
|
if (p_direction != NULL && p_up != NULL) {
|
||||||
m_listener->SetOrientation(
|
ma_engine_listener_set_direction(&m_engine, 0, p_direction[0], p_direction[1], -p_direction[2]);
|
||||||
p_direction[0],
|
ma_engine_listener_set_world_up(&m_engine, 0, p_up[0], p_up[1], -p_up[2]);
|
||||||
p_direction[1],
|
|
||||||
p_direction[2],
|
|
||||||
p_up[0],
|
|
||||||
p_up[1],
|
|
||||||
p_up[2],
|
|
||||||
DS3D_DEFERRED
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_velocity != NULL) {
|
if (p_velocity != NULL) {
|
||||||
m_listener->SetVelocity(p_velocity[0], p_velocity[1], p_velocity[2], DS3D_DEFERRED);
|
ma_engine_listener_set_velocity(&m_engine, 0, p_velocity[0], p_velocity[1], -p_velocity[2]);
|
||||||
}
|
|
||||||
|
|
||||||
if (p_position != NULL || (p_direction != NULL && p_up != NULL) || p_velocity != NULL) {
|
|
||||||
m_listener->CommitDeferredSettings();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#ifndef MXLOOPINGMIDIPRESENTER_H
|
|
||||||
#define MXLOOPINGMIDIPRESENTER_H
|
|
||||||
|
|
||||||
#include "mxmidipresenter.h"
|
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc240
|
|
||||||
// SIZE 0x58
|
|
||||||
class MxLoopingMIDIPresenter : public MxMIDIPresenter {
|
|
||||||
public:
|
|
||||||
// FUNCTION: BETA10 0x1012f0b0
|
|
||||||
static const char* HandlerClassName()
|
|
||||||
{
|
|
||||||
// STRING: LEGO1 0x10101de0
|
|
||||||
return "MxLoopingMIDIPresenter";
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1830
|
|
||||||
// FUNCTION: BETA10 0x10143910
|
|
||||||
inline const char* ClassName() const override // vtable+0x0c
|
|
||||||
{
|
|
||||||
return HandlerClassName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1840
|
|
||||||
inline MxBool IsA(const char* p_name) const override // vtable+0x10
|
|
||||||
{
|
|
||||||
return !strcmp(p_name, MxLoopingMIDIPresenter::ClassName()) || MxMIDIPresenter::IsA(p_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamingTickle() override; // vtable+0x20
|
|
||||||
void DoneTickle() override; // vtable+0x2c
|
|
||||||
MxResult PutData() override; // vtable+0x4c
|
|
||||||
};
|
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100b19c0
|
|
||||||
// MxLoopingMIDIPresenter::`scalar deleting destructor'
|
|
||||||
|
|
||||||
#endif // MXLOOPINGMIDIPRESENTER_H
|
|
|
@ -1,55 +0,0 @@
|
||||||
#ifndef MXMIDIPRESENTER_H
|
|
||||||
#define MXMIDIPRESENTER_H
|
|
||||||
|
|
||||||
#include "mxmusicpresenter.h"
|
|
||||||
|
|
||||||
class MxStreamChunk;
|
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dca20
|
|
||||||
// SIZE 0x58
|
|
||||||
class MxMIDIPresenter : public MxMusicPresenter {
|
|
||||||
public:
|
|
||||||
MxMIDIPresenter();
|
|
||||||
~MxMIDIPresenter() override;
|
|
||||||
|
|
||||||
// FUNCTION: BETA10 0x1012f090
|
|
||||||
static const char* HandlerClassName()
|
|
||||||
{
|
|
||||||
// STRING: LEGO1 0x10101df8
|
|
||||||
return "MxMIDIPresenter";
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2650
|
|
||||||
// FUNCTION: BETA10 0x10143a90
|
|
||||||
inline const char* ClassName() const override // vtable+0x0c
|
|
||||||
{
|
|
||||||
return HandlerClassName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2660
|
|
||||||
inline MxBool IsA(const char* p_name) const override // vtable+0x10
|
|
||||||
{
|
|
||||||
return !strcmp(p_name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(p_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadyTickle() override; // vtable+0x18
|
|
||||||
void StartingTickle() override; // vtable+0x1c
|
|
||||||
void StreamingTickle() override; // vtable+0x20
|
|
||||||
void DoneTickle() override; // vtable+0x2c
|
|
||||||
void Destroy() override; // vtable+0x38
|
|
||||||
void EndAction() override; // vtable+0x40
|
|
||||||
MxResult PutData() override; // vtable+0x4c
|
|
||||||
void SetVolume(MxS32 p_volume) override; // vtable+0x60
|
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100c27a0
|
|
||||||
// MxMIDIPresenter::`scalar deleting destructor'
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Init();
|
|
||||||
void Destroy(MxBool p_fromDestructor);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
MxStreamChunk* m_chunk; // 0x54
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MXMIDIPRESENTER_H
|
|
|
@ -6,7 +6,6 @@
|
||||||
class MxAtomSet;
|
class MxAtomSet;
|
||||||
class MxDSAction;
|
class MxDSAction;
|
||||||
class MxEventManager;
|
class MxEventManager;
|
||||||
class MxMusicManager;
|
|
||||||
class MxNotificationManager;
|
class MxNotificationManager;
|
||||||
class MxObjectFactory;
|
class MxObjectFactory;
|
||||||
class MxSoundManager;
|
class MxSoundManager;
|
||||||
|
@ -21,7 +20,6 @@ MxTimer* Timer();
|
||||||
MxStreamer* Streamer();
|
MxStreamer* Streamer();
|
||||||
MxSoundManager* MSoundManager();
|
MxSoundManager* MSoundManager();
|
||||||
MxVariableTable* VariableTable();
|
MxVariableTable* VariableTable();
|
||||||
MxMusicManager* MusicManager();
|
|
||||||
MxEventManager* EventManager();
|
MxEventManager* EventManager();
|
||||||
MxResult Start(MxDSAction*);
|
MxResult Start(MxDSAction*);
|
||||||
MxNotificationManager* NotificationManager();
|
MxNotificationManager* NotificationManager();
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
#ifndef MXMUSICMANAGER_H
|
|
||||||
#define MXMUSICMANAGER_H
|
|
||||||
|
|
||||||
#include "decomp.h"
|
|
||||||
#include "mxaudiomanager.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc930
|
|
||||||
// SIZE 0x58
|
|
||||||
class MxMusicManager : public MxAudioManager {
|
|
||||||
public:
|
|
||||||
MxMusicManager();
|
|
||||||
~MxMusicManager() override;
|
|
||||||
|
|
||||||
void Destroy() override; // vtable+18
|
|
||||||
void SetVolume(MxS32 p_volume) override; // vtable+2c
|
|
||||||
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((HMIDIOUT) m_midiStreamH, &p_volume)) {
|
|
||||||
p_volume = CalculateVolume(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MxResult ResetStream();
|
|
||||||
void ResetBuffer();
|
|
||||||
MxResult InitializeMIDI(MxU8* p_data, MxS32 p_loopCount);
|
|
||||||
void DeinitializeMIDI();
|
|
||||||
void SetMultiplier(MxS32 p_multiplier);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Destroy(MxBool p_fromDestructor);
|
|
||||||
|
|
||||||
MxS32 CalculateVolume(MxS32 p_volume);
|
|
||||||
void SetMIDIVolume();
|
|
||||||
|
|
||||||
static void CALLBACK MidiCallbackProc(HDRVR p_hdrvr, UINT p_uMsg, DWORD p_dwUser, DWORD p_dw1, DWORD p_dw2);
|
|
||||||
|
|
||||||
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'
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void Init();
|
|
||||||
void InitData();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MXMUSICMANAGER_H
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef MXMUSICPRESENTER_H
|
|
||||||
#define MXMUSICPRESENTER_H
|
|
||||||
|
|
||||||
#include "mxaudiopresenter.h"
|
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc9b8
|
|
||||||
// SIZE 0x54
|
|
||||||
class MxMusicPresenter : public MxAudioPresenter {
|
|
||||||
public:
|
|
||||||
MxMusicPresenter();
|
|
||||||
~MxMusicPresenter() override;
|
|
||||||
|
|
||||||
// FUNCTION: BETA10 0x10143a70
|
|
||||||
static const char* HandlerClassName()
|
|
||||||
{
|
|
||||||
// STRING: LEGO1 0x10101e48
|
|
||||||
return "MxMusicPresenter";
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c23a0
|
|
||||||
// FUNCTION: BETA10 0x10143a50
|
|
||||||
inline const char* ClassName() const override // vtable+0x0c
|
|
||||||
{
|
|
||||||
return HandlerClassName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c23b0
|
|
||||||
inline MxBool IsA(const char* p_name) const override // vtable+0x10
|
|
||||||
{
|
|
||||||
return !strcmp(p_name, MxMusicPresenter::ClassName()) || MxAudioPresenter::IsA(p_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MxResult AddToManager() override; // vtable+0x34
|
|
||||||
void Destroy() override; // vtable+0x38
|
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100c24c0
|
|
||||||
// MxMusicPresenter::`scalar deleting destructor'
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Init();
|
|
||||||
void Destroy(MxBool p_fromDestructor);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MXMUSICPRESENTER_H
|
|
|
@ -12,11 +12,9 @@
|
||||||
X(MxSmkPresenter) \
|
X(MxSmkPresenter) \
|
||||||
X(MxStillPresenter) \
|
X(MxStillPresenter) \
|
||||||
X(MxWavePresenter) \
|
X(MxWavePresenter) \
|
||||||
X(MxMIDIPresenter) \
|
|
||||||
X(MxEventPresenter) \
|
X(MxEventPresenter) \
|
||||||
X(MxLoopingFlcPresenter) \
|
X(MxLoopingFlcPresenter) \
|
||||||
X(MxLoopingSmkPresenter) \
|
X(MxLoopingSmkPresenter)
|
||||||
X(MxLoopingMIDIPresenter)
|
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc220
|
// VTABLE: LEGO1 0x100dc220
|
||||||
class MxObjectFactory : public MxCore {
|
class MxObjectFactory : public MxCore {
|
||||||
|
|
|
@ -11,7 +11,6 @@ class MxAtomSet;
|
||||||
class MxDSAction;
|
class MxDSAction;
|
||||||
class MxEntity;
|
class MxEntity;
|
||||||
class MxEventManager;
|
class MxEventManager;
|
||||||
class MxMusicManager;
|
|
||||||
class MxNotificationManager;
|
class MxNotificationManager;
|
||||||
class MxNotificationParam;
|
class MxNotificationParam;
|
||||||
class MxObjectFactory;
|
class MxObjectFactory;
|
||||||
|
@ -86,9 +85,6 @@ class MxOmni : public MxCore {
|
||||||
// FUNCTION: BETA10 0x101251c0
|
// FUNCTION: BETA10 0x101251c0
|
||||||
MxVariableTable* GetVariableTable() const { return this->m_variableTable; }
|
MxVariableTable* GetVariableTable() const { return this->m_variableTable; }
|
||||||
|
|
||||||
// FUNCTION: BETA10 0x101251e0
|
|
||||||
MxMusicManager* GetMusicManager() const { return this->m_musicManager; }
|
|
||||||
|
|
||||||
// FUNCTION: BETA10 0x10125200
|
// FUNCTION: BETA10 0x10125200
|
||||||
MxEventManager* GetEventManager() const { return this->m_eventManager; }
|
MxEventManager* GetEventManager() const { return this->m_eventManager; }
|
||||||
|
|
||||||
|
@ -111,7 +107,6 @@ class MxOmni : public MxCore {
|
||||||
MxNotificationManager* m_notificationManager; // 0x28
|
MxNotificationManager* m_notificationManager; // 0x28
|
||||||
MxVideoManager* m_videoManager; // 0x2c
|
MxVideoManager* m_videoManager; // 0x2c
|
||||||
MxSoundManager* m_soundManager; // 0x30
|
MxSoundManager* m_soundManager; // 0x30
|
||||||
MxMusicManager* m_musicManager; // 0x34
|
|
||||||
MxEventManager* m_eventManager; // 0x38
|
MxEventManager* m_eventManager; // 0x38
|
||||||
MxTimer* m_timer; // 0x3c
|
MxTimer* m_timer; // 0x3c
|
||||||
MxStreamer* m_streamer; // 0x40
|
MxStreamer* m_streamer; // 0x40
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
#include "mxatom.h"
|
#include "mxatom.h"
|
||||||
#include "mxaudiomanager.h"
|
#include "mxaudiomanager.h"
|
||||||
|
|
||||||
#include <dsound.h>
|
#include <SDL3/SDL_audio.h>
|
||||||
|
#include <miniaudio.h>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc128
|
// VTABLE: LEGO1 0x100dc128
|
||||||
// SIZE 0x3c
|
// SIZE 0x3c
|
||||||
|
@ -20,17 +21,29 @@ class MxSoundManager : public MxAudioManager {
|
||||||
virtual void Pause(); // vtable+0x34
|
virtual void Pause(); // vtable+0x34
|
||||||
virtual void Resume(); // vtable+0x38
|
virtual void Resume(); // vtable+0x38
|
||||||
|
|
||||||
inline LPDIRECTSOUND GetDirectSound() { return m_directSound; }
|
inline ma_engine* GetEngine() { return &m_engine; }
|
||||||
|
|
||||||
MxS32 GetAttenuation(MxU32 p_volume);
|
float GetAttenuation(MxU32 p_volume);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init();
|
void Init();
|
||||||
void Destroy(MxBool p_fromDestructor);
|
void Destroy(MxBool p_fromDestructor);
|
||||||
MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId);
|
MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId);
|
||||||
|
|
||||||
LPDIRECTSOUND m_directSound; // 0x30
|
// [library:audio]
|
||||||
LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34
|
// Upscaling everything to 44.1KHz, since we have various sample rates throughout the game.
|
||||||
|
// Not sure how DirectSound handles this when different buffers have different rates.
|
||||||
|
static const MxU32 g_sampleRate = 44100;
|
||||||
|
|
||||||
|
static void AudioStreamCallback(
|
||||||
|
void* p_userdata,
|
||||||
|
SDL_AudioStream* p_stream,
|
||||||
|
int p_additionalAmount,
|
||||||
|
int p_totalAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
ma_engine m_engine;
|
||||||
|
SDL_AudioStream* m_stream;
|
||||||
undefined m_unk0x38[4];
|
undefined m_unk0x38[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "decomp.h"
|
#include "decomp.h"
|
||||||
#include "mxsoundpresenter.h"
|
#include "mxsoundpresenter.h"
|
||||||
|
|
||||||
#include <dsound.h>
|
#include <miniaudio.h>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d49a8
|
// VTABLE: LEGO1 0x100d49a8
|
||||||
// SIZE 0x6c
|
// SIZE 0x6c
|
||||||
|
@ -56,12 +56,19 @@ class MxWavePresenter : public MxSoundPresenter {
|
||||||
// FUNCTION: LEGO1 0x1000d6b0
|
// FUNCTION: LEGO1 0x1000d6b0
|
||||||
virtual MxBool IsPaused() { return m_paused; } // vtable+0x6c
|
virtual MxBool IsPaused() { return m_paused; } // vtable+0x6c
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
// SIZE 0x18
|
// SIZE 0x18
|
||||||
struct WaveFormat {
|
struct WaveFormat {
|
||||||
PCMWAVEFORMAT m_pcmWaveFormat; // 0x00
|
MxU16 m_formatTag; // 0x00
|
||||||
|
MxU16 m_channels; // 0x02
|
||||||
|
MxU32 m_samplesPerSec; // 0x04
|
||||||
|
MxU32 m_avgBytesPerSec; // 0x08
|
||||||
|
MxU16 m_blockAlign; // 0x0c
|
||||||
|
MxU16 m_bitsPerSample; // 0x0e
|
||||||
MxU32 m_dataSize; // 0x10
|
MxU32 m_dataSize; // 0x10
|
||||||
MxU32 m_flags; // 0x14
|
MxU32 m_flags; // 0x14
|
||||||
};
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1000d810
|
// SYNTHETIC: LEGO1 0x1000d810
|
||||||
// MxWavePresenter::`scalar deleting destructor'
|
// MxWavePresenter::`scalar deleting destructor'
|
||||||
|
@ -69,16 +76,21 @@ class MxWavePresenter : public MxSoundPresenter {
|
||||||
protected:
|
protected:
|
||||||
void Init();
|
void Init();
|
||||||
void Destroy(MxBool p_fromDestructor);
|
void Destroy(MxBool p_fromDestructor);
|
||||||
|
MxBool WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length);
|
||||||
|
|
||||||
MxS8 GetPlayedChunks();
|
// [library:audio] One chunk has up to 1 second worth of frames
|
||||||
MxBool FUN_100b1ba0();
|
static const MxU32 g_millisecondsPerChunk = 1000;
|
||||||
void WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length);
|
|
||||||
|
// [library:audio] Store up to 2 chunks worth of frames (same as in original game)
|
||||||
|
static const MxU32 g_rbSizeInMilliseconds = g_millisecondsPerChunk * 2;
|
||||||
|
|
||||||
|
// [library:audio] WAVE_FORMAT_PCM (audio in .SI files only used this format)
|
||||||
|
static const MxU32 g_supportedFormatTag = 1;
|
||||||
|
|
||||||
WaveFormat* m_waveFormat; // 0x54
|
WaveFormat* m_waveFormat; // 0x54
|
||||||
LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x58
|
ma_pcm_rb m_rb;
|
||||||
|
ma_sound m_sound;
|
||||||
MxU32 m_chunkLength; // 0x5c
|
MxU32 m_chunkLength; // 0x5c
|
||||||
MxU32 m_lockSize; // 0x60
|
|
||||||
MxU8 m_writtenChunks; // 0x64
|
|
||||||
MxBool m_started; // 0x65
|
MxBool m_started; // 0x65
|
||||||
MxBool m_is3d; // 0x66
|
MxBool m_is3d; // 0x66
|
||||||
MxS8 m_silenceData; // 0x67
|
MxS8 m_silenceData; // 0x67
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
#include "mxloopingmidipresenter.h"
|
|
||||||
|
|
||||||
#include "decomp.h"
|
|
||||||
#include "mxdssound.h"
|
|
||||||
#include "mxmisc.h"
|
|
||||||
#include "mxmusicmanager.h"
|
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxLoopingMIDIPresenter, 0x58);
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2a80
|
|
||||||
void MxLoopingMIDIPresenter::StreamingTickle()
|
|
||||||
{
|
|
||||||
if (m_action->GetLoopCount()) {
|
|
||||||
MxMIDIPresenter::StreamingTickle();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_chunk) {
|
|
||||||
m_chunk = NextChunk();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_chunk->GetTime() + m_action->GetDuration() <= m_action->GetElapsedTime()) {
|
|
||||||
ProgressTickleState(e_done);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2ae0
|
|
||||||
void MxLoopingMIDIPresenter::DoneTickle()
|
|
||||||
{
|
|
||||||
if (m_action->GetLoopCount()) {
|
|
||||||
MxMIDIPresenter::DoneTickle();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EndAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2b00
|
|
||||||
MxResult MxLoopingMIDIPresenter::PutData()
|
|
||||||
{
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
|
|
||||||
if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) {
|
|
||||||
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
|
||||||
MusicManager()->InitializeMIDI(m_chunk->GetData(), !m_action->GetLoopCount() ? -1 : m_action->GetLoopCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
#include "mxmidipresenter.h"
|
|
||||||
|
|
||||||
#include "decomp.h"
|
|
||||||
#include "mxautolock.h"
|
|
||||||
#include "mxdssound.h"
|
|
||||||
#include "mxdssubscriber.h"
|
|
||||||
#include "mxmisc.h"
|
|
||||||
#include "mxmusicmanager.h"
|
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxMIDIPresenter, 0x58);
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c25e0
|
|
||||||
MxMIDIPresenter::MxMIDIPresenter()
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c27c0
|
|
||||||
MxMIDIPresenter::~MxMIDIPresenter()
|
|
||||||
{
|
|
||||||
Destroy(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2820
|
|
||||||
void MxMIDIPresenter::Init()
|
|
||||||
{
|
|
||||||
m_chunk = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2830
|
|
||||||
void MxMIDIPresenter::Destroy(MxBool p_fromDestructor)
|
|
||||||
{
|
|
||||||
if (MusicManager()) {
|
|
||||||
MusicManager()->DeinitializeMIDI();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
|
|
||||||
if (m_subscriber && m_chunk) {
|
|
||||||
m_subscriber->FreeDataChunk(m_chunk);
|
|
||||||
}
|
|
||||||
Init();
|
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
|
|
||||||
if (!p_fromDestructor) {
|
|
||||||
MxMusicPresenter::Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2890
|
|
||||||
void MxMIDIPresenter::ReadyTickle()
|
|
||||||
{
|
|
||||||
MxStreamChunk* chunk = NextChunk();
|
|
||||||
|
|
||||||
if (chunk) {
|
|
||||||
m_subscriber->FreeDataChunk(chunk);
|
|
||||||
ParseExtra();
|
|
||||||
ProgressTickleState(e_starting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c28d0
|
|
||||||
void MxMIDIPresenter::StartingTickle()
|
|
||||||
{
|
|
||||||
MxStreamChunk* chunk = CurrentChunk();
|
|
||||||
|
|
||||||
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) {
|
|
||||||
ProgressTickleState(e_streaming);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2910
|
|
||||||
void MxMIDIPresenter::StreamingTickle()
|
|
||||||
{
|
|
||||||
if (m_chunk) {
|
|
||||||
ProgressTickleState(e_done);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_chunk = NextChunk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2940
|
|
||||||
void MxMIDIPresenter::DoneTickle()
|
|
||||||
{
|
|
||||||
if (!MusicManager()->GetMIDIInitialized()) {
|
|
||||||
EndAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2960
|
|
||||||
void MxMIDIPresenter::Destroy()
|
|
||||||
{
|
|
||||||
Destroy(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2970
|
|
||||||
MxResult MxMIDIPresenter::PutData()
|
|
||||||
{
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
|
|
||||||
if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) {
|
|
||||||
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
|
||||||
|
|
||||||
if (MusicManager()->InitializeMIDI(m_chunk->GetData(), 1) != SUCCESS) {
|
|
||||||
EndAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c29e0
|
|
||||||
void MxMIDIPresenter::EndAction()
|
|
||||||
{
|
|
||||||
if (m_action) {
|
|
||||||
AUTOLOCK(m_criticalSection);
|
|
||||||
|
|
||||||
MxMediaPresenter::EndAction();
|
|
||||||
MusicManager()->DeinitializeMIDI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2a60
|
|
||||||
void MxMIDIPresenter::SetVolume(MxS32 p_volume)
|
|
||||||
{
|
|
||||||
m_volume = p_volume;
|
|
||||||
MusicManager()->SetMultiplier(p_volume);
|
|
||||||
}
|
|
|
@ -1,294 +0,0 @@
|
||||||
#include "mxmusicmanager.h"
|
|
||||||
|
|
||||||
#include "mxmisc.h"
|
|
||||||
#include "mxticklemanager.h"
|
|
||||||
#include "mxticklethread.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxMusicManager, 0x58);
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c05a0
|
|
||||||
MxMusicManager::MxMusicManager()
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0630
|
|
||||||
MxMusicManager::~MxMusicManager()
|
|
||||||
{
|
|
||||||
Destroy(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0690
|
|
||||||
void MxMusicManager::Init()
|
|
||||||
{
|
|
||||||
m_multiplier = 100;
|
|
||||||
InitData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c06a0
|
|
||||||
void MxMusicManager::InitData()
|
|
||||||
{
|
|
||||||
m_midiStreamH = 0;
|
|
||||||
m_midiInitialized = FALSE;
|
|
||||||
m_bufferSize = 0;
|
|
||||||
m_bufferCurrentSize = 0;
|
|
||||||
m_bufferOffset = 0;
|
|
||||||
m_bufferCurrentOffset = 0;
|
|
||||||
m_loopCount = 0;
|
|
||||||
m_midiHdrP = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c06c0
|
|
||||||
void MxMusicManager::Destroy(MxBool p_fromDestructor)
|
|
||||||
{
|
|
||||||
if (m_thread) {
|
|
||||||
m_thread->Terminate();
|
|
||||||
if (m_thread) {
|
|
||||||
delete m_thread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TickleManager()->UnregisterClient(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
DeinitializeMIDI();
|
|
||||||
Init();
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
|
|
||||||
if (!p_fromDestructor) {
|
|
||||||
MxAudioManager::Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResetBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_midiHdrP->dwFlags & MHDR_DONE || m_midiHdrP->dwFlags & MHDR_PREPARED) {
|
|
||||||
if (midiOutUnprepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR)) != MMSYSERR_NOERROR) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(m_midiHdrP, 0, sizeof(MIDIHDR));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bufferCurrentOffset += 4;
|
|
||||||
DWORD length = *((DWORD*) m_bufferCurrentOffset);
|
|
||||||
m_bufferCurrentOffset += sizeof(DWORD);
|
|
||||||
|
|
||||||
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--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c07e0
|
|
||||||
void MxMusicManager::ResetBuffer()
|
|
||||||
{
|
|
||||||
m_bufferCurrentOffset = m_bufferOffset;
|
|
||||||
m_bufferCurrentSize = m_bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c07f0
|
|
||||||
void MxMusicManager::SetMIDIVolume()
|
|
||||||
{
|
|
||||||
MxS32 result = (m_volume * m_multiplier) / 0x64;
|
|
||||||
HMIDISTRM streamHandle = m_midiStreamH;
|
|
||||||
|
|
||||||
if (streamHandle) {
|
|
||||||
MxS32 volume = CalculateVolume(result);
|
|
||||||
midiOutSetVolume((HMIDIOUT) streamHandle, volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0820
|
|
||||||
void CALLBACK MxMusicManager::MidiCallbackProc(HDRVR p_hdrvr, UINT p_uMsg, DWORD p_dwUser, DWORD p_dw1, DWORD p_dw2)
|
|
||||||
{
|
|
||||||
if (p_uMsg == MOM_DONE) {
|
|
||||||
((MxMusicManager*) p_dwUser)->ResetStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0840
|
|
||||||
MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
|
||||||
{
|
|
||||||
MxResult status = FAILURE;
|
|
||||||
MxBool locked = FALSE;
|
|
||||||
|
|
||||||
if (MxAudioManager::Create() == SUCCESS) {
|
|
||||||
if (p_createThread) {
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
locked = TRUE;
|
|
||||||
m_thread = new MxTickleThread(this, p_frequencyMS);
|
|
||||||
|
|
||||||
if (!m_thread || m_thread->Start(0, 0) != SUCCESS) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TickleManager()->RegisterClient(this, p_frequencyMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (status != SUCCESS) {
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (locked) {
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0930
|
|
||||||
void MxMusicManager::Destroy()
|
|
||||||
{
|
|
||||||
Destroy(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0940
|
|
||||||
void MxMusicManager::SetVolume(MxS32 p_volume)
|
|
||||||
{
|
|
||||||
MxAudioManager::SetVolume(p_volume);
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
SetMIDIVolume();
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0970
|
|
||||||
void MxMusicManager::SetMultiplier(MxS32 p_multiplier)
|
|
||||||
{
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
m_multiplier = p_multiplier;
|
|
||||||
SetMIDIVolume();
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c09a0
|
|
||||||
MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume)
|
|
||||||
{
|
|
||||||
MxS32 result = (p_volume * 0xffff) / 100;
|
|
||||||
return (result << 0x10) | result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c09c0
|
|
||||||
MxResult MxMusicManager::InitializeMIDI(MxU8* p_data, MxS32 p_loopCount)
|
|
||||||
{
|
|
||||||
MxResult result = FAILURE;
|
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
|
|
||||||
if (!m_midiInitialized) {
|
|
||||||
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(&m_midiStreamH, &device, 1, (DWORD) MidiCallbackProc, (DWORD) this, CALLBACK_FUNCTION) !=
|
|
||||||
MMSYSERR_NOERROR) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetMIDIVolume(m_midiVolume);
|
|
||||||
|
|
||||||
m_midiHdrP = new MIDIHDR();
|
|
||||||
if (!m_midiHdrP) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) != MMSYSERR_NOERROR) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bufferOffset += 0x14;
|
|
||||||
m_bufferSize = *((MxU32*) m_bufferOffset);
|
|
||||||
m_bufferOffset += sizeof(MxU32);
|
|
||||||
m_loopCount = p_loopCount;
|
|
||||||
m_midiInitialized = TRUE;
|
|
||||||
|
|
||||||
ResetBuffer();
|
|
||||||
if (ResetStream() != SUCCESS) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMIDIVolume();
|
|
||||||
if (midiStreamRestart(m_midiStreamH) != MMSYSERR_NOERROR) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0b20
|
|
||||||
void MxMusicManager::DeinitializeMIDI()
|
|
||||||
{
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
|
|
||||||
if (m_midiInitialized) {
|
|
||||||
m_midiInitialized = FALSE;
|
|
||||||
midiStreamStop(m_midiStreamH);
|
|
||||||
midiOutUnprepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR));
|
|
||||||
midiOutSetVolume((HMIDIOUT) m_midiStreamH, m_midiVolume);
|
|
||||||
midiStreamClose(m_midiStreamH);
|
|
||||||
delete m_midiHdrP;
|
|
||||||
InitData();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
#include "mxmusicpresenter.h"
|
|
||||||
|
|
||||||
#include "decomp.h"
|
|
||||||
#include "mxmisc.h"
|
|
||||||
#include "mxmusicmanager.h"
|
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxMusicPresenter, 0x54);
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c22c0
|
|
||||||
MxMusicPresenter::MxMusicPresenter()
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c24e0
|
|
||||||
MxMusicPresenter::~MxMusicPresenter()
|
|
||||||
{
|
|
||||||
Destroy(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2540
|
|
||||||
void MxMusicPresenter::Init()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c2550
|
|
||||||
void MxMusicPresenter::Destroy(MxBool p_fromDestructor)
|
|
||||||
{
|
|
||||||
if (MusicManager()) {
|
|
||||||
MusicManager()->UnregisterPresenter(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
|
||||||
Init();
|
|
||||||
m_criticalSection.Leave();
|
|
||||||
|
|
||||||
if (!p_fromDestructor) {
|
|
||||||
MxMediaPresenter::Destroy(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c25a0
|
|
||||||
MxResult MxMusicPresenter::AddToManager()
|
|
||||||
{
|
|
||||||
MxResult result = FAILURE;
|
|
||||||
|
|
||||||
if (MusicManager()) {
|
|
||||||
result = SUCCESS;
|
|
||||||
MusicManager()->RegisterPresenter(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c25d0
|
|
||||||
void MxMusicPresenter::Destroy()
|
|
||||||
{
|
|
||||||
Destroy(FALSE);
|
|
||||||
}
|
|
|
@ -37,8 +37,8 @@ MxSoundManager::~MxSoundManager()
|
||||||
// FUNCTION: LEGO1 0x100ae830
|
// FUNCTION: LEGO1 0x100ae830
|
||||||
void MxSoundManager::Init()
|
void MxSoundManager::Init()
|
||||||
{
|
{
|
||||||
m_directSound = NULL;
|
SDL_zero(m_engine);
|
||||||
m_dsBuffer = NULL;
|
m_stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100ae840
|
// FUNCTION: LEGO1 0x100ae840
|
||||||
|
@ -54,10 +54,12 @@ void MxSoundManager::Destroy(MxBool p_fromDestructor)
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
|
|
||||||
if (m_dsBuffer) {
|
if (m_stream) {
|
||||||
m_dsBuffer->Release();
|
SDL_DestroyAudioStream(m_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ma_engine_uninit(&m_engine);
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
m_criticalSection.Leave();
|
m_criticalSection.Leave();
|
||||||
|
|
||||||
|
@ -79,56 +81,27 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
locked = TRUE;
|
locked = TRUE;
|
||||||
|
|
||||||
if (DirectSoundCreate(NULL, &m_directSound, NULL) != DS_OK) {
|
ma_engine_config engineConfig = ma_engine_config_init();
|
||||||
|
engineConfig.noDevice = MA_TRUE;
|
||||||
|
engineConfig.channels = MxOmni::IsSound3D() ? 2 : 1;
|
||||||
|
engineConfig.sampleRate = g_sampleRate;
|
||||||
|
|
||||||
|
if (ma_engine_init(&engineConfig, &m_engine) != MA_SUCCESS) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_directSound->SetCooperativeLevel(MxOmni::GetInstance()->GetWindowHandle(), DSSCL_PRIORITY) != DS_OK) {
|
SDL_AudioSpec spec;
|
||||||
|
SDL_zero(spec);
|
||||||
|
spec.freq = ma_engine_get_sample_rate(&m_engine);
|
||||||
|
spec.format = SDL_AUDIO_F32;
|
||||||
|
spec.channels = ma_engine_get_channels(&m_engine);
|
||||||
|
|
||||||
|
if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) ==
|
||||||
|
NULL) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSBUFFERDESC desc;
|
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
|
||||||
memset(&desc, 0, sizeof(desc));
|
|
||||||
desc.dwSize = sizeof(desc);
|
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
|
||||||
desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_directSound->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
|
|
||||||
if (!MxOmni::IsSound3D()) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
MxOmni::SetSound3D(FALSE);
|
|
||||||
desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
|
|
||||||
|
|
||||||
if (m_directSound->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WAVEFORMATEX format;
|
|
||||||
|
|
||||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
|
|
||||||
if (MxOmni::IsSound3D()) {
|
|
||||||
format.nChannels = 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
format.nChannels = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
format.nSamplesPerSec = 11025; // KHz
|
|
||||||
format.wBitsPerSample = 16;
|
|
||||||
format.nBlockAlign = format.nChannels * 2;
|
|
||||||
format.nAvgBytesPerSec = format.nBlockAlign * 11025;
|
|
||||||
format.cbSize = 0;
|
|
||||||
|
|
||||||
status = m_dsBuffer->SetFormat(&format);
|
|
||||||
|
|
||||||
if (p_createThread) {
|
if (p_createThread) {
|
||||||
m_thread = new MxTickleThread(this, p_frequencyMS);
|
m_thread = new MxTickleThread(this, p_frequencyMS);
|
||||||
|
@ -154,6 +127,25 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MxSoundManager::AudioStreamCallback(
|
||||||
|
void* p_userdata,
|
||||||
|
SDL_AudioStream* p_stream,
|
||||||
|
int p_additionalAmount,
|
||||||
|
int p_totalAmount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static MxU8 g_buffer[4096];
|
||||||
|
|
||||||
|
MxSoundManager* manager = (MxSoundManager*) p_userdata;
|
||||||
|
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(ma_format_f32, ma_engine_get_channels(&manager->m_engine));
|
||||||
|
ma_uint32 bufferSizeInFrames = (ma_uint32) SDL_min(sizeof(g_buffer), p_additionalAmount) / bytesPerFrame;
|
||||||
|
ma_uint64 framesRead;
|
||||||
|
|
||||||
|
if (ma_engine_read_pcm_frames(&manager->m_engine, g_buffer, bufferSizeInFrames, &framesRead) == MA_SUCCESS) {
|
||||||
|
SDL_PutAudioStreamData(manager->m_stream, g_buffer, framesRead * bytesPerFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100aeab0
|
// FUNCTION: LEGO1 0x100aeab0
|
||||||
void MxSoundManager::Destroy()
|
void MxSoundManager::Destroy()
|
||||||
{
|
{
|
||||||
|
@ -196,15 +188,15 @@ MxPresenter* MxSoundManager::FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_obje
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100aecf0
|
// FUNCTION: LEGO1 0x100aecf0
|
||||||
MxS32 MxSoundManager::GetAttenuation(MxU32 p_volume)
|
float MxSoundManager::GetAttenuation(MxU32 p_volume)
|
||||||
{
|
{
|
||||||
// The unit for p_volume is percent, rounded to integer.
|
// [library:audio] Convert DSOUND attenutation units to linear miniaudio volume
|
||||||
// Convert to DSOUND attenuation units: -10000 (silent) to 0 (loudest).
|
|
||||||
if (p_volume == 0) {
|
if (p_volume == 0) {
|
||||||
return DSBVOLUME_MIN;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_volumeAttenuation[p_volume - 1];
|
return ma_volume_db_to_linear((float) g_volumeAttenuation[p_volume - 1] / 100.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100aed10
|
// FUNCTION: LEGO1 0x100aed10
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "mxsoundmanager.h"
|
#include "mxsoundmanager.h"
|
||||||
#include "mxutilities.h"
|
#include "mxutilities.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxWavePresenter, 0x6c);
|
DECOMP_SIZE_ASSERT(MxWavePresenter, 0x6c);
|
||||||
DECOMP_SIZE_ASSERT(MxWavePresenter::WaveFormat, 0x18);
|
DECOMP_SIZE_ASSERT(MxWavePresenter::WaveFormat, 0x18);
|
||||||
|
|
||||||
|
@ -17,10 +19,9 @@ DECOMP_SIZE_ASSERT(MxWavePresenter::WaveFormat, 0x18);
|
||||||
void MxWavePresenter::Init()
|
void MxWavePresenter::Init()
|
||||||
{
|
{
|
||||||
m_waveFormat = NULL;
|
m_waveFormat = NULL;
|
||||||
m_dsBuffer = NULL;
|
SDL_zero(m_rb);
|
||||||
|
SDL_zero(m_sound);
|
||||||
m_chunkLength = 0;
|
m_chunkLength = 0;
|
||||||
m_lockSize = 0;
|
|
||||||
m_writtenChunks = 0;
|
|
||||||
m_started = FALSE;
|
m_started = FALSE;
|
||||||
m_is3d = FALSE;
|
m_is3d = FALSE;
|
||||||
m_paused = FALSE;
|
m_paused = FALSE;
|
||||||
|
@ -37,10 +38,8 @@ MxResult MxWavePresenter::AddToManager()
|
||||||
// FUNCTION: LEGO1 0x100b1b10
|
// FUNCTION: LEGO1 0x100b1b10
|
||||||
void MxWavePresenter::Destroy(MxBool p_fromDestructor)
|
void MxWavePresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (m_dsBuffer) {
|
ma_sound_uninit(&m_sound);
|
||||||
m_dsBuffer->Stop();
|
ma_pcm_rb_uninit(&m_rb);
|
||||||
m_dsBuffer->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_waveFormat) {
|
if (m_waveFormat) {
|
||||||
delete[] ((MxU8*) m_waveFormat);
|
delete[] ((MxU8*) m_waveFormat);
|
||||||
|
@ -53,64 +52,34 @@ void MxWavePresenter::Destroy(MxBool p_fromDestructor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1b60
|
|
||||||
MxS8 MxWavePresenter::GetPlayedChunks()
|
|
||||||
{
|
|
||||||
DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
|
|
||||||
MxS8 playedChunks = -1;
|
|
||||||
|
|
||||||
if (m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor) == DS_OK) {
|
|
||||||
playedChunks = dwCurrentPlayCursor / m_chunkLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return playedChunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1ba0
|
|
||||||
MxBool MxWavePresenter::FUN_100b1ba0()
|
|
||||||
{
|
|
||||||
return !m_started || GetPlayedChunks() != m_writtenChunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1bd0
|
// FUNCTION: LEGO1 0x100b1bd0
|
||||||
void MxWavePresenter::WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length)
|
MxBool MxWavePresenter::WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length)
|
||||||
{
|
{
|
||||||
DWORD dwStatus;
|
ma_uint32 requestedFrames =
|
||||||
LPVOID pvAudioPtr1;
|
ma_calculate_buffer_size_in_frames_from_milliseconds(g_millisecondsPerChunk, m_waveFormat->m_samplesPerSec);
|
||||||
DWORD dwOffset;
|
ma_uint32 acquiredFrames = requestedFrames;
|
||||||
LPVOID pvAudioPtr2;
|
void* bufferOut;
|
||||||
DWORD dwAudioBytes1;
|
|
||||||
DWORD dwAudioBytes2;
|
|
||||||
|
|
||||||
dwOffset = m_chunkLength * m_writtenChunks;
|
ma_pcm_rb_acquire_write(&m_rb, &acquiredFrames, &bufferOut);
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
|
||||||
|
|
||||||
if (dwStatus == DSBSTATUS_BUFFERLOST) {
|
// [library:audio] If there isn't enough space in the buffer for a full chunk, try again later.
|
||||||
m_dsBuffer->Restore();
|
if (acquiredFrames != requestedFrames) {
|
||||||
m_dsBuffer->GetStatus(&dwStatus);
|
ma_pcm_rb_commit_write(&m_rb, 0);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwStatus != DSBSTATUS_BUFFERLOST) {
|
ma_uint32 acquiredBytes = acquiredFrames * ma_get_bytes_per_frame(m_rb.format, m_rb.channels);
|
||||||
if (m_action->GetFlags() & MxDSAction::c_looping) {
|
assert(p_length <= acquiredBytes);
|
||||||
m_writtenChunks++;
|
|
||||||
m_lockSize = p_length;
|
memcpy(bufferOut, p_audioPtr, p_length);
|
||||||
}
|
|
||||||
else {
|
// [library:audio] Pad with silence data if we don't have a full chunk.
|
||||||
m_writtenChunks = 1 - m_writtenChunks;
|
if (p_length < acquiredBytes) {
|
||||||
m_lockSize = m_chunkLength;
|
memset((ma_uint8*) bufferOut + p_length, m_silenceData, acquiredBytes - p_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_dsBuffer->Lock(dwOffset, m_lockSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) ==
|
ma_pcm_rb_commit_write(&m_rb, acquiredFrames);
|
||||||
DS_OK) {
|
return TRUE;
|
||||||
memcpy(pvAudioPtr1, p_audioPtr, p_length);
|
|
||||||
|
|
||||||
if (m_lockSize > p_length && !(m_action->GetFlags() & MxDSAction::c_looping)) {
|
|
||||||
memset((MxU8*) pvAudioPtr1 + p_length, m_silenceData, m_lockSize - p_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dsBuffer->Unlock(pvAudioPtr1, m_lockSize, pvAudioPtr2, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1cf0
|
// FUNCTION: LEGO1 0x100b1cf0
|
||||||
|
@ -133,54 +102,67 @@ void MxWavePresenter::StartingTickle()
|
||||||
MxStreamChunk* chunk = CurrentChunk();
|
MxStreamChunk* chunk = CurrentChunk();
|
||||||
|
|
||||||
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) {
|
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) {
|
||||||
MxU32 length = chunk->GetLength();
|
MxBool success = FALSE;
|
||||||
WAVEFORMATEX waveFormatEx;
|
m_chunkLength = chunk->GetLength();
|
||||||
|
|
||||||
m_chunkLength = length;
|
assert(m_waveFormat->m_formatTag == g_supportedFormatTag);
|
||||||
memset(&waveFormatEx, 0, sizeof(waveFormatEx));
|
assert(m_waveFormat->m_bitsPerSample == 8 || m_waveFormat->m_bitsPerSample == 16);
|
||||||
|
|
||||||
waveFormatEx.wFormatTag = m_waveFormat->m_pcmWaveFormat.wf.wFormatTag;
|
// [library:audio]
|
||||||
waveFormatEx.nChannels = m_waveFormat->m_pcmWaveFormat.wf.nChannels;
|
// The original game supported a looping/repeating action mode which apparently
|
||||||
waveFormatEx.nSamplesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nSamplesPerSec;
|
// went unused in the retail version of the game (at least for audio).
|
||||||
waveFormatEx.nAvgBytesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec;
|
// It is only ever "used" on startup to load two dummy sounds which are
|
||||||
waveFormatEx.nBlockAlign = m_waveFormat->m_pcmWaveFormat.wf.nBlockAlign;
|
// initially disabled and never play: IsleScript::c_TransitionSound1 and IsleScript::c_TransitionSound2
|
||||||
waveFormatEx.wBitsPerSample = m_waveFormat->m_pcmWaveFormat.wBitsPerSample;
|
// If MxDSAction::c_looping was set, MxWavePresenter kept the entire sound track
|
||||||
|
// in a buffer, presumably to allow random seeking and looping. This functionality
|
||||||
|
// has most likely been superseded by the looping mechanism implemented in the streaming layer.
|
||||||
|
// Since this has gone unused and to reduce complexity, we don't allow this anymore;
|
||||||
|
// except for the two dummy sounds, which must be !IsEnabled()
|
||||||
|
assert(!(m_action->GetFlags() & MxDSAction::c_looping) || !IsEnabled());
|
||||||
|
|
||||||
if (waveFormatEx.wBitsPerSample == 8) {
|
if (m_waveFormat->m_bitsPerSample == 8) {
|
||||||
m_silenceData = 0x7F;
|
m_silenceData = 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waveFormatEx.wBitsPerSample == 16) {
|
if (m_waveFormat->m_bitsPerSample == 16) {
|
||||||
m_silenceData = 0;
|
m_silenceData = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSBUFFERDESC desc;
|
if (ma_pcm_rb_init(
|
||||||
memset(&desc, 0, sizeof(desc));
|
m_waveFormat->m_bitsPerSample == 16 ? ma_format_s16 : ma_format_u8,
|
||||||
desc.dwSize = sizeof(desc);
|
m_waveFormat->m_channels,
|
||||||
|
ma_calculate_buffer_size_in_frames_from_milliseconds(
|
||||||
if (m_is3d) {
|
g_rbSizeInMilliseconds,
|
||||||
desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
|
m_waveFormat->m_samplesPerSec
|
||||||
}
|
),
|
||||||
else {
|
NULL,
|
||||||
desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
|
NULL,
|
||||||
|
&m_rb
|
||||||
|
) != MA_SUCCESS) {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_action->GetFlags() & MxDSAction::c_looping) {
|
ma_pcm_rb_set_sample_rate(&m_rb, m_waveFormat->m_samplesPerSec);
|
||||||
desc.dwBufferBytes = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec *
|
|
||||||
(m_action->GetDuration() / m_action->GetLoopCount()) / 1000;
|
if (ma_sound_init_from_data_source(
|
||||||
}
|
MSoundManager()->GetEngine(),
|
||||||
else {
|
&m_rb,
|
||||||
desc.dwBufferBytes = 2 * length;
|
m_is3d ? 0 : MA_SOUND_FLAG_NO_SPATIALIZATION,
|
||||||
|
NULL,
|
||||||
|
&m_sound
|
||||||
|
) != MA_SUCCESS) {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
desc.lpwfxFormat = &waveFormatEx;
|
ma_sound_set_looping(&m_sound, MA_TRUE);
|
||||||
|
|
||||||
if (MSoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
|
|
||||||
EndAction();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
||||||
ProgressTickleState(e_streaming);
|
ProgressTickleState(e_streaming);
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (!success) {
|
||||||
|
EndAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,18 +197,8 @@ void MxWavePresenter::StreamingTickle()
|
||||||
// FUNCTION: LEGO1 0x100b20c0
|
// FUNCTION: LEGO1 0x100b20c0
|
||||||
void MxWavePresenter::DoneTickle()
|
void MxWavePresenter::DoneTickle()
|
||||||
{
|
{
|
||||||
if (m_dsBuffer) {
|
if (!ma_sound_get_engine(&m_sound) || m_action->GetFlags() & MxDSAction::c_bit7 ||
|
||||||
DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
|
ma_pcm_rb_pointer_distance(&m_rb) == 0) {
|
||||||
m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor);
|
|
||||||
|
|
||||||
MxS8 playedChunks = dwCurrentPlayCursor / m_chunkLength;
|
|
||||||
if (m_action->GetFlags() & MxDSAction::c_bit7 || m_action->GetFlags() & MxDSAction::c_looping ||
|
|
||||||
(!(m_action->GetFlags() & MxDSAction::c_looping) &&
|
|
||||||
(m_writtenChunks != playedChunks || m_lockSize + (m_chunkLength * playedChunks) <= dwCurrentPlayCursor))) {
|
|
||||||
MxMediaPresenter::DoneTickle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MxMediaPresenter::DoneTickle();
|
MxMediaPresenter::DoneTickle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,16 +220,13 @@ MxResult MxWavePresenter::PutData()
|
||||||
if (IsEnabled()) {
|
if (IsEnabled()) {
|
||||||
switch (m_currentTickleState) {
|
switch (m_currentTickleState) {
|
||||||
case e_streaming:
|
case e_streaming:
|
||||||
if (m_currentChunk && FUN_100b1ba0()) {
|
if (m_currentChunk && WriteToSoundBuffer(m_currentChunk->GetData(), m_currentChunk->GetLength())) {
|
||||||
WriteToSoundBuffer(m_currentChunk->GetData(), m_currentChunk->GetLength());
|
|
||||||
m_subscriber->FreeDataChunk(m_currentChunk);
|
m_subscriber->FreeDataChunk(m_currentChunk);
|
||||||
m_currentChunk = NULL;
|
m_currentChunk = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_started) {
|
if (!m_started) {
|
||||||
m_dsBuffer->SetCurrentPosition(0);
|
if (ma_sound_start(&m_sound) == MA_SUCCESS) {
|
||||||
|
|
||||||
if (m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING) == DS_OK) {
|
|
||||||
m_started = TRUE;
|
m_started = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,9 +236,7 @@ MxResult MxWavePresenter::PutData()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dsBuffer->SetCurrentPosition(0);
|
if (ma_sound_start(&m_sound) == MA_SUCCESS) {
|
||||||
|
|
||||||
if (m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1) == DS_OK) {
|
|
||||||
m_started = TRUE;
|
m_started = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,8 +252,8 @@ void MxWavePresenter::EndAction()
|
||||||
AUTOLOCK(m_criticalSection);
|
AUTOLOCK(m_criticalSection);
|
||||||
MxMediaPresenter::EndAction();
|
MxMediaPresenter::EndAction();
|
||||||
|
|
||||||
if (m_dsBuffer) {
|
if (ma_sound_get_engine(&m_sound)) {
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,10 +264,10 @@ void MxWavePresenter::SetVolume(MxS32 p_volume)
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
|
|
||||||
m_volume = p_volume;
|
m_volume = p_volume;
|
||||||
if (m_dsBuffer != NULL) {
|
if (ma_sound_get_engine(&m_sound)) {
|
||||||
MxS32 volume = p_volume * MxOmni::GetInstance()->GetSoundManager()->GetVolume() / 100;
|
MxS32 volume = p_volume * MxOmni::GetInstance()->GetSoundManager()->GetVolume() / 100;
|
||||||
MxS32 attenuation = MxOmni::GetInstance()->GetSoundManager()->GetAttenuation(volume);
|
float attenuation = MxOmni::GetInstance()->GetSoundManager()->GetAttenuation(volume);
|
||||||
m_dsBuffer->SetVolume(attenuation);
|
ma_sound_set_volume(&m_sound, attenuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
m_criticalSection.Leave();
|
||||||
|
@ -313,11 +280,10 @@ void MxWavePresenter::Enable(MxBool p_enable)
|
||||||
MxSoundPresenter::Enable(p_enable);
|
MxSoundPresenter::Enable(p_enable);
|
||||||
|
|
||||||
if (p_enable) {
|
if (p_enable) {
|
||||||
m_writtenChunks = 0;
|
|
||||||
m_started = FALSE;
|
m_started = FALSE;
|
||||||
}
|
}
|
||||||
else if (m_dsBuffer) {
|
else if (ma_sound_get_engine(&m_sound)) {
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,8 +315,8 @@ void MxWavePresenter::ParseExtra()
|
||||||
void MxWavePresenter::Pause()
|
void MxWavePresenter::Pause()
|
||||||
{
|
{
|
||||||
if (!m_paused && m_started) {
|
if (!m_paused && m_started) {
|
||||||
if (m_dsBuffer) {
|
if (ma_sound_get_engine(&m_sound)) {
|
||||||
m_dsBuffer->Stop();
|
ma_sound_stop(&m_sound);
|
||||||
}
|
}
|
||||||
m_paused = TRUE;
|
m_paused = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -360,17 +326,8 @@ void MxWavePresenter::Pause()
|
||||||
void MxWavePresenter::Resume()
|
void MxWavePresenter::Resume()
|
||||||
{
|
{
|
||||||
if (m_paused) {
|
if (m_paused) {
|
||||||
if (m_dsBuffer && m_started) {
|
if (ma_sound_get_engine(&m_sound) && m_started) {
|
||||||
switch (m_currentTickleState) {
|
ma_sound_start(&m_sound);
|
||||||
case e_streaming:
|
|
||||||
m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
||||||
break;
|
|
||||||
case e_repeating:
|
|
||||||
m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1);
|
|
||||||
break;
|
|
||||||
case e_done:
|
|
||||||
m_dsBuffer->Play(0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_paused = FALSE;
|
m_paused = FALSE;
|
||||||
|
|
|
@ -76,14 +76,6 @@ MxVariableTable* VariableTable()
|
||||||
return MxOmni::GetInstance()->GetVariableTable();
|
return MxOmni::GetInstance()->GetVariableTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100acf30
|
|
||||||
// FUNCTION: BETA10 0x10124faf
|
|
||||||
MxMusicManager* MusicManager()
|
|
||||||
{
|
|
||||||
assert(MxOmni::GetInstance());
|
|
||||||
return MxOmni::GetInstance()->GetMusicManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100acf40
|
// FUNCTION: LEGO1 0x100acf40
|
||||||
// FUNCTION: BETA10 0x10124ff6
|
// FUNCTION: BETA10 0x10124ff6
|
||||||
MxEventManager* EventManager()
|
MxEventManager* EventManager()
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
#include "mxeventpresenter.h"
|
#include "mxeventpresenter.h"
|
||||||
#include "mxflcpresenter.h"
|
#include "mxflcpresenter.h"
|
||||||
#include "mxloopingflcpresenter.h"
|
#include "mxloopingflcpresenter.h"
|
||||||
#include "mxloopingmidipresenter.h"
|
|
||||||
#include "mxloopingsmkpresenter.h"
|
#include "mxloopingsmkpresenter.h"
|
||||||
#include "mxmidipresenter.h"
|
|
||||||
#include "mxpresenter.h"
|
#include "mxpresenter.h"
|
||||||
#include "mxsmkpresenter.h"
|
#include "mxsmkpresenter.h"
|
||||||
#include "mxstillpresenter.h"
|
#include "mxstillpresenter.h"
|
||||||
|
|
|
@ -11,9 +11,7 @@
|
||||||
#include "mxeventpresenter.h"
|
#include "mxeventpresenter.h"
|
||||||
#include "mxflcpresenter.h"
|
#include "mxflcpresenter.h"
|
||||||
#include "mxloopingflcpresenter.h"
|
#include "mxloopingflcpresenter.h"
|
||||||
#include "mxloopingmidipresenter.h"
|
|
||||||
#include "mxloopingsmkpresenter.h"
|
#include "mxloopingsmkpresenter.h"
|
||||||
#include "mxmidipresenter.h"
|
|
||||||
#include "mxmisc.h"
|
#include "mxmisc.h"
|
||||||
#include "mxnotificationmanager.h"
|
#include "mxnotificationmanager.h"
|
||||||
#include "mxobjectfactory.h"
|
#include "mxobjectfactory.h"
|
||||||
|
@ -210,8 +208,8 @@ const char* PresenterNameDispatch(const MxDSAction& p_action)
|
||||||
format = ((MxDSSound&) p_action).GetMediaFormat();
|
format = ((MxDSSound&) p_action).GetMediaFormat();
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case FOURCC(' ', 'M', 'I', 'D'):
|
case FOURCC(' ', 'M', 'I', 'D'):
|
||||||
name = !p_action.IsLooping() ? MxMIDIPresenter::HandlerClassName()
|
// [library:audio] No MIDI files are used in the retail version of the game.
|
||||||
: MxLoopingMIDIPresenter::HandlerClassName();
|
assert(FALSE);
|
||||||
break;
|
break;
|
||||||
case FOURCC(' ', 'W', 'A', 'V'):
|
case FOURCC(' ', 'W', 'A', 'V'):
|
||||||
name = MxWavePresenter::HandlerClassName();
|
name = MxWavePresenter::HandlerClassName();
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "mxdsmultiaction.h"
|
#include "mxdsmultiaction.h"
|
||||||
#include "mxeventmanager.h"
|
#include "mxeventmanager.h"
|
||||||
#include "mxmisc.h"
|
#include "mxmisc.h"
|
||||||
#include "mxmusicmanager.h"
|
|
||||||
#include "mxnotificationmanager.h"
|
#include "mxnotificationmanager.h"
|
||||||
#include "mxobjectfactory.h"
|
#include "mxobjectfactory.h"
|
||||||
#include "mxomnicreateparam.h"
|
#include "mxomnicreateparam.h"
|
||||||
|
@ -63,7 +62,6 @@ void MxOmni::Init()
|
||||||
m_notificationManager = NULL;
|
m_notificationManager = NULL;
|
||||||
m_videoManager = NULL;
|
m_videoManager = NULL;
|
||||||
m_soundManager = NULL;
|
m_soundManager = NULL;
|
||||||
m_musicManager = NULL;
|
|
||||||
m_eventManager = NULL;
|
m_eventManager = NULL;
|
||||||
m_timer = NULL;
|
m_timer = NULL;
|
||||||
m_streamer = NULL;
|
m_streamer = NULL;
|
||||||
|
@ -149,15 +147,6 @@ MxResult MxOmni::Create(MxOmniCreateParam& p_param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_param.CreateFlags().CreateMusicManager()) {
|
|
||||||
if ((m_musicManager = new MxMusicManager())) {
|
|
||||||
if (m_musicManager->Create(50, 0) != SUCCESS) {
|
|
||||||
delete m_musicManager;
|
|
||||||
m_musicManager = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_param.CreateFlags().CreateEventManager()) {
|
if (p_param.CreateFlags().CreateEventManager()) {
|
||||||
if ((m_eventManager = new MxEventManager())) {
|
if ((m_eventManager = new MxEventManager())) {
|
||||||
if (m_eventManager->Create(50, 0) != SUCCESS) {
|
if (m_eventManager->Create(50, 0) != SUCCESS) {
|
||||||
|
@ -198,7 +187,6 @@ void MxOmni::Destroy()
|
||||||
|
|
||||||
delete m_eventManager;
|
delete m_eventManager;
|
||||||
delete m_soundManager;
|
delete m_soundManager;
|
||||||
delete m_musicManager;
|
|
||||||
delete m_videoManager;
|
delete m_videoManager;
|
||||||
delete m_streamer;
|
delete m_streamer;
|
||||||
delete m_timer;
|
delete m_timer;
|
||||||
|
|
|
@ -27,7 +27,7 @@ To achieve our goal of platform independence, we need to replace any Windows-onl
|
||||||
| Filesystem | [SDL3](https://www.libsdl.org/) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Afilesystem%5D%22&type=code) |
|
| Filesystem | [SDL3](https://www.libsdl.org/) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Afilesystem%5D%22&type=code) |
|
||||||
| Threads, Mutexes (Synchronization) | [SDL3](https://www.libsdl.org/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Asynchronization%5D%22&type=code) |
|
| Threads, Mutexes (Synchronization) | [SDL3](https://www.libsdl.org/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Asynchronization%5D%22&type=code) |
|
||||||
| Keyboard/Mouse, Joystick, DirectInput (Input) | [SDL3](https://www.libsdl.org/) | WIP | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Ainput%5D%22&type=code) |
|
| Keyboard/Mouse, Joystick, DirectInput (Input) | [SDL3](https://www.libsdl.org/) | WIP | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Ainput%5D%22&type=code) |
|
||||||
| WinMM, DirectSound (Audio) | [SDL_mixer](https://github.com/libsdl-org/SDL_mixer) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aaudio%5D%22&type=code) |
|
| WinMM, DirectSound (Audio) | [SDL3](https://www.libsdl.org/), [miniaudio](https://miniaud.io/) | WIP | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aaudio%5D%22&type=code) |
|
||||||
| DirectDraw (2D video) | [SDL3](https://www.libsdl.org/) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A2d%5D%22&type=code) |
|
| DirectDraw (2D video) | [SDL3](https://www.libsdl.org/) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A2d%5D%22&type=code) |
|
||||||
| [Smacker](https://github.com/isledecomp/isle/tree/master/3rdparty/smacker) | [libsmacker](https://github.com/foxtacles/libsmacker) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable%20%22%2F%2F%20%5Blibrary%3Alibsmacker%5D%22&type=code) |
|
| [Smacker](https://github.com/isledecomp/isle/tree/master/3rdparty/smacker) | [libsmacker](https://github.com/foxtacles/libsmacker) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable%20%22%2F%2F%20%5Blibrary%3Alibsmacker%5D%22&type=code) |
|
||||||
| Direct3D (3D video) | [SDL3](https://www.libsdl.org/), OpenGL ES (**TBD**) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) |
|
| Direct3D (3D video) | [SDL3](https://www.libsdl.org/), OpenGL ES (**TBD**) | ❌ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) |
|
||||||
|
|
Loading…
Reference in a new issue