Isle
Loading...
Searching...
No Matches
legocachsound.cpp
Go to the documentation of this file.
1#include "legocachsound.h"
2
3#include "legosoundmanager.h"
4#include "misc.h"
5#include "mxomni.h"
6
7#include <assert.h>
8
10
11// FUNCTION: LEGO1 0x100064d0
12// FUNCTION: BETA10 0x10066340
14{
15 Init();
16}
17
18// FUNCTION: LEGO1 0x10006630
19// FUNCTION: BETA10 0x100663f3
21{
22 Destroy();
23}
24
25// FUNCTION: LEGO1 0x100066d0
26// FUNCTION: BETA10 0x10066498
27void LegoCacheSound::Init()
28{
29 m_dsBuffer = NULL;
30 m_data = NULL;
31 m_unk0x58 = FALSE;
32 memset(&m_wfx, 0, sizeof(m_wfx));
33 m_looping = TRUE;
34 m_unk0x6a = FALSE;
35 m_volume = 79;
36 m_unk0x70 = FALSE;
37 m_muted = FALSE;
38}
39
40// FUNCTION: LEGO1 0x10006710
41// FUNCTION: BETA10 0x10066505
43 LPPCMWAVEFORMAT p_pwfx,
44 MxString p_mediaSrcPath,
45 MxS32 p_volume,
46 MxU8* p_data,
47 MxU32 p_dataSize
48)
49{
50 assert(p_pwfx);
51
52 WAVEFORMATEX wfx;
53 wfx.wFormatTag = p_pwfx->wf.wFormatTag;
54 wfx.nChannels = p_pwfx->wf.nChannels;
55 wfx.nSamplesPerSec = p_pwfx->wf.nSamplesPerSec;
56 wfx.nAvgBytesPerSec = p_pwfx->wf.nAvgBytesPerSec;
57 wfx.nBlockAlign = p_pwfx->wf.nBlockAlign;
58 wfx.wBitsPerSample = p_pwfx->wBitsPerSample;
59 wfx.cbSize = 0;
60
61 DSBUFFERDESC desc;
62 memset(&desc, 0, sizeof(desc));
63 desc.dwSize = sizeof(desc);
64
65 if (MxOmni::IsSound3D()) {
66 desc.dwFlags =
68 }
69 else {
71 }
72
73 desc.dwBufferBytes = p_dataSize;
74 desc.lpwfxFormat = &wfx;
75
76 if (SoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
77 return FAILURE;
78 }
79
80 m_volume = p_volume;
81
82 MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
83 MxS32 attenuation = SoundManager()->GetAttenuation(volume);
84 m_dsBuffer->SetVolume(attenuation);
85
86 if (m_sound.Create(m_dsBuffer, NULL, m_volume) != SUCCESS) {
87 m_dsBuffer->Release();
88 m_dsBuffer = NULL;
89 return FAILURE;
90 }
91
92 if (p_data != NULL && p_dataSize != 0) {
93 CopyData(p_data, p_dataSize);
94 }
95
96 m_unk0x48 = GetBaseFilename(p_mediaSrcPath);
97 m_wfx = *p_pwfx;
98 return SUCCESS;
99}
100
101// FUNCTION: LEGO1 0x100068e0
102// FUNCTION: BETA10 0x100667a0
103void LegoCacheSound::CopyData(MxU8* p_data, MxU32 p_dataSize)
104{
105 assert(p_data);
106 assert(p_dataSize);
107
108 delete[] m_data;
109 m_dataSize = p_dataSize;
110 m_data = new MxU8[m_dataSize];
111 memcpy(m_data, p_data, m_dataSize);
112}
113
114// FUNCTION: LEGO1 0x10006920
115// FUNCTION: BETA10 0x1006685b
117{
118 if (m_dsBuffer) {
119 m_dsBuffer->Stop();
120 m_dsBuffer->Release();
121 m_dsBuffer = NULL;
122 }
123
124 delete[] m_data;
125 Init();
126}
127
128// FUNCTION: LEGO1 0x10006960
129// FUNCTION: BETA10 0x100668cf
131{
132 LegoCacheSound* pnew = new LegoCacheSound();
133 assert(pnew);
134
135 MxResult result = pnew->Create(&m_wfx, m_unk0x48, m_volume, m_data, m_dataSize);
136 if (result == SUCCESS) {
137 return pnew;
138 }
139 else {
140 delete pnew;
141 return NULL;
142 }
143}
144
145// FUNCTION: LEGO1 0x10006a30
146// FUNCTION: BETA10 0x10066a23
147MxResult LegoCacheSound::Play(const char* p_name, MxBool p_looping)
148{
149 assert(m_dsBuffer);
150
151 if (m_data == NULL || m_dataSize == 0) {
152 return FAILURE;
153 }
154
155 m_unk0x6a = FALSE;
156 m_sound.FUN_10011a60(m_dsBuffer, p_name);
157
158 if (p_name != NULL) {
159 m_unk0x74 = p_name;
160 }
161
162 DWORD dwStatus;
163 m_dsBuffer->GetStatus(&dwStatus);
164
165 if (dwStatus == DSBSTATUS_BUFFERLOST) {
166 m_dsBuffer->Restore();
167 m_dsBuffer->GetStatus(&dwStatus);
168 }
169
170 if (dwStatus != DSBSTATUS_BUFFERLOST) {
171 LPVOID pvAudioPtr1, pvAudioPtr2;
172 DWORD dwAudioBytes1, dwAudioBytes2;
173
174 if (m_dsBuffer->Lock(0, m_dataSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) == DS_OK) {
175 memcpy(pvAudioPtr1, m_data, dwAudioBytes1);
176
177 if (dwAudioBytes2 != 0) {
178 memcpy(pvAudioPtr2, m_data + dwAudioBytes1, dwAudioBytes2);
179 }
180
181 DWORD sts = m_dsBuffer->Unlock(pvAudioPtr1, dwAudioBytes1, pvAudioPtr2, dwAudioBytes2);
182 assert(!sts);
183 m_dsBuffer->SetCurrentPosition(0);
184 if (m_dsBuffer->Play(0, 0, p_looping)) {
185 assert(0);
186 }
187 }
188 else {
189 assert(0);
190 }
191 }
192 else {
193 assert(0);
194 }
195
196 if (p_looping == FALSE) {
197 m_looping = FALSE;
198 }
199 else {
200 m_looping = TRUE;
201 }
202
203 m_unk0x58 = TRUE;
204 m_unk0x70 = TRUE;
205 return SUCCESS;
206}
207
208// FUNCTION: LEGO1 0x10006b80
209// FUNCTION: BETA10 0x10066ca3
211{
212 DWORD dwStatus;
213 m_dsBuffer->GetStatus(&dwStatus);
214
215 if (dwStatus) {
216 m_dsBuffer->Stop();
217 }
218
219 m_unk0x58 = FALSE;
220 m_unk0x6a = FALSE;
221
222 m_sound.Reset();
223 if (m_unk0x74.GetLength() != 0) {
224 m_unk0x74 = "";
225 }
226}
227
228// FUNCTION: LEGO1 0x10006be0
229// FUNCTION: BETA10 0x10066d23
231{
232 if (!m_looping) {
233 DWORD dwStatus;
234 m_dsBuffer->GetStatus(&dwStatus);
235
236 if (m_unk0x70) {
237 if (dwStatus == 0) {
238 return;
239 }
240
241 m_unk0x70 = FALSE;
242 }
243
244 if (dwStatus == 0) {
245 m_dsBuffer->Stop();
246 m_sound.Reset();
247 if (m_unk0x74.GetLength() != 0) {
248 m_unk0x74 = "";
249 }
250
251 m_unk0x58 = FALSE;
252 return;
253 }
254 }
255
256 if (m_unk0x74.GetLength() == 0) {
257 return;
258 }
259
260 if (!m_muted) {
261 if (!m_sound.UpdatePosition(m_dsBuffer)) {
262 if (!m_unk0x6a) {
263 m_dsBuffer->Stop();
264 m_unk0x6a = TRUE;
265 }
266 }
267 else if (m_unk0x6a) {
268 m_dsBuffer->Play(0, 0, m_looping);
269 m_unk0x6a = FALSE;
270 }
271 }
272}
273
274// FUNCTION: LEGO1 0x10006cb0
275// FUNCTION: BETA10 0x10066e85
277{
278 m_sound.SetDistance(p_min, p_max);
279}
280
281// FUNCTION: LEGO1 0x10006cd0
282// FUNCTION: BETA10 0x10066eb0
284{
285}
286
287// FUNCTION: LEGO1 0x10006ce0
289{
290 if (m_muted != p_muted) {
291 m_muted = p_muted;
292
293 if (m_muted) {
294 m_dsBuffer->SetVolume(-3000);
295 }
296 else {
297 MxS32 volume = m_volume * SoundManager()->GetVolume() / 100;
298 MxS32 attenuation = SoundManager()->GetAttenuation(volume);
299 m_dsBuffer->SetVolume(attenuation);
300 }
301 }
302}
303
304// FUNCTION: LEGO1 0x10006d40
305// FUNCTION: BETA10 0x10066ec8
307{
308 if (m_muted != p_muted) {
309 m_muted = p_muted;
310
311 if (m_muted) {
312 m_dsBuffer->Stop();
313 }
314 else {
315 m_dsBuffer->Play(0, 0, m_looping);
316 }
317 }
318}
319
320// FUNCTION: LEGO1 0x10006d80
321// FUNCTION: BETA10 0x100670e7
322MxString LegoCacheSound::GetBaseFilename(MxString& p_path)
323{
324 // Get the base filename from the given path
325 // e.g. "Z:\Lego\Audio\test.wav" --> "test"
326 char* str = p_path.GetData();
327
328 // Start at the end of the string and work backwards.
329 char* p = str + strlen(str);
330 char* end = p;
331
332 while (str != p--) {
333 // If the file has an extension, we want to exclude it from the output.
334 // Set this as our new end position.
335 if (*p == '.') {
336 end = p;
337 }
338
339 // Stop if we hit a directory or drive letter.
340 if (*p == '\\') {
341 break;
342 }
343 }
344
345 MxString output;
346 // Increment by one to shift p to the start of the filename.
347 char* x = ++p;
348 // If end points to the dot in filename, change it to a null terminator.
349 x[end - p] = '\0';
350 return output = x;
351}
void Reset()
[AI] Releases any in-world/actor/ROI associations and resets member pointers.
MxS32 SetDistance(MxS32 p_min, MxS32 p_max)
[AI] Sets the minimum and maximum 3D sound effective distances if 3D sound is enabled.
MxU32 UpdatePosition(LPDIRECTSOUNDBUFFER p_directSoundBuffer)
[AI] Recalculates and updates the sound position on the underlying DirectSound 3D buffer or the volum...
void FUN_10011a60(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char *p_name)
[AI] Associates a new in-world object to this sound, updating its 3D position tracking and (if applic...
MxResult Create(LPDIRECTSOUNDBUFFER p_directSoundBuffer, const char *p_name, MxS32 p_volume)
[AI] Initializes 3D sound for a given DirectSound buffer and associates it with a named game object.
Definition: lego3dsound.cpp:40
Sound cache object managing DirectSound buffers and 3D positioning for preloaded sound data.
Definition: legocachsound.h:17
void SetDistance(MxS32 p_min, MxS32 p_max)
Sets minimum and maximum audible distances for 3D sound attenuation.
LegoCacheSound * Clone()
Creates an identical copy of this LegoCacheSound, including memory buffers, properties,...
MxResult Play(const char *p_name, MxBool p_looping)
Starts playback of the cached sound in this buffer.
void FUN_10006be0()
Handles sound updates per tick; manages stopping, buffer state, and 3D-position refreshes if sound is...
virtual MxResult Create(LPPCMWAVEFORMAT p_pwfx, MxString p_mediaSrcPath, MxS32 p_volume, MxU8 *p_data, MxU32 p_dataSize)
Creates the sound object with given audio format, source path, volume, and initializes DirectSound bu...
virtual void FUN_10006cd0(undefined4 param1, undefined4 param2)
Unknown legacy/function stub.
~LegoCacheSound() override
Destructor; releases owned sound resources and buffer, unmutes if needed.
void MuteStop(MxBool p_mute)
Mutes/unmutes by stopping (mute) or resuming playback.
void Stop()
Immediately stops playback and resets buffer, clearing event tag and position cues.
LegoCacheSound()
Constructs a new LegoCacheSound and initializes its members to default/empty state.
virtual void Destroy()
Releases allocated DirectSound buffer and internal data, resetting all fields.
void MuteSilence(MxBool p_muted)
Mutes/unmutes by scaling volume to minimum (muted) or restoring original volume.
virtual MxS32 GetVolume()
[AI] Gets the current global audio volume.
static MxBool IsSound3D()
[AI] Returns current state of 3D sound configuration.
Definition: mxomni.cpp:387
MxS32 GetAttenuation(MxU32 p_volume)
[AI] Maps a percentage volume (1-100) to a DirectSound-specific attenuation value.
LPDIRECTSOUND GetDirectSound()
[AI] Gets pointer to internal DirectSound interface.
Mindscape custom string class for managing dynamic C-strings within the game engine.
Definition: mxstring.h:14
char * GetData() const
Returns a pointer to the internal character buffer.
Definition: mxstring.h:110
const MxU16 GetLength() const
Returns the length of the string (number of characters, not including null terminator).
Definition: mxstring.h:115
LPSTR LPSTR LPVOID
Definition: d3dcaps.h:216
#define TRUE
Definition: d3drmdef.h:28
#define FALSE
Definition: d3drmdef.h:27
typedef DWORD(FAR PASCAL *LPCLIPPERCALLBACK)(LPDIRECTDRAWCLIPPER lpDDClipper
#define DECOMP_SIZE_ASSERT(T, S)
Definition: decomp.h:19
unsigned int undefined4
Definition: decomp.h:28
#define DSBCAPS_CTRLVOLUME
Definition: dsound.h:808
#define DSBCAPS_CTRLPAN
Definition: dsound.h:807
#define DSBSTATUS_BUFFERLOST
Definition: dsound.h:762
#define DSBCAPS_STATIC
Definition: dsound.h:802
#define DSBCAPS_LOCSOFTWARE
Definition: dsound.h:804
#define DS_OK
Definition: dsound.h:690
#define DSBCAPS_CTRLFREQUENCY
Definition: dsound.h:806
#define DSBCAPS_CTRL3D
Definition: dsound.h:805
#define NULL
[AI] Null pointer value (C/C++ semantics).
Definition: legotypes.h:26
#define FAILURE
[AI] Used to indicate a failed operation in result codes.
Definition: legotypes.h:34
#define SUCCESS
[AI] Used to indicate a successful operation in result codes.
Definition: legotypes.h:30
LegoSoundManager * SoundManager()
[AI] Accessor for the game's LegoSoundManager subsystem from the global LegoOmni instance....
Definition: misc.cpp:22
MxU8 MxBool
[AI]
Definition: mxtypes.h:124
MxLong MxResult
[AI]
Definition: mxtypes.h:106
unsigned char MxU8
[AI]
Definition: mxtypes.h:8
signed int MxS32
[AI]
Definition: mxtypes.h:38
unsigned int MxU32
[AI]
Definition: mxtypes.h:32
DWORD dwSize
Definition: dsound.h:97
DWORD dwFlags
Definition: dsound.h:98
DWORD dwBufferBytes
Definition: dsound.h:99
LPWAVEFORMATEX lpwfxFormat
Definition: dsound.h:101