isle/LEGO1/lego/legoomni/src/audio/legocachsound.cpp
2025-08-05 22:51:55 -04:00

388 lines
7.6 KiB
C++

#include "legocachsound.h"
#include "legosoundmanager.h"
#include "misc.h"
#include "mxmain.h"
#include <assert.h>
DECOMP_SIZE_ASSERT(LegoCacheSound, 0x88)
// FUNCTION: LEGO1 0x100064d0
// FUNCTION: BETA10 0x10066340
LegoCacheSound::LegoCacheSound()
{
Init();
}
// FUNCTION: LEGO1 0x10006630
// FUNCTION: BETA10 0x100663f3
LegoCacheSound::~LegoCacheSound()
{
Destroy();
}
// FUNCTION: LEGO1 0x100066d0
// FUNCTION: BETA10 0x10066498
void LegoCacheSound::Init()
{
m_dsBuffer = NULL;
m_data = NULL;
m_unk0x58 = FALSE;
memset(&m_wfx, 0, sizeof(m_wfx));
m_looping = TRUE;
m_unk0x6a = FALSE;
m_volume = 79;
m_unk0x70 = FALSE;
m_muted = FALSE;
}
// FUNCTION: LEGO1 0x10006710
// FUNCTION: BETA10 0x10066505
MxResult LegoCacheSound::Create(
LPPCMWAVEFORMAT p_pwfx,
MxString p_mediaSrcPath,
MxS32 p_volume,
MxU8* p_data,
MxU32 p_dataSize
)
{
assert(p_pwfx);
WAVEFORMATEX wfx;
wfx.wFormatTag = p_pwfx->wf.wFormatTag;
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;
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if (MxOmni::IsSound3D()) {
desc.dwFlags =
DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME;
}
else {
desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
}
desc.dwBufferBytes = p_dataSize;
desc.lpwfxFormat = &wfx;
if (SoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
return FAILURE;
}
m_volume = p_volume;
MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
MxS32 attenuation = SoundManager()->GetAttenuation(volume);
m_dsBuffer->SetVolume(attenuation);
if (m_sound.Create(m_dsBuffer, NULL, m_volume) != SUCCESS) {
m_dsBuffer->Release();
m_dsBuffer = NULL;
return FAILURE;
}
if (p_data != NULL && p_dataSize != 0) {
CopyData(p_data, p_dataSize);
}
m_unk0x48 = GetBaseFilename(p_mediaSrcPath);
m_wfx = *p_pwfx;
return SUCCESS;
}
// FUNCTION: LEGO1 0x100068e0
// FUNCTION: BETA10 0x100667a0
void LegoCacheSound::CopyData(MxU8* p_data, MxU32 p_dataSize)
{
assert(p_data);
assert(p_dataSize);
delete[] m_data;
m_dataSize = p_dataSize;
m_data = new MxU8[m_dataSize];
memcpy(m_data, p_data, m_dataSize);
}
// FUNCTION: LEGO1 0x10006920
// FUNCTION: BETA10 0x1006685b
void LegoCacheSound::Destroy()
{
if (m_dsBuffer) {
m_dsBuffer->Stop();
m_dsBuffer->Release();
m_dsBuffer = NULL;
}
delete[] m_data;
Init();
}
// FUNCTION: LEGO1 0x10006960
// FUNCTION: BETA10 0x100668cf
LegoCacheSound* LegoCacheSound::Clone()
{
LegoCacheSound* pnew = new LegoCacheSound();
assert(pnew);
MxResult result = pnew->Create(&m_wfx, m_unk0x48, m_volume, m_data, m_dataSize);
if (result == SUCCESS) {
return pnew;
}
else {
delete pnew;
return NULL;
}
}
// FUNCTION: LEGO1 0x10006a30
// FUNCTION: BETA10 0x10066a23
MxResult LegoCacheSound::Play(const char* p_name, MxBool p_looping)
{
assert(m_dsBuffer);
if (m_data == NULL || m_dataSize == 0) {
return FAILURE;
}
m_unk0x6a = FALSE;
m_sound.FUN_10011a60(m_dsBuffer, p_name);
if (p_name != NULL) {
m_unk0x74 = p_name;
}
DWORD dwStatus;
m_dsBuffer->GetStatus(&dwStatus);
if (dwStatus == DSBSTATUS_BUFFERLOST) {
m_dsBuffer->Restore();
m_dsBuffer->GetStatus(&dwStatus);
}
if (dwStatus != DSBSTATUS_BUFFERLOST) {
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
if (m_dsBuffer->Lock(0, m_dataSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) == DS_OK) {
memcpy(pvAudioPtr1, m_data, dwAudioBytes1);
if (dwAudioBytes2 != 0) {
memcpy(pvAudioPtr2, m_data + dwAudioBytes1, dwAudioBytes2);
}
DWORD sts = m_dsBuffer->Unlock(pvAudioPtr1, dwAudioBytes1, pvAudioPtr2, dwAudioBytes2);
assert(!sts);
m_dsBuffer->SetCurrentPosition(0);
if (m_dsBuffer->Play(0, 0, p_looping)) {
assert(0);
}
}
else {
assert(0);
}
}
else {
assert(0);
}
if (p_looping == FALSE) {
m_looping = FALSE;
}
else {
m_looping = TRUE;
}
m_unk0x58 = TRUE;
m_unk0x70 = TRUE;
return SUCCESS;
}
// FUNCTION: LEGO1 0x10006b80
// FUNCTION: BETA10 0x10066ca3
void LegoCacheSound::Stop()
{
DWORD dwStatus;
m_dsBuffer->GetStatus(&dwStatus);
if (dwStatus) {
m_dsBuffer->Stop();
}
m_unk0x58 = FALSE;
m_unk0x6a = FALSE;
m_sound.Reset();
if (m_unk0x74.GetLength() != 0) {
m_unk0x74 = "";
}
}
// FUNCTION: LEGO1 0x10006be0
// FUNCTION: BETA10 0x10066d23
void LegoCacheSound::FUN_10006be0()
{
if (!m_looping) {
DWORD dwStatus;
m_dsBuffer->GetStatus(&dwStatus);
if (m_unk0x70) {
if (dwStatus == 0) {
return;
}
m_unk0x70 = FALSE;
}
if (dwStatus == 0) {
m_dsBuffer->Stop();
m_sound.Reset();
if (m_unk0x74.GetLength() != 0) {
m_unk0x74 = "";
}
m_unk0x58 = FALSE;
return;
}
}
if (m_unk0x74.GetLength() == 0) {
return;
}
if (!m_muted) {
if (!m_sound.UpdatePosition(m_dsBuffer)) {
if (!m_unk0x6a) {
m_dsBuffer->Stop();
m_unk0x6a = TRUE;
}
}
else if (m_unk0x6a) {
m_dsBuffer->Play(0, 0, m_looping);
m_unk0x6a = FALSE;
}
}
}
// FUNCTION: LEGO1 0x10006cb0
// FUNCTION: BETA10 0x10066e85
void LegoCacheSound::SetDistance(MxS32 p_min, MxS32 p_max)
{
m_sound.SetDistance(p_min, p_max);
}
// FUNCTION: LEGO1 0x10006cd0
// FUNCTION: BETA10 0x10066eb0
void LegoCacheSound::FUN_10006cd0(undefined4, undefined4)
{
}
// FUNCTION: LEGO1 0x10006ce0
void LegoCacheSound::MuteSilence(MxBool p_muted)
{
if (m_muted != p_muted) {
m_muted = p_muted;
if (m_muted) {
m_dsBuffer->SetVolume(-3000);
}
else {
MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
MxS32 attenuation = SoundManager()->GetAttenuation(volume);
m_dsBuffer->SetVolume(attenuation);
}
}
}
// FUNCTION: LEGO1 0x10006d40
// FUNCTION: BETA10 0x10066ec8
void LegoCacheSound::MuteStop(MxBool p_muted)
{
if (m_muted != p_muted) {
m_muted = p_muted;
if (m_muted) {
m_dsBuffer->Stop();
}
else {
m_dsBuffer->Play(0, 0, m_looping);
}
}
}
// FUNCTION: BETA10 0x10066f4d
MxResult LegoCacheSound::GetFrequency(LPDWORD p_freq)
{
return m_dsBuffer->GetFrequency(p_freq);
}
// FUNCTION: BETA10 0x10066f7b
MxResult LegoCacheSound::SetFrequency(DWORD p_freq)
{
return m_dsBuffer->SetFrequency(p_freq);
}
// FUNCTION: BETA10 0x10066fa9
LegoCacheSound::LegoCacheSound(LegoCacheSound& p_sound)
{
CopyFrom(p_sound);
}
// FUNCTION: BETA10 0x10067062
LegoCacheSound& LegoCacheSound::operator=(LegoCacheSound& p_sound)
{
if (this == &p_sound) {
return *this;
}
CopyFrom(p_sound);
return *this;
}
// FUNCTION: BETA10 0x1006709d
void LegoCacheSound::CopyFrom(LegoCacheSound& p_sound)
{
MessageBox(NULL, "don't know how to copy DirectSoundBuffer", NULL, MB_OK);
assert(0);
}
// FUNCTION: LEGO1 0x10006d80
// FUNCTION: BETA10 0x100670e7
MxString LegoCacheSound::GetBaseFilename(MxString& p_path)
{
// Get the base filename from the given path
// e.g. "Z:\Lego\Audio\test.wav" --> "test"
char* str = p_path.GetData();
// Start at the end of the string and work backwards.
char* p = str + strlen(str);
char* end = p;
while (str != p--) {
// If the file has an extension, we want to exclude it from the output.
// Set this as our new end position.
if (*p == '.') {
end = p;
}
// Stop if we hit a directory or drive letter.
if (*p == '\\') {
break;
}
}
MxString output;
// Increment by one to shift p to the start of the filename.
char* x = ++p;
// If end points to the dot in filename, change it to a null terminator.
x[end - p] = '\0';
return output = x;
}