mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-02-03 12:31:15 +00:00
WIP
This commit is contained in:
parent
2775b55691
commit
50305630c8
@ -471,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)
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -40,21 +40,23 @@ void Lego3DWavePresenter::StartingTickle()
|
|||||||
|
|
||||||
MxWavePresenter::StartingTickle();
|
MxWavePresenter::StartingTickle();
|
||||||
|
|
||||||
if (m_dsBuffer != NULL) {
|
/*
|
||||||
MxU16 extraLength;
|
if (m_dsBuffer != NULL) {
|
||||||
char* buff;
|
MxU16 extraLength;
|
||||||
m_action->GetExtra(extraLength, buff);
|
char* buff;
|
||||||
|
m_action->GetExtra(extraLength, buff);
|
||||||
|
|
||||||
if (!strcmp(buff, "FROM_PARENT") && m_compositePresenter != NULL) {
|
if (!strcmp(buff, "FROM_PARENT") && m_compositePresenter != NULL) {
|
||||||
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(m_dsBuffer, buff, m_volume) != SUCCESS) {
|
||||||
m_dsBuffer->Release();
|
m_dsBuffer->Release();
|
||||||
m_dsBuffer = NULL;
|
m_dsBuffer = NULL;
|
||||||
EndAction();
|
EndAction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1004a8b0
|
// FUNCTION: LEGO1 0x1004a8b0
|
||||||
@ -62,5 +64,5 @@ void Lego3DWavePresenter::StartingTickle()
|
|||||||
void Lego3DWavePresenter::StreamingTickle()
|
void Lego3DWavePresenter::StreamingTickle()
|
||||||
{
|
{
|
||||||
MxWavePresenter::StreamingTickle();
|
MxWavePresenter::StreamingTickle();
|
||||||
m_sound.UpdatePosition(m_dsBuffer);
|
// m_sound.UpdatePosition(m_dsBuffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ MxResult LegoCacheSound::Create(
|
|||||||
MxU32 p_dataSize
|
MxU32 p_dataSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
WAVEFORMATEX wfx;
|
WAVEFORMATEX wfx;
|
||||||
wfx.wFormatTag = p_pwfx->wf.wFormatTag;
|
wfx.wFormatTag = p_pwfx->wf.wFormatTag;
|
||||||
wfx.nChannels = p_pwfx->wf.nChannels;
|
wfx.nChannels = p_pwfx->wf.nChannels;
|
||||||
@ -87,7 +88,7 @@ MxResult LegoCacheSound::Create(
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_unk0x48 = FUN_10006d80(p_mediaSrcPath);
|
m_unk0x48 = FUN_10006d80(p_mediaSrcPath);
|
||||||
m_wfx = *p_pwfx;
|
m_wfx = *p_pwfx;*/
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ void LegoLoadCacheSoundPresenter::Destroy(MxBool p_fromDestructor)
|
|||||||
void LegoLoadCacheSoundPresenter::ReadyTickle()
|
void LegoLoadCacheSoundPresenter::ReadyTickle()
|
||||||
{
|
{
|
||||||
MxStreamChunk* chunk = NextChunk();
|
MxStreamChunk* chunk = NextChunk();
|
||||||
|
return EndAction();
|
||||||
|
|
||||||
if (chunk) {
|
if (chunk) {
|
||||||
WaveFormat* header = (WaveFormat*) chunk->GetData();
|
WaveFormat* header = (WaveFormat*) chunk->GetData();
|
||||||
@ -53,7 +54,7 @@ void LegoLoadCacheSoundPresenter::ReadyTickle()
|
|||||||
m_pData = data;
|
m_pData = data;
|
||||||
|
|
||||||
m_cacheSound = new LegoCacheSound();
|
m_cacheSound = new LegoCacheSound();
|
||||||
m_pcmWaveFormat = header->m_pcmWaveFormat;
|
// m_pcmWaveFormat = header->m_pcmWaveFormat;
|
||||||
|
|
||||||
m_subscriber->FreeDataChunk(chunk);
|
m_subscriber->FreeDataChunk(chunk);
|
||||||
ProgressTickleState(e_streaming);
|
ProgressTickleState(e_streaming);
|
||||||
|
|||||||
@ -43,6 +43,7 @@ MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
|||||||
MxResult result = FAILURE;
|
MxResult result = FAILURE;
|
||||||
|
|
||||||
if (MxSoundManager::Create(10, FALSE) == SUCCESS) {
|
if (MxSoundManager::Create(10, FALSE) == SUCCESS) {
|
||||||
|
/*
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
locked = TRUE;
|
locked = TRUE;
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cacheSoundManager = new LegoCacheSoundManager;
|
m_cacheSoundManager = new LegoCacheSoundManager;*/
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ void LegoSoundManager::Destroy()
|
|||||||
// FUNCTION: LEGO1 0x1002a3a0
|
// FUNCTION: LEGO1 0x1002a3a0
|
||||||
MxResult LegoSoundManager::Tickle()
|
MxResult LegoSoundManager::Tickle()
|
||||||
{
|
{
|
||||||
MxSoundManager::Tickle();
|
return MxSoundManager::Tickle();
|
||||||
|
|
||||||
AUTOLOCK(m_criticalSection);
|
AUTOLOCK(m_criticalSection);
|
||||||
return m_cacheSoundManager->Tickle();
|
return m_cacheSoundManager->Tickle();
|
||||||
|
|||||||
@ -5,7 +5,9 @@
|
|||||||
#include "mxatom.h"
|
#include "mxatom.h"
|
||||||
#include "mxaudiomanager.h"
|
#include "mxaudiomanager.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL_audio.h>
|
||||||
#include <dsound.h>
|
#include <dsound.h>
|
||||||
|
#include <miniaudio.h>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dc128
|
// VTABLE: LEGO1 0x100dc128
|
||||||
// SIZE 0x3c
|
// SIZE 0x3c
|
||||||
@ -20,7 +22,7 @@ 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);
|
MxS32 GetAttenuation(MxU32 p_volume);
|
||||||
|
|
||||||
@ -29,8 +31,16 @@ class MxSoundManager : public MxAudioManager {
|
|||||||
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.
|
||||||
|
const ma_uint32 sampleRate = 44100;
|
||||||
|
|
||||||
|
static void SDLCALL
|
||||||
|
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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "mxsoundpresenter.h"
|
#include "mxsoundpresenter.h"
|
||||||
|
|
||||||
#include <dsound.h>
|
#include <dsound.h>
|
||||||
|
#include <miniaudio.h>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d49a8
|
// VTABLE: LEGO1 0x100d49a8
|
||||||
// SIZE 0x6c
|
// SIZE 0x6c
|
||||||
@ -56,12 +57,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
|
||||||
MxU32 m_dataSize; // 0x10
|
MxU16 m_channels; // 0x02
|
||||||
MxU32 m_flags; // 0x14
|
MxU32 m_samplesPerSec; // 0x04
|
||||||
|
MxU32 m_avgBytesPerSec; // 0x08
|
||||||
|
MxU16 m_blockAlign; // 0x0c
|
||||||
|
MxU16 m_bitsPerSample; // 0x0e
|
||||||
|
MxU32 m_dataSize; // 0x10
|
||||||
|
MxU32 m_flags; // 0x14
|
||||||
};
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1000d810
|
// SYNTHETIC: LEGO1 0x1000d810
|
||||||
// MxWavePresenter::`scalar deleting destructor'
|
// MxWavePresenter::`scalar deleting destructor'
|
||||||
@ -69,20 +77,27 @@ 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();
|
const MxU32 millisecondsPerChunk = 1000;
|
||||||
void WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length);
|
|
||||||
|
|
||||||
WaveFormat* m_waveFormat; // 0x54
|
// [library:audio] Store up to 2 chunks worth of frames (same as in original game)
|
||||||
LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x58
|
const MxU32 rbSizeInMilliseconds = millisecondsPerChunk * 2;
|
||||||
MxU32 m_chunkLength; // 0x5c
|
|
||||||
MxU32 m_lockSize; // 0x60
|
// [library:audio] WAVE_FORMAT_PCM (audio in .SI files only used this format)
|
||||||
MxU8 m_writtenChunks; // 0x64
|
const ma_uint32 supportedFormatTag = 1;
|
||||||
MxBool m_started; // 0x65
|
|
||||||
MxBool m_is3d; // 0x66
|
WaveFormat* m_waveFormat; // 0x54
|
||||||
MxS8 m_silenceData; // 0x67
|
ma_pcm_rb m_rb;
|
||||||
MxBool m_paused; // 0x68
|
ma_sound m_sound;
|
||||||
|
MxU32 m_chunkLength; // 0x5c
|
||||||
|
MxU32 m_lockSize; // 0x60
|
||||||
|
MxU8 m_writtenChunks; // 0x64
|
||||||
|
MxBool m_started; // 0x65
|
||||||
|
MxBool m_is3d; // 0x66
|
||||||
|
MxS8 m_silenceData; // 0x67
|
||||||
|
MxBool m_paused; // 0x68
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MXWAVEPRESENTER_H
|
#endif // MXWAVEPRESENTER_H
|
||||||
|
|||||||
@ -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 = 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_OUTPUT, &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 SDLCALL MxSoundManager::AudioStreamCallback(
|
||||||
|
void* p_userdata,
|
||||||
|
SDL_AudioStream* p_stream,
|
||||||
|
int p_additionalAmount,
|
||||||
|
int p_totalAmount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static MxU8 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(buffer), p_additionalAmount) / bytesPerFrame;
|
||||||
|
ma_uint64 framesRead;
|
||||||
|
|
||||||
|
if (ma_engine_read_pcm_frames(&manager->m_engine, buffer, bufferSizeInFrames, &framesRead) == MA_SUCCESS) {
|
||||||
|
SDL_PutAudioStreamData(manager->m_stream, buffer, framesRead * bytesPerFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100aeab0
|
// FUNCTION: LEGO1 0x100aeab0
|
||||||
void MxSoundManager::Destroy()
|
void MxSoundManager::Destroy()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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,7 +19,8 @@ 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_lockSize = 0;
|
||||||
m_writtenChunks = 0;
|
m_writtenChunks = 0;
|
||||||
@ -37,10 +40,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 +54,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(millisecondsPerChunk, m_waveFormat->m_samplesPerSec);
|
||||||
DWORD dwOffset;
|
ma_uint32 acquiredFrames = requestedFrames;
|
||||||
LPVOID pvAudioPtr2;
|
void* p_bufferOut;
|
||||||
DWORD dwAudioBytes1;
|
|
||||||
DWORD dwAudioBytes2;
|
|
||||||
|
|
||||||
dwOffset = m_chunkLength * m_writtenChunks;
|
ma_pcm_rb_acquire_write(&m_rb, &acquiredFrames, &p_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;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_writtenChunks = 1 - m_writtenChunks;
|
|
||||||
m_lockSize = m_chunkLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_dsBuffer->Lock(dwOffset, m_lockSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) ==
|
memcpy(p_bufferOut, p_audioPtr, p_length);
|
||||||
DS_OK) {
|
|
||||||
memcpy(pvAudioPtr1, p_audioPtr, p_length);
|
|
||||||
|
|
||||||
if (m_lockSize > p_length && !(m_action->GetFlags() & MxDSAction::c_looping)) {
|
// [library:audio] Pad with silence data if we don't have a full chunk.
|
||||||
memset((MxU8*) pvAudioPtr1 + p_length, m_silenceData, m_lockSize - p_length);
|
if (p_length < acquiredBytes) {
|
||||||
}
|
memset((ma_uint8*) p_bufferOut + p_length, m_silenceData, acquiredBytes - p_length);
|
||||||
|
|
||||||
m_dsBuffer->Unlock(pvAudioPtr1, m_lockSize, pvAudioPtr2, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ma_pcm_rb_commit_write(&m_rb, acquiredFrames);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b1cf0
|
// FUNCTION: LEGO1 0x100b1cf0
|
||||||
@ -133,55 +104,66 @@ 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 == 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) {
|
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;
|
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
||||||
|
ProgressTickleState(e_streaming);
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
if (MSoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
|
done:
|
||||||
|
if (!success) {
|
||||||
EndAction();
|
EndAction();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
SetVolume(((MxDSSound*) m_action)->GetVolume());
|
|
||||||
ProgressTickleState(e_streaming);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,18 +197,7 @@ 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 || !ma_sound_is_playing(&m_sound)) {
|
||||||
DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
|
|
||||||
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 +219,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 +235,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 +251,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 +263,9 @@ 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);
|
ma_sound_set_volume(&m_sound, (float) volume / 100.0f);
|
||||||
m_dsBuffer->SetVolume(attenuation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_criticalSection.Leave();
|
m_criticalSection.Leave();
|
||||||
@ -316,8 +281,8 @@ void MxWavePresenter::Enable(MxBool p_enable)
|
|||||||
m_writtenChunks = 0;
|
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 +314,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 +325,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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user