TONY: Implement more of the music related code from the original

This commit is contained in:
Paul Gilbert 2012-06-19 20:50:48 +10:00
parent 0aa3d39cf7
commit 61d460a854
6 changed files with 673 additions and 286 deletions

View file

@ -2198,14 +2198,14 @@ DECLARE_CUSTOM_FUNCTION(DemuteJingle)(CORO_PARAM, uint32, uint32, uint32, uint32
void CustPlayMusic(uint32 nChannel, const char *mFN, uint32 nFX, bool bLoop, int nSync = 0) {
if (nSync == 0)
nSync = 2000;
debug("Start CustPlayMusic");
debugC(DEBUG_INTERMEDIATE, kTonyDebugMusic, "Start CustPlayMusic");
GLOBALS.PlayMusic(nChannel, mFN, nFX, bLoop, nSync);
debug("End CustPlayMusic");
debugC(DEBUG_INTERMEDIATE, kTonyDebugMusic, "End CustPlayMusic");
}
DECLARE_CUSTOM_FUNCTION(PlaySoundEffect)(CORO_PARAM, uint32 nMusic, uint32 nFX, uint32 bNoLoop, uint32) {
if (nFX == 0 || nFX == 1 || nFX == 2) {
debug("PlaySoundEffect stop fadeout");
debugC(DEBUG_INTERMEDIATE, kTonyDebugSound, "PlaySoundEffect stop fadeout");
GLOBALS._bFadeOutStop = true;
}

View file

@ -473,8 +473,6 @@ void RMGfxEngine::init() {
delete load;
// Display 'Loading' screen
// TODO: The loading screen isn't currently optimal, since the game doesn't respond to events
// whilst the mpalInit code is being executed.
_vm->_window.getNewFrame(*this, NULL);
_vm->_window.repaint();

View file

@ -39,11 +39,406 @@ namespace Tony {
#define RELEASE(x) {if ((x) != NULL) { (x)->release(); x = NULL; }}
/****************************************************************************\
*****************************************************************************
* class CODECRAW
* --------------
* Description: CODEC to play hard from pure samples
*****************************************************************************
\****************************************************************************/
class CODECRAW : public CODEC {
public:
CODECRAW(bool _bLoop = true);
virtual ~CODECRAW();
virtual uint32 decompress(Common::SeekableReadStream *stream, void *lpBuf, uint32 dwSize);
virtual void loopReset();
};
/****************************************************************************\
*****************************************************************************
* class CODECADPCM
* ----------------
* Description: Play ADPCM compressed data
*****************************************************************************
\****************************************************************************/
class CODECADPCM : public CODECRAW {
protected:
byte *lpTemp;
static const int indexTable[16];
static const int stepSizeTable[89];
public:
CODECADPCM(bool _bLoop = true, byte *lpTempBuffer = NULL);
virtual ~CODECADPCM();
virtual uint32 decompress(Common::SeekableReadStream *stream, void *lpBuf, uint32 dwSize) = 0;
virtual void loopReset() = 0;
};
class CODECADPCMSTEREO : public CODECADPCM {
protected:
int valpred[2], index[2];
public:
CODECADPCMSTEREO(bool _bLoop=true, byte *lpTempBuffer = NULL);
virtual ~CODECADPCMSTEREO();
virtual uint32 decompress(Common::SeekableReadStream *stream, void *lpBuf, uint32 dwSize);
virtual void loopReset();
};
class CODECADPCMMONO : public CODECADPCM {
protected:
int valpred, index;
public:
CODECADPCMMONO(bool _bLoop = true, byte *lpTempBuffer = NULL);
virtual ~CODECADPCMMONO();
virtual uint32 decompress(Common::SeekableReadStream *stream, void *lpBuf, uint32 dwSize);
virtual void loopReset();
};
/****************************************************************************\
* CODEC Methods
\****************************************************************************/
/**
* Standard cosntructor. It's possible to specify whether you want to
* enable or disable the loop (which by default, and 'active).
*
* @param loop True if you want to loop, false to disable
*/
CODEC::CODEC(bool loop) {
_bLoop = loop;
_bEndReached = false;
}
CODEC::~CODEC() {
}
/**
* Tell whether we have reached the end of the stream
*
* @return True if we're done, false otherwise.
*/
bool CODEC::endOfStream() {
return _bEndReached;
}
/****************************************************************************\
* CODECRAW Methods
\****************************************************************************/
/**
* Standard cosntructor. Simply calls the inherited constructor
*/
CODECRAW::CODECRAW(bool loop) : CODEC(loop) {
}
CODECRAW::~CODECRAW() {
}
/**
* Reset the stream to the beginning of the file. In the case of RAW files, does nothing
*/
void CODECRAW::loopReset() {
}
/**
* Manage the RAW format. Simply copies the file's stream buffer
*
* @return Indicates the position of the file for the end of the loop
*/
uint32 CODECRAW::decompress(Common::SeekableReadStream *stream, void *buf, uint32 dwSize) {
byte *lpBuf = (byte *)buf;
uint32 dwRead;
uint32 dwEOF;
_bEndReached = false;
dwEOF = 0;
dwRead = stream->read(lpBuf, dwSize);
if (dwRead < dwSize) {
dwEOF = dwRead;
_bEndReached = true;
if (!_bLoop) {
Common::fill(lpBuf + dwRead, lpBuf + dwRead + (dwSize - dwRead), 0);
} else {
stream->seek(0);
dwRead = stream->read(lpBuf + dwRead, dwSize - dwRead);
}
}
return dwEOF;
}
/****************************************************************************\
* CODECADPCM Methods
\****************************************************************************/
const int CODECADPCM::indexTable[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
const int CODECADPCM::stepSizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
#define MAXDECODESIZE (44100 * 2 * 2)
/**
* Standard constructor. Initialises and allocates temporary memory tables
*/
CODECADPCM::CODECADPCM(bool loop, byte *lpTempBuffer) : CODECRAW(loop) {
// Alloca la memoria temporanea
if (lpTempBuffer != NULL) {
lpTemp = lpTempBuffer;
} else {
lpTemp = (byte *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, MAXDECODESIZE);
if (lpTemp == NULL) {
error("Insufficient memory!");
return;
}
}
}
CODECADPCMMONO::CODECADPCMMONO(bool loop, byte *lpTempBuffer) : CODECADPCM(loop,lpTempBuffer) {
// Inizializza per il playing
loopReset();
}
CODECADPCMMONO::~CODECADPCMMONO() {
}
CODECADPCMSTEREO::CODECADPCMSTEREO(bool loop, byte *lpTempBuffer) : CODECADPCM(loop, lpTempBuffer) {
// Initialise for playing
loopReset();
}
CODECADPCMSTEREO::~CODECADPCMSTEREO() {
}
/**
* Destructor. Free the buffer
*/
CODECADPCM::~CODECADPCM() {
globalDestroy(lpTemp);
}
/**
* Reset the player before each play or loop
*/
void CODECADPCMSTEREO::loopReset() {
valpred[0] = 0;
valpred[1] = 0;
index[0] = 0;
index[1] = 0;
}
void CODECADPCMMONO::loopReset() {
valpred = 0;
index = 0;
}
/**
* Manages decompressing the ADPCM 16:4 format.
*/
uint32 CODECADPCMMONO::decompress(Common::SeekableReadStream *stream, void *buf, uint32 dwSize) {
uint16 *lpBuf = (uint16 *)buf;
byte *inp;
int bufferstep;
int cache;
int delta;
int sign;
int vpdiff;
uint32 eof, i;
int step;
bufferstep = 1;
step = stepSizeTable[index];
// Invokes the raw codec to read the stream from disk to loop.
eof = CODECRAW::decompress(stream, lpTemp, dwSize / 4);
inp = lpTemp;
eof *= 2;
// If you must do an immediate loop
if (endOfStream() && eof == 0) {
loopReset();
bufferstep = 1;
step = stepSizeTable[index];
} else if (!endOfStream())
eof = 0;
dwSize /= 2;
for (i = 0; i < dwSize; i++) {
// Check if we are at the end of the file, and are looping
if (eof != 0 && i == eof) {
loopReset();
bufferstep=1;
step = stepSizeTable[index];
}
// Read the delta (4 bits)
if (bufferstep) {
cache = *inp++;
delta = (cache >> 4) & 0xF;
} else
delta = cache & 0xF;
// Find the new index
index += indexTable[delta];
if (index < 0) index = 0;
if (index > 88) index = 88;
// Reads the sign and separates it
sign = delta & 8;
delta = delta & 7;
// Find the difference from the previous value
vpdiff = step >> 3;
if (delta & 4) vpdiff += step;
if (delta & 2) vpdiff += step >> 1;
if (delta & 1) vpdiff += step >> 2;
if (sign)
valpred -= vpdiff;
else
valpred += vpdiff;
// Check the limits of the found value
if (valpred > 32767)
valpred = 32767;
else if (valpred < -32768)
valpred = -32768;
// Update the step
step = stepSizeTable[index];
// Write the value found
*lpBuf++ = (uint16)valpred;
bufferstep = !bufferstep;
}
return eof / 2;
}
uint32 CODECADPCMSTEREO::decompress(Common::SeekableReadStream *stream, void *buf, uint32 dwSize) {
uint16 *lpBuf=(uint16 *)buf;
byte *inp;
int bufferstep;
int cache;
int delta;
int sign;
int vpdiff;
uint32 eof, i;
int step[2];
bufferstep = 1;
step[0] = stepSizeTable[index[0]];
step[1] = stepSizeTable[index[1]];
// Invokes the RAW codec to read the stream from disk.
eof = CODECRAW::decompress(stream, lpTemp, dwSize / 4);
inp = lpTemp;
eof *= 2;
// If you must do an immediate loop
if (endOfStream() && eof == 0) {
loopReset();
bufferstep = 1;
step[0] = stepSizeTable[index[0]];
step[1] = stepSizeTable[index[1]];
} else if (!endOfStream())
eof = 0;
dwSize /= 2;
for (i = 0;i < dwSize; i++) {
// If you must do an immediate loop
if (eof != 0 && i == eof) {
loopReset();
bufferstep = 1;
step[0] = stepSizeTable[index[0]];
step[1] = stepSizeTable[index[1]];
}
// Reads the delta (4 bits)
if (bufferstep) {
cache = *inp++;
delta = cache & 0xF;
} else
delta = (cache >> 4) & 0xF;
// Find the new index
index[bufferstep] += indexTable[delta];
if (index[bufferstep] < 0) index[bufferstep] = 0;
if (index[bufferstep] > 88) index[bufferstep] = 88;
// Reads the sign and separates it
sign = delta & 8;
delta = delta & 7;
// Find the difference from the previous value
vpdiff = step[bufferstep] >> 3;
if (delta & 4) vpdiff += step[bufferstep];
if (delta & 2) vpdiff += step[bufferstep] >> 1;
if (delta & 1) vpdiff += step[bufferstep] >> 2;
if (sign)
valpred[bufferstep] -= vpdiff;
else
valpred[bufferstep] += vpdiff;
// Check the limits of the value
if (valpred[bufferstep] > 32767)
valpred[bufferstep] = 32767;
else if (valpred[bufferstep] < -32768)
valpred[bufferstep] =- 32768;
// Update the step
step[bufferstep] = stepSizeTable[index[bufferstep]];
// Write the found value
*lpBuf++ = (uint16)valpred[bufferstep];
bufferstep = !bufferstep;
}
return eof / 2;
}
/****************************************************************************\
* FPSOUND Methods
\****************************************************************************/
/**
* Default constructor. Initializes the attributes.
*
*/
FPSound::FPSound() {
_bSoundSupported = false;
}
@ -53,7 +448,6 @@ FPSound::FPSound() {
*
* @returns True is everything is OK, False otherwise
*/
bool FPSound::init() {
_bSoundSupported = g_system->getMixer()->isReady();
return _bSoundSupported;
@ -308,7 +702,7 @@ bool FPSfx::stop() {
/**
* Enables or disables the Sfx loop.
*
* @param bLoop True to enable the loop, False to disable
* @param _bLoop True to enable the loop, False to disable
*
* @remarks The loop must be activated BEFORE the sfx starts
* playing. Any changes made during the play will have
@ -423,20 +817,19 @@ void FPSfx::soundCheckProcess(CORO_PARAM, const void *param) {
* @remarks Do *NOT* declare an object directly, but rather
* create it using FPSound::CreateStream()
*/
FPStream::FPStream(bool bSoundOn) {
#ifdef REFACTOR_ME
//hwnd=hWnd;
hwnd=hWnd;
lpDS = LPDS;
bSoundSupported = bSoundOn;
bFileLoaded = false;
bIsPlaying = false;
bPaused = false;
bSyncExit = false;
lpDSBuffer = NULL;
lpDSNotify = NULL;
hHot1 = hHot2 = hHot3 = hPlayThread_PlayFast = hPlayThread_PlayNormal = NULL;
_lpDSBuffer = NULL;
_lpDSNotify = NULL;
#endif
_bSoundSupported = bSoundOn;
_bFileLoaded = false;
_bIsPlaying = false;
_bPaused = false;
_bSyncExit = false;
_hHot1 = _hHot2 = _hHot3 = _hPlayThreadPlayFast = _hPlayThreadPlayNormal = CORO_INVALID_PID_VALUE;
}
bool FPStream::createBuffer(int nBufSize) {
@ -512,40 +905,38 @@ bool FPStream::createBuffer(int nBufSize) {
*/
FPStream::~FPStream() {
#ifdef REFACTOR_ME
if (!bSoundSupported)
if (!_bSoundSupported)
return;
if (bIsPlaying)
Stop();
if (_bIsPlaying)
stop();
if (bFileLoaded)
UnloadFile();
if (_bFileLoaded)
unloadFile();
if (hHot1) {
CloseHandle(hHot1);
hHot1 = NULL;
if (_hHot1) {
CoroScheduler.closeEvent(_hHot1);
_hHot1 = CORO_INVALID_PID_VALUE;
}
if (hHot2) {
CloseHandle(hHot2);
hHot2 = NULL;
if (_hHot2) {
CoroScheduler.closeEvent(_hHot2);
_hHot2 = CORO_INVALID_PID_VALUE;
}
if (hHot3) {
CloseHandle(hHot3);
hHot3 = NULL;
if (_hHot3) {
CoroScheduler.closeEvent(_hHot3);
_hHot3 = CORO_INVALID_PID_VALUE;
}
if (hPlayThread_PlayFast) {
CloseHandle(hPlayThread_PlayFast);
hPlayThread_PlayFast = NULL;
if (_hPlayThreadPlayFast != CORO_INVALID_PID_VALUE) {
CoroScheduler.closeEvent(_hPlayThreadPlayFast);
_hPlayThreadPlayFast = CORO_INVALID_PID_VALUE;
}
if (hPlayThread_PlayNormal) {
CloseHandle(hPlayThread_PlayNormal);
hPlayThread_PlayNormal = NULL;
if (_hPlayThreadPlayNormal != CORO_INVALID_PID_VALUE) {
CoroScheduler.closeEvent(_hPlayThreadPlayNormal);
_hPlayThreadPlayNormal = CORO_INVALID_PID_VALUE;
}
SyncToPlay = NULL;
_syncToPlay = NULL;
#ifdef REFACTOR_ME
RELEASE(lpDSNotify);
RELEASE(lpDSBuffer);
#endif
@ -559,7 +950,6 @@ FPStream::~FPStream() {
* FPSound::CreateStream().
* Object pointers are no longer valid after this call.
*/
void FPStream::release() {
delete this;
}
@ -567,44 +957,35 @@ void FPStream::release() {
/**
* Opens a file stream
*
* @param lpszFile Filename to be opened
* @param fileName Filename to be opened
* @param dwCodec CODEC to be used to uncompress samples
*
* @returns True is everything is OK, False otherwise
*/
bool FPStream::loadFile(const char *lpszFileName, uint32 dwCodType, int nBufSize) {
#ifdef REFACTOR_ME
HRESULT err;
void *lpBuf;
uint32 dwHi;
if (!bSoundSupported)
bool FPStream::loadFile(const Common::String &fileName, uint32 dwCodType, int nBufSize) {
if (!_bSoundSupported)
return true;
/* Si salva il tipo di codec */
dwCodec = dwCodType;
// Save the codec type
_dwCodec = dwCodType;
/* Crea il buffer */
if (!CreateBuffer(nBufSize))
// Create the buffer
if (!createBuffer(nBufSize))
return true;
/* Apre il file di stream in lettura */
if (!_file.open(lpszFileName))
//MessageBox(hwnd,"Cannot open stream file!","FPStream::LoadFile()", MB_OK);
// Open the file stream for reading
if (!_file.open(fileName))
return false;
}
/* Si salva la lunghezza dello stream */
dwSize = _file.size();
_file.seek(0);
// Save the size of the stream
_dwSize = _file.size();
/* Tutto a posto, possiamo uscire */
bFileLoaded = true;
bIsPlaying = false;
bPaused = false;
#endif
return true;
// All done
_bFileLoaded = true;
_bIsPlaying = false;
_bPaused = false;
return true;
}
/**
@ -616,85 +997,80 @@ return true;
* @remarks It is necessary to call this function to free the
* memory used by the stream.
*/
bool FPStream::unloadFile() {
#ifdef REFACTOR_ME
if (!bSoundSupported || !bFileLoaded)
if (!_bSoundSupported || !_bFileLoaded)
return true;
/* Closes the file handle stream */
_file.close();
#ifdef REFACTOR_ME
RELEASE(lpDSNotify);
RELEASE(lpDSBuffer);
/* Remember no more file is loaded in memory */
bFileLoaded = false;
#endif
// Flag that the file is no longer in memory
_bFileLoaded = false;
return true;
}
void FPStream::prefetch() {
#ifdef REFACTOR_ME
uint32 dwId;
void *lpBuf;
uint32 dwHi;
HRESULT err;
if (!bSoundSupported || !bFileLoaded)
if (!_bSoundSupported || !_bFileLoaded)
return;
/* Allocates a temporary buffer */
lpTempBuffer = (byte *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, dwBufferSize / 2);
if (lpTempBuffer == NULL)
// Allocates a temporary buffer
_lpTempBuffer = (byte *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, _dwBufferSize / 2);
if (_lpTempBuffer == NULL)
return;
switch (dwCodec) {
case FPCODEC_RAW:
lpCodec = new CODECRAW(bLoop);
break;
case FPCODEC_ADPCM:
lpCodec = new CODECADPCMSTEREO(bLoop);
break;
default:
if (_dwCodec == FPCODEC_RAW) {
_codec = new CODECRAW(_bLoop);
} else if (_dwCodec == FPCODEC_ADPCM) {
_codec = new CODECADPCMSTEREO(_bLoop);
} else {
return;
}
/* reset the file position */
// reset the file position
_file.seek(0);
/* Fills the buffer for the data already ready */
#ifdef REFACTOR_ME
// Fills the buffer for the data already ready
if ((err = lpDSBuffer->Lock(0, dwBufferSize / 2, &lpBuf, (uint32 *)&dwHi, NULL, NULL, 0)) != DS_OK) {
MessageBox(hwnd, "Cannot lock stream buffer!", "soundLoadStream()", MB_OK);
_vm->GUIError("Cannot lock stream buffer!", "soundLoadStream()");
return;
}
#endif
/* Uncompress the data from the stream directly into the locked buffer */
lpCodec->Decompress(hFile, lpBuf, dwBufferSize / 2);
// Uncompress the data from the stream directly into the locked buffer
_codec->decompress(_file.readStream(_file.size()), lpBuf, _dwBufferSize / 2);
/* Unlock the buffer */
lpDSBuffer->Unlock(lpBuf, dwBufferSize / 2, NULL, NULL);
// Unlock the buffer
#ifdef REFACTOR_ME
lpDSBuffer->unlock(lpBuf, _dwBufferSize / 2, NULL, NULL);
#endif
/* Create a thread to play the stream */
hThreadEnd = CreateEvent(NULL, false, false, NULL);
hPlayThread = CreateThread(NULL, 10240, (LPTHREAD_START_ROUTINE)PlayThread, (void *)this, 0, &dwId);
SetThreadPriority(hPlayThread, THREAD_PRIORITY_HIGHEST);
// Create a thread to play the stream
_hThreadEnd = CoroScheduler.createEvent(false, false);
_hPlayThread = CoroScheduler.createProcess(playThread, this, sizeof(FPStream *));
/* Start to play the buffer */
lpDSBuffer->SetCurrentPosition(0);
bIsPlaying = true;
// Start to play the buffer
#ifdef REFACTOR_ME
lpDSBuffer->setCurrentPosition(0);
#endif
_bIsPlaying = true;
dspnHot[0].dwOffset = 32;
dspnHot[0].hEventNotify = hHot1;
#ifdef REFACTOR_ME
_dspnHot[0].dwOffset = 32;
_dspnHot[0].hEventNotify = _hHot1;
dspnHot[1].dwOffset = dwBufferSize / 2 + 32;
dspnHot[1].hEventNotify = hHot2;
_dspnHot[1].dwOffset = dwBufferSize / 2 + 32;
_dspnHot[1].hEventNotify = _hHot2;
dspnHot[2].dwOffset = dwBufferSize - 32; //DSBPN_OFFSETSTOP;
dspnHot[2].hEventNotify = hHot3;
_dspnHot[2].dwOffset = dwBufferSize - 32; //DSBPN_OFFSETSTOP;
_dspnHot[2].hEventNotify = _hHot3;
if (FAILED(lpDSNotify->SetNotificationPositions(3, dspnHot))) {
int a = 1;
@ -748,11 +1124,11 @@ bool FPStream::play() {
switch (dwCodec) {
case FPCODEC_RAW:
lpCodec = new CODECRAW(bLoop);
_codec = new CODECRAW(_bLoop);
break;
case FPCODEC_ADPCM:
lpCodec = new CODECADPCMSTEREO(bLoop);
_codec = new CODECADPCMSTEREO(_bLoop);
break;
default:
@ -770,7 +1146,7 @@ bool FPStream::play() {
}
/* Uncompress the data from the stream directly into the locked buffer */
lpCodec->Decompress(hFile, lpBuf, dwBufferSize / 2);
_codec->Decompress(hFile, lpBuf, dwBufferSize / 2);
/* Unlock the buffer */
lpDSBuffer->Unlock(lpBuf, dwBufferSize / 2, NULL, NULL);
@ -846,7 +1222,7 @@ bool FPStream::stop(bool bSync) {
GlobalFree(lpTempBuffer);
/* Close and free the CODEC */
delete lpCodec;
delete _codec;
bIsPlaying = false;
bPaused = false;
@ -882,7 +1258,7 @@ void FPStream::waitForSync(FPStream *toplay) {
GlobalFree(lpTempBuffer);
/* Close and free the CODEC */
delete lpCodec;
delete _codec;
#endif
_bIsPlaying = false;
}
@ -892,129 +1268,110 @@ void FPStream::waitForSync(FPStream *toplay) {
*
*/
void FPStream::playThread(FPStream *This) {
#ifdef REFACTOR_ME
void FPStream::playThread(CORO_PARAM, const void *param) {
CORO_BEGIN_CONTEXT;
byte *lpLockBuf;
uint32 dwResult;
byte *lpLockBuf2;
uint32 dwResult2;
bool cicla = true;
bool cicla;
uint32 countEnd;
bool bPrecache;
char buf[1024];
uint32 hList[5];
CORO_END_CONTEXT(_ctx);
/* Events that signal when you need to do something */
HANDLE hList[5] = { This->hThreadEnd, This->hHot1, This->hHot2, This->hHot3, This->hPlayThread_PlayFast };
// FPStream *This = *(FPStream **)param;
bPrecache = true;
countEnd = 0;
while (cicla) {
if (This->lpCodec->EndOfStream() && This->lpCodec->bLoop == false) {
countEnd++;
if (countEnd == 3)
CORO_BEGIN_CODE(_ctx);
#ifdef REFACTOR_ME
// Events that signal when you need to do something
_ctx->hList[0] = This->_hThreadEnd;
_ctx->hList[1] = This->_hHot1;
_ctx->hList[2] = This->_hHot2;
_ctx->hList[3] = This->_hHot3;
_ctx->hList[4] = This->_hPlayThreadPlayFast;
_ctx->cicla = true;
_ctx->bPrecache = true;
_ctx->countEnd = 0;
while (_ctx->cicla) {
if (This->_codec->endOfStream() && This->_codec->_bLoop == false) {
_ctx->countEnd++;
if (_ctx->countEnd == 3)
break;
}
/* Uncompresses the data being written into the temporary buffer */
if (This->lastVolume == 0)
ZeroMemory(This->lpTempBuffer, This->dwBufferSize / 2);
else if (bPrecache)
This->lpCodec->Decompress(This->_file, This->lpTempBuffer, This->dwBufferSize / 2);
// Uncompresses the data being written into the temporary buffer
if (This->_lastVolume == 0)
ZeroMemory(This->_lpTempBuffer, This->_dwBufferSize / 2);
else if (_ctx->bPrecache)
This->_codec->decompress(This->_file.readStream(This->_file.size()), This->_lpTempBuffer, This->_dwBufferSize / 2);
bPrecache = false;
_ctx->bPrecache = false;
/* Waits for an event. Since they are all in automatic reset, there is no need to reset it after */
// Waits for an event. Since they are all in automatic reset, there is no need to reset it after
// uint32 dwBufStatus;
// This->lpDSBuffer->GetStatus(&dwBufStatus);
uint32 dwBufStatus;
CORO_INVOKE_4(CoroScheduler.waitForMultipleObjects, 5, _ctx->hList, false, CORO_INFINITE, &_ctx->dwResult);
// sprintf(buf, "WFMO: %x (buf status: %x) MyThread: 0x%x\n", This->lpDSBuffer, dwBufStatus, GetCurrentThreadId());
// warning(buf);
dwResult = WaitForMultipleObjects(5, hList, false, CORO_INFINITE);
/* uint32 dwPlay, dwWrite;
This->lpDSBuffer->GetCurrentPosition(&dwPlay, &dwWrite);
sprintf(buf, "CP Play: %u, Write: %u\n", dwPlay, dwWrite);
warning(buf); */
/* Make a switch to determine which event has been set */
switch (dwResult - WAIT_OBJECT_0) {
case 0:
// Check to determine which event has been set
if (CoroScheduler.getEvent(This->_hThreadEnd)->signalled) {
/* Must leave the thread */
cicla = false;
break;
_ctx->cicla = false;
case 1:
/* Must fill the second half of the buffer */
// if (dwPlay >= This->dspnHot[0].dwOffset && dwPlay <= This->dspnHot[0].dwOffset+1024 )
{
// sprintf(buf, "Prima metà buffer: %x\n", This->lpDSBuffer);
// warning(buf);
This->lpDSBuffer->Lock(This->dwBufferSize / 2, This->dwBufferSize / 2, (void **)&lpLockBuf, &dwResult, (void **)&lpLockBuf2, &dwResult2, 0);
// sprintf(buf, "LockedBuf: dwResult=%x, dwBufferSize/2=%x, lpLockBuf2=%x, dwResult2=%x\n", dwResult, This->dwBufferSize/2, lpLockBuf2, dwResult2);
// warning(buf);
copyMemory(lpLockBuf, This->lpTempBuffer, This->dwBufferSize / 2);
This->lpDSBuffer->Unlock(lpLockBuf, This->dwBufferSize / 2, lpLockBuf2, 0);
bPrecache = true;
}
break;
} else if (CoroScheduler.getEvent(This->_hHot1)->signalled) {
// Must fill the second half of the buffer
This->lpDSBuffer->Lock(This->_dwBufferSize / 2, This->_dwBufferSize / 2, (void **)&_ctx->lpLockBuf, &_ctx->dwResult, (void **)&_ctx->lpLockBuf2, &_ctx->dwResult2, 0);
case 2:
/* Must fill the first half of the buffer */
// if (dwPlay >= This->dspnHot[1].dwOffset && dwPlay <= This->dspnHot[1].dwOffset+1024 )
{
// sprintf(buf, "Seconda metà buffer: %x\n", This->lpDSBuffer);
// warning(buf);
This->lpDSBuffer->Lock(0, This->dwBufferSize / 2, (void **)&lpLockBuf, &dwResult, NULL, NULL, 0);
copyMemory(lpLockBuf, This->lpTempBuffer, This->dwBufferSize / 2);
This->lpDSBuffer->Unlock(lpLockBuf, This->dwBufferSize / 2, NULL, NULL);
bPrecache = true;
}
break;
copyMemory(_ctx->lpLockBuf, This->_lpTempBuffer, This->_dwBufferSize / 2);
This->lpDSBuffer->Unlock(_ctx->lpLockBuf, This->_dwBufferSize / 2, _ctx->lpLockBuf2, 0);
_ctx->bPrecache = true;
} else if (CoroScheduler.getEvent(This->_hHot2)->signalled) {
This->lpDSBuffer->Lock(0, This->_dwBufferSize / 2, (void **)&_ctx->lpLockBuf, &_ctx->dwResult, NULL, NULL, 0);
copyMemory(_ctx->lpLockBuf, This->_lpTempBuffer, This->_dwBufferSize / 2);
This->lpDSBuffer->Unlock(_ctx->lpLockBuf, This->_dwBufferSize / 2, NULL, NULL);
_ctx->bPrecache = true;
} else if (CoroScheduler.getEvent(This->_hHot3)->signalled) {
if (This->_bSyncExit) {
CoroScheduler.setEvent(This->_syncToPlay->_hPlayThreadPlayFast);
case 3: {
// sprintf(buf, "End of buffer %x (SyncToPlay [%x]=%x, SyncExit: [%x]=%d)\n", This->lpDSBuffer, &This->SyncToPlay, This->SyncToPlay, &This->bSyncExit, This->bSyncExit);
// warning(buf);
if (This->bSyncExit) {
// sprintf(buf, "Go with sync (Buffer: %x) MyThread: %x!\n", This->SyncToPlay->lpDSBuffer, GetCurrentThreadId());
// warning(buf);
//This->SyncToPlay->PlayFast();
SetEvent(This->SyncToPlay->hPlayThread_PlayFast);
// Transfer immediatly control to the other threads
Sleep(0);
This->bSyncExit = false;
cicla = false;
break;
}
}
break;
CORO_SLEEP(1);
case 4:
This->PlayFast();
This->_bSyncExit = false;
_ctx->cicla = false;
break;
}
} else if (CoroScheduler.getEvent(This->_hPlayThreadPlayFast)->signalled) {
This->playFast();
}
}
/* Close the DirectSound buffer */
// sprintf(buf, "Exiting thread. Buffer = %x, MyThread = 0x%x\n", This->lpDSBuffer, GetCurrentThreadId());
// warning(buf);
// Close the DirectSound buffer
This->lpDSBuffer->Stop();
ExitThread(0);
#endif
CORO_END_CODE;
}
/**
* Unables or disables stream loop.
*
* @param bLoop True enable loop, False disables it
* @param _bLoop True enable loop, False disables it
*
* @remarks The loop must be activated BEFORE the stream starts
* playing. Any changes made during the play will have no
* effect until the stream is stopped then played again.
*/
void FPStream::setLoop(bool loop) {
_bLoop = loop;
}
@ -1025,38 +1382,38 @@ void FPStream::setLoop(bool loop) {
*
* @param bPause True enables pause, False disables it
*/
void FPStream::pause(bool bPause) {
if (_bFileLoaded) {
if (bPause && _bIsPlaying) {
#ifdef REFACTOR_ME
_lpDSBuffer->Stop();
#endif
_bIsPlaying = false;
_bPaused = true;
} else if (!bPause && _bPaused) {
#ifdef REFACTOR_ME
_dspnHot[0].dwOffset = 32;
_dspnHot[0].hEventNotify = hHot1;
if (bFileLoaded) {
if (bPause && bIsPlaying) {
lpDSBuffer->Stop();
bIsPlaying = false;
bPaused = true;
} else if (!bPause && bPaused) {
dspnHot[0].dwOffset = 32;
dspnHot[0].hEventNotify = hHot1;
_dspnHot[1].dwOffset = dwBufferSize / 2 + 32;
_dspnHot[1].hEventNotify = hHot2;
dspnHot[1].dwOffset = dwBufferSize / 2 + 32;
dspnHot[1].hEventNotify = hHot2;
dspnHot[2].dwOffset = dwBufferSize - 32; //DSBPN_OFFSETSTOP;
dspnHot[2].hEventNotify = hHot3;
_dspnHot[2].dwOffset = dwBufferSize - 32; //DSBPN_OFFSETSTOP;
_dspnHot[2].hEventNotify = hHot3;
if (FAILED(lpDSNotify->SetNotificationPositions(3, dspnHot))) {
int a = 1;
}
lpDSBuffer->Play(0, 0, bLoop);
bIsPlaying = true;
bPaused = false;
lpDSBuffer->Play(0, 0, _bLoop);
#endif
_bIsPlaying = true;
_bPaused = false;
// Trick to reset the volume after a possible new sound configuration
SetVolume(lastVolume);
setVolume(_lastVolume);
}
}
#endif
}
/**

View file

@ -245,6 +245,24 @@ public:
bool endOfBuffer() const;
};
/**
* Codec base class
*/
class CODEC {
protected:
bool _bEndReached;
public:
bool _bLoop;
CODEC(bool _bLoop = true);
virtual ~CODEC();
virtual uint32 decompress(Common::SeekableReadStream *stream, void *lpBuf, uint32 dwSize) = 0;
virtual void loopReset() = 0;
bool endOfStream();
};
class FPStream {
private:
// HWND hwnd;
@ -258,12 +276,12 @@ private:
uint32 _dwSize; // Stream size (bytes)
uint32 _dwCodec; // CODEC used
HANDLE _hThreadEnd; // Event used to close thread
uint32 _hThreadEnd; // Event used to close thread
Common::File _file; // File handle used for the stream
HANDLE _hPlayThread; // Handle of the Play thread
HANDLE _hHot1, _hHot2, _hHot3; // Events set by DirectSoundNotify
HANDLE _hPlayThreadPlayFast;
HANDLE _hPlayThreadPlayNormal;
uint32 _hPlayThread; // Handle of the Play thread
uint32 _hHot1, _hHot2, _hHot3; // Events set by DirectSoundNotify
uint32 _hPlayThreadPlayFast;
uint32 _hPlayThreadPlayNormal;
bool _bSoundSupported; // True if the sound is active
bool _bFileLoaded; // True if the file is open
@ -273,6 +291,7 @@ private:
bool _bPaused;
int _lastVolume;
FPStream *_syncToPlay;
CODEC *_codec;
// DSBPOSITIONNOTIFY dspnHot[3];
@ -286,7 +305,7 @@ private:
* Thread playing the stream
*
*/
static void playThread(FPStream *This);
static void playThread(CORO_PARAM, const void *param);
public:
@ -321,13 +340,13 @@ public:
/**
* Opens a file stream
*
* @param lpszFile Filename to be opened
* @param fileName Filename to be opened
* @param dwCodec CODEC to be used to uncompress samples
*
* @returns True is everything is OK, False otherwise
*/
bool loadFile(const char *lpszFileName, uint32 dwCodec = FPCODEC_RAW, int nSync = 2000);
bool loadFile(const Common::String &fileName, uint32 dwCodec = FPCODEC_RAW, int nSync = 2000);
/**
* Closes a file stream (opened or not).

View file

@ -187,10 +187,7 @@ void TonyEngine::GUIError(const Common::String &msg) {
GUIErrorMessage(msg);
}
void TonyEngine::playMusic(int nChannel, const char *fn, int nFX, bool bLoop, int nSync) {
warning("TODO: TonyEngine::playMusic");
// g_system->lockMutex(csMusic);
void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, bool bLoop, int nSync) {
if (nChannel < 4)
if (GLOBALS._flipflop)
nChannel = nChannel + 1;
@ -207,64 +204,78 @@ void TonyEngine::playMusic(int nChannel, const char *fn, int nFX, bool bLoop, in
break;
}
#ifdef REFACTOR_ME
// Mette il path giusto
if (nChannel < 4)
GetDataDirectory(DD_MUSIC, path_buffer);
else
GetDataDirectory(DD_LAYER, path_buffer);
_splitpath(path_buffer, drive, dir, NULL, NULL);
_splitpath(fn, NULL, NULL, fname, ext);
_makepath(path_buffer, drive, dir, fname, ext);
_makepath(path_buffer, drive, dir, fname, ext);
if (nFX == 22) { // Sync a tempo
curChannel = nChannel;
strcpy(nextMusic, path_buffer);
nextLoop = bLoop;
nextSync = nSync;
if (flipflop)
nextChannel = nChannel - 1;
GLOBALS._curChannel = nChannel;
GLOBALS._nextLoop = bLoop;
GLOBALS._nextSync = nSync;
if (GLOBALS._flipflop)
GLOBALS._nextChannel = nChannel - 1;
else
nextChannel = nChannel + 1;
DWORD id;
HANDLE hThread = CreateThread(NULL, 10240, (LPTHREAD_START_ROUTINE)DoNextMusic, _stream, 0, &id);
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
GLOBALS._nextChannel = nChannel + 1;
uint32 hThread = CoroScheduler.createProcess(doNextMusic, &_stream, sizeof(FPStream ***));
assert(hThread != CORO_INVALID_PID_VALUE);
} else if (nFX == 44) { // Cambia canale e lascia finire il primo
if (flipflop)
nextChannel = nChannel - 1;
if (GLOBALS._flipflop)
GLOBALS._nextChannel = nChannel - 1;
else
nextChannel = nChannel + 1;
GLOBALS._nextChannel = nChannel + 1;
_stream[nextChannel]->Stop();
_stream[nextChannel]->UnloadFile();
_stream[GLOBALS._nextChannel]->stop();
_stream[GLOBALS._nextChannel]->unloadFile();
if (!getIsDemo()) {
if (!_stream[nextChannel]->LoadFile(path_buffer, FPCODEC_ADPCM, nSync))
theGame.Abort();
if (!_stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
_vm->abortGame();
} else {
_stream[nextChannel]->LoadFile(path_buffer, FPCODEC_ADPCM, nSync);
_stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
}
_stream[nextChannel]->SetLoop(bLoop);
_stream[nextChannel]->Play();
_stream[GLOBALS._nextChannel]->setLoop(bLoop);
_stream[GLOBALS._nextChannel]->play();
flipflop = 1 - flipflop;
GLOBALS._flipflop = 1 - GLOBALS._flipflop;
} else {
if (!getIsDemo()) {
if (!_stream[nChannel]->LoadFile(path_buffer, FPCODEC_ADPCM, nSync))
theGame.Abort();
if (!_stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
_vm->abortGame();
} else {
_stream[nChannel]->LoadFile(path_buffer, FPCODEC_ADPCM, nSync);
_stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
}
_stream[nChannel]->SetLoop(bLoop);
_stream[nChannel]->Play();
_stream[nChannel]->setLoop(bLoop);
_stream[nChannel]->play();
}
#endif
}
// g_system->unlockMutex(csMusic);
void TonyEngine::doNextMusic(CORO_PARAM, const void *param) {
CORO_BEGIN_CONTEXT;
Common::String fn;
CORO_END_CONTEXT(_ctx);
FPStream **streams = *(FPStream ***)param;
CORO_BEGIN_CODE(_ctx);
if (!_vm->getIsDemo()) {
if (!streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync))
_vm->abortGame();
} else {
streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync);
}
streams[GLOBALS._nextChannel]->setLoop(GLOBALS._nextLoop);
streams[GLOBALS._nextChannel]->prefetch();
streams[GLOBALS._curChannel]->stop(true);
streams[GLOBALS._curChannel]->waitForSync(streams[GLOBALS._nextChannel]);
streams[GLOBALS._curChannel]->unloadFile();
GLOBALS._flipflop = 1 - GLOBALS._flipflop;
CORO_END_CODE;
}
void TonyEngine::playSFX(int nChannel, int nFX) {

View file

@ -87,6 +87,8 @@ private:
void closeVoiceDatabase();
void initCustomFunctionMap();
static void playProcess(CORO_PARAM, const void *param);
static void doNextMusic(CORO_PARAM, const void *param);
protected:
// Engine APIs
virtual Common::Error run();
@ -183,7 +185,7 @@ public:
// Music
// ******
void playMusic(int nChannel, const char *fn, int nFX, bool bLoop, int nSync);
void playMusic(int nChannel, const Common::String &fn, int nFX, bool bLoop, int nSync);
void stopMusic(int nChannel);
void playSFX(int nSfx, int nFX = 0);