Isle
Loading...
Searching...
No Matches
mxwavepresenter.cpp
Go to the documentation of this file.
1#include "mxwavepresenter.h"
2
3#include "decomp.h"
4#include "define.h"
5#include "mxautolock.h"
6#include "mxdssound.h"
7#include "mxdssubscriber.h"
8#include "mxmisc.h"
9#include "mxomni.h"
10#include "mxsoundmanager.h"
11#include "mxutilities.h"
12
15
16// FUNCTION: LEGO1 0x100b1ad0
18{
21 m_chunkLength = 0;
22 m_lockSize = 0;
25 m_is3d = FALSE;
27}
28
29// FUNCTION: LEGO1 0x100b1af0
31{
33 Init();
34 return result;
35}
36
37// FUNCTION: LEGO1 0x100b1b10
38void MxWavePresenter::Destroy(MxBool p_fromDestructor)
39{
40 if (m_dsBuffer) {
41 m_dsBuffer->Stop();
42 m_dsBuffer->Release();
43 }
44
45 if (m_waveFormat) {
46 delete[] ((MxU8*) m_waveFormat);
47 }
48
49 Init();
50
51 if (!p_fromDestructor) {
53 }
54}
55
56// FUNCTION: LEGO1 0x100b1b60
58{
59 DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
60 MxS8 playedChunks = -1;
61
62 if (m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor) == DS_OK) {
63 playedChunks = dwCurrentPlayCursor / m_chunkLength;
64 }
65
66 return playedChunks;
67}
68
69// FUNCTION: LEGO1 0x100b1ba0
71{
73}
74
75// FUNCTION: LEGO1 0x100b1bd0
76void MxWavePresenter::WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length)
77{
78 DWORD dwStatus;
79 LPVOID pvAudioPtr1;
80 DWORD dwOffset;
81 LPVOID pvAudioPtr2;
82 DWORD dwAudioBytes1;
83 DWORD dwAudioBytes2;
84
85 dwOffset = m_chunkLength * m_writtenChunks;
86 m_dsBuffer->GetStatus(&dwStatus);
87
88 if (dwStatus == DSBSTATUS_BUFFERLOST) {
89 m_dsBuffer->Restore();
90 m_dsBuffer->GetStatus(&dwStatus);
91 }
92
93 if (dwStatus != DSBSTATUS_BUFFERLOST) {
96 m_lockSize = p_length;
97 }
98 else {
101 }
102
103 if (m_dsBuffer->Lock(dwOffset, m_lockSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) ==
104 DS_OK) {
105 memcpy(pvAudioPtr1, p_audioPtr, p_length);
106
107 if (m_lockSize > p_length && !(m_action->GetFlags() & MxDSAction::c_looping)) {
108 memset((MxU8*) pvAudioPtr1 + p_length, m_silenceData, m_lockSize - p_length);
109 }
110
111 m_dsBuffer->Unlock(pvAudioPtr1, m_lockSize, pvAudioPtr2, 0);
112 }
113 }
114}
115
116// FUNCTION: LEGO1 0x100b1cf0
118{
119 MxStreamChunk* chunk = NextChunk();
120
121 if (chunk) {
122 m_waveFormat = (WaveFormat*) new MxU8[chunk->GetLength()];
123 memcpy(m_waveFormat, chunk->GetData(), chunk->GetLength());
125 ParseExtra();
127 }
128}
129
130// FUNCTION: LEGO1 0x100b1d50
132{
133 MxStreamChunk* chunk = CurrentChunk();
134
135 if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) {
136 MxU32 length = chunk->GetLength();
137 WAVEFORMATEX waveFormatEx;
138
139 m_chunkLength = length;
140 memset(&waveFormatEx, 0, sizeof(waveFormatEx));
141
142 waveFormatEx.wFormatTag = m_waveFormat->m_pcmWaveFormat.wf.wFormatTag;
143 waveFormatEx.nChannels = m_waveFormat->m_pcmWaveFormat.wf.nChannels;
144 waveFormatEx.nSamplesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nSamplesPerSec;
145 waveFormatEx.nAvgBytesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec;
146 waveFormatEx.nBlockAlign = m_waveFormat->m_pcmWaveFormat.wf.nBlockAlign;
147 waveFormatEx.wBitsPerSample = m_waveFormat->m_pcmWaveFormat.wBitsPerSample;
148
149 if (waveFormatEx.wBitsPerSample == 8) {
150 m_silenceData = 0x7F;
151 }
152
153 if (waveFormatEx.wBitsPerSample == 16) {
154 m_silenceData = 0;
155 }
156
157 DSBUFFERDESC desc;
158 memset(&desc, 0, sizeof(desc));
159 desc.dwSize = sizeof(desc);
160
161 if (m_is3d) {
163 }
164 else {
166 }
167
169 desc.dwBufferBytes = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec *
170 (m_action->GetDuration() / m_action->GetLoopCount()) / 1000;
171 }
172 else {
173 desc.dwBufferBytes = 2 * length;
174 }
175
176 desc.lpwfxFormat = &waveFormatEx;
177
178 if (MSoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) {
179 EndAction();
180 }
181 else {
184 }
185 }
186}
187
188// FUNCTION: LEGO1 0x100b1ea0
190{
191 if (!m_currentChunk) {
193 MxStreamChunk* chunk = CurrentChunk();
194
195 if (chunk && chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM &&
196 !(chunk->GetChunkFlags() & DS_CHUNK_BIT16)) {
197 chunk->SetChunkFlags(chunk->GetChunkFlags() | DS_CHUNK_BIT16);
198
200 MxU8* data = new MxU8[m_chunkLength];
201
202 memset(data, m_silenceData, m_chunkLength);
203
205 m_currentChunk->SetData(data);
206 m_currentChunk->SetTime(chunk->GetTime() + 1000);
208 }
209 }
210
212 }
213}
214
215// FUNCTION: LEGO1 0x100b20c0
217{
218 if (m_dsBuffer) {
219 DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
220 m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor);
221
222 MxS8 playedChunks = dwCurrentPlayCursor / m_chunkLength;
225 (m_writtenChunks != playedChunks || m_lockSize + (m_chunkLength * playedChunks) <= dwCurrentPlayCursor))) {
227 }
228 }
229 else {
231 }
232}
233
234// FUNCTION: LEGO1 0x100b2130
236{
237 WriteToSoundBuffer(p_chunk->GetData(), p_chunk->GetLength());
238 if (IsEnabled()) {
239 m_subscriber->FreeDataChunk(p_chunk);
240 }
241}
242
243// FUNCTION: LEGO1 0x100b2160
245{
247
248 if (IsEnabled()) {
249 switch (m_currentTickleState) {
250 case e_streaming:
251 if (m_currentChunk && FUN_100b1ba0()) {
255 }
256
257 if (!m_started) {
258 m_dsBuffer->SetCurrentPosition(0);
259
260 if (m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING) == DS_OK) {
261 m_started = TRUE;
262 }
263 }
264 break;
265 case e_repeating:
266 if (m_started) {
267 break;
268 }
269
270 m_dsBuffer->SetCurrentPosition(0);
271
272 if (m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1) == DS_OK) {
273 m_started = TRUE;
274 }
275 }
276 }
277
278 return SUCCESS;
279}
280
281// FUNCTION: LEGO1 0x100b2280
283{
284 if (m_action) {
287
288 if (m_dsBuffer) {
289 m_dsBuffer->Stop();
290 }
291 }
292}
293
294// FUNCTION: LEGO1 0x100b2300
296{
298
299 m_volume = p_volume;
300 if (m_dsBuffer != NULL) {
301 MxS32 volume = p_volume * MxOmni::GetInstance()->GetSoundManager()->GetVolume() / 100;
302 MxS32 attenuation = MxOmni::GetInstance()->GetSoundManager()->GetAttenuation(volume);
303 m_dsBuffer->SetVolume(attenuation);
304 }
305
307}
308
309// FUNCTION: LEGO1 0x100b2360
311{
312 if (IsEnabled() != p_enable) {
313 MxSoundPresenter::Enable(p_enable);
314
315 if (p_enable) {
316 m_writtenChunks = 0;
318 }
319 else if (m_dsBuffer) {
320 m_dsBuffer->Stop();
321 }
322 }
323}
324
325// FUNCTION: LEGO1 0x100b23a0
327{
329
330 MxU16 extraLength;
331 char* extraData;
332 m_action->GetExtra(extraLength, extraData);
333
334 if (extraLength) {
335 char extraCopy[512];
336 memcpy(extraCopy, extraData, extraLength);
337 extraCopy[extraLength] = '\0';
338
339 char soundValue[512];
340 if (KeyValueStringParse(soundValue, g_strSOUND, extraCopy)) {
341 if (!strcmpi(soundValue, "FALSE")) {
342 Enable(FALSE);
343 }
344 }
345 }
346}
347
348// FUNCTION: LEGO1 0x100b2440
350{
351 if (!m_paused && m_started) {
352 if (m_dsBuffer) {
353 m_dsBuffer->Stop();
354 }
355 m_paused = TRUE;
356 }
357}
358
359// FUNCTION: LEGO1 0x100b2470
361{
362 if (m_paused) {
363 if (m_dsBuffer && m_started) {
364 switch (m_currentTickleState) {
365 case e_streaming:
366 m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
367 break;
368 case e_repeating:
369 m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1);
370 break;
371 case e_done:
372 m_dsBuffer->Play(0, 0, 0);
373 }
374 }
375
376 m_paused = FALSE;
377 }
378}
virtual MxS32 GetVolume()
[AI] Gets the current global audio volume.
virtual MxS32 GetVolume()
[AI] Returns the current runtime audio volume for this presenter (0-100).
MxS32 m_volume
[AI] Current playback volume, range 0-100 (percent).
void Enter()
[AI] Acquires/gains entry to the critical section or mutex, blocking if not available.
void Leave()
[AI] Releases/leaves the critical section or mutex.
MxU32 GetFlags()
[AI] Returns the flag field for this action (bitmask).
Definition: mxdsaction.h:177
void GetExtra(MxU16 &p_extraLength, char *&p_extraData)
[AI] Retrieves the extra data and its length for this action.
Definition: mxdsaction.h:168
MxS32 GetLoopCount()
[AI] Returns the loop count for this action.
Definition: mxdsaction.h:203
virtual MxLong GetDuration()
[AI] Gets the duration for which this action is intended to run.
Definition: mxdsaction.cpp:39
virtual MxLong GetElapsedTime()
[AI] Gets elapsed time for this action since the last time field 0x90 was set.
Definition: mxdsaction.cpp:159
@ c_looping
[AI] Action or media should repeat in a loop [AI]
Definition: mxdsaction.h:21
@ c_bit7
[AI] Unknown - possibly reserved [AI]
Definition: mxdsaction.h:26
MxU32 GetLength()
[AI] Returns the length in bytes of the data payload. [AI]
Definition: mxdschunk.h:105
MxLong GetTime()
[AI] Returns the time (timestamp or tick) associated with this chunk. [AI]
Definition: mxdschunk.h:102
void SetData(MxU8 *p_data)
[AI] Sets the pointer to the raw payload data (may or may not be owned by chunk object).
Definition: mxdschunk.h:93
MxU8 * GetData()
[AI] Returns a pointer to the start of the data payload. [AI]
Definition: mxdschunk.h:108
void SetChunkFlags(MxU16 p_flags)
[AI] Sets all chunk header flag bits.
Definition: mxdschunk.h:77
MxU16 GetChunkFlags()
[AI] Returns the chunk's flag bitfield. [AI]
Definition: mxdschunk.h:96
void SetLength(MxU32 p_length)
[AI] Sets the payload data length for this chunk.
Definition: mxdschunk.h:89
void SetTime(MxLong p_time)
[AI] Sets the time (timestamp/tick/frame) associated with this chunk.
Definition: mxdschunk.h:85
[AI] Represents a sound action extracted from an SI script and used in the data-driven action system.
Definition: mxdssound.h:14
void FreeDataChunk(MxStreamChunk *p_chunk)
[AI] Frees (deletes) a data chunk if it's found in the consumed data list; also forcibly deletes sing...
MxStreamChunk * CurrentChunk()
[AI] Returns a pointer to the current data chunk at the head of the stream, without consuming it.
MxStreamChunk * NextChunk()
[AI] Returns the next data chunk in the stream, removing it from the stream queue.
void EndAction() override
[AI] Ends the media playback action, releasing all resources, notifying listeners if necessary.
void Enable(MxBool p_enable) override
[AI] Enables or disables media stream playback and transitions state as needed.
void DoneTickle() override
[AI] Per-frame update for the "done" state; transitions this presenter to idle and ends the action.
void StreamingTickle() override
[AI] Per-frame update when streaming the media stream.
MxDSSubscriber * m_subscriber
[AI] Subscriber that provides the stream data (e.g., audio/video chunks) for this presenter.
MxStreamChunk * m_currentChunk
[AI] Currently active data chunk for playback or processing.
static MxOmni * GetInstance()
[AI] Returns the singleton instance of the MxOmni subsystem coordinator.
Definition: mxomni.cpp:289
MxSoundManager * GetSoundManager() const
[AI] Gets the engine's sound manager used for playing/controlling sounds.
Definition: mxomni.h:228
virtual void ParseExtra()
[AI] Parses additional data from the associated action for configuration or world interaction.
Definition: mxpresenter.cpp:80
void ProgressTickleState(TickleState p_tickleState)
[AI] Helper for advancing the presenter's tickle state and updating transition history.
Definition: mxpresenter.h:72
MxBool IsEnabled()
[AI] Returns whether this presenter is logically enabled (based on the associated action's flags).
MxDSAction * m_action
[AI] The associated action currently being presented by this presenter.
Definition: mxpresenter.h:211
TickleState m_currentTickleState
[AI] Current state in the tickle lifecycle.
Definition: mxpresenter.h:199
@ e_repeating
[AI] Presentation is repeating (e.g., looping media).
Definition: mxpresenter.h:28
@ e_done
[AI] Completed processing the current action.
Definition: mxpresenter.h:30
@ e_starting
[AI] In the process of starting playback/presentation.
Definition: mxpresenter.h:26
@ e_streaming
[AI] Streaming or rendering actively.
Definition: mxpresenter.h:27
MxCriticalSection m_criticalSection
[AI] Thread synchronization for presenter state and data.
Definition: mxpresenter.h:214
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.
void Destroy() override
[AI] Public destroy method called by the engine to clean up the presenter.
MxResult AddToManager() override
[AI] Registers this presenter with the global MxSoundManager.
[AI] Represents a streamable chunk of data, typically sourced from a media buffer and designed for no...
Definition: mxstreamchunk.h:19
[AI] Presenter for streaming and managing PCM waveform audio via DirectSound buffer.
MxResult AddToManager() override
[AI] Registers this presenter with the global MxSoundManager.
virtual void Pause()
[AI] Pauses audio playback, halting sound buffer while keeping position for resume.
void Enable(MxBool p_enable) override
[AI] Enables or disables media stream playback and transitions state as needed.
MxU32 m_lockSize
[AI] Size in bytes for current buffer lock/write operation.
void ParseExtra() override
[AI] Parses additional data from the associated action for configuration or world interaction.
MxU8 m_writtenChunks
[AI] Number of chunks written into the DirectSound buffer.
MxS8 GetPlayedChunks()
[AI] Returns the index of the currently played chunk in the sound buffer.
void StartingTickle() override
[AI] Handles actions required when first starting presentation. Advances to streaming state.
void LoopChunk(MxStreamChunk *p_chunk) override
[AI] Adds a chunk to the looping chunk list, making it available for repeated playback.
void ReadyTickle() override
[AI] Handles the transition and setup for the Ready state. Parses extra action data and advances stat...
LPDIRECTSOUNDBUFFER m_dsBuffer
[AI] DirectSound buffer handling PCM sample playback.
void EndAction() override
[AI] Ends the media playback action, releasing all resources, notifying listeners if necessary.
void Destroy() override
[AI] Explicit resource release.
MxS8 m_silenceData
[AI] Value written as silence into buffer when needed (format-dependent, e.g., 0 or 0x7F).
void StreamingTickle() override
[AI] Per-frame update when streaming the media stream.
virtual void Resume()
[AI] Resumes audio playback after a pause, restarting sound from the current buffer position.
void SetVolume(MxS32 p_volume) override
[AI] Sets the presentation volume for playback (0-100).
void DoneTickle() override
[AI] Per-frame update for the "done" state; transitions this presenter to idle and ends the action.
void Init()
[AI] Initializes all member variables to safe/empty values.
MxBool FUN_100b1ba0()
[AI] Checks if more chunks can or should be streamed into buffer.
MxBool m_started
[AI] TRUE if audio playback has started on the buffer.
MxBool m_is3d
[AI] TRUE if buffer/audio is 3D spatialized.
MxResult PutData() override
[AI] Allows the presenter to submit pending results or output to the engine.
MxBool m_paused
[AI] TRUE if playback is currently paused.
MxU32 m_chunkLength
[AI] Size in bytes for one audio streaming chunk.
void WriteToSoundBuffer(void *p_audioPtr, MxU32 p_length)
[AI] Writes a block of audio data to the DirectSound buffer at the correct chunk offset.
WaveFormat * m_waveFormat
[AI] Pointer to the wave format struct for buffer description/allocation.
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
const char * g_strSOUND
[AI] Symbolic string used to reference sound effects or sound object properties in the scripting syst...
Definition: define.cpp:93
#define DSBCAPS_CTRLVOLUME
Definition: dsound.h:808
#define DSBCAPS_CTRLPAN
Definition: dsound.h:807
#define DSBSTATUS_BUFFERLOST
Definition: dsound.h:762
#define DS_OK
Definition: dsound.h:690
#define DSBCAPS_CTRLFREQUENCY
Definition: dsound.h:806
#define DSBCAPS_CTRL3D
Definition: dsound.h:805
#define DSBPLAY_LOOPING
Definition: dsound.h:759
#define NULL
[AI] Null pointer value (C/C++ semantics).
Definition: legotypes.h:26
#define SUCCESS
[AI] Used to indicate a successful operation in result codes.
Definition: legotypes.h:30
#define AUTOLOCK(CS)
[AI] Macro for automatic locking using the MxAutoLock class. This macro instantiates an MxAutoLock ob...
Definition: mxautolock.h:5
#define DS_CHUNK_END_OF_STREAM
[AI] Flag bit indicating this chunk is the last in its stream.
Definition: mxdschunk.h:14
#define DS_CHUNK_BIT1
[AI] Flag bit indicating that the data should be released (freed) when the chunk is destroyed.
Definition: mxdschunk.h:10
#define DS_CHUNK_BIT16
[AI] Unspecified bit flag that may be used for platform- or feature- specific logic.
Definition: mxdschunk.h:26
MxSoundManager * MSoundManager()
[AI] Returns the global sound manager responsible for sound FX/voice playback.
Definition: mxmisc.cpp:57
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 short MxU16
[AI]
Definition: mxtypes.h:20
unsigned int MxU32
[AI]
Definition: mxtypes.h:32
signed char MxS8
[AI]
Definition: mxtypes.h:14
MxBool KeyValueStringParse(char *, const char *, const char *)
Searches p_string for a key command and copies its associated value to p_output.
Definition: mxutilities.cpp:85
[AI] Holds WAVE PCM format info for DirectSound buffer creation and streaming.
PCMWAVEFORMAT m_pcmWaveFormat
[AI] PCM format struct containing standard Windows WAVE format fields.
DWORD dwSize
Definition: dsound.h:97
DWORD dwFlags
Definition: dsound.h:98
DWORD dwBufferBytes
Definition: dsound.h:99
LPWAVEFORMATEX lpwfxFormat
Definition: dsound.h:101