From 61d460a854ff4883411846703543bb2f797fcd6b Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 19 Jun 2012 20:50:48 +1000 Subject: TONY: Implement more of the music related code from the original --- engines/tony/custom.cpp | 6 +- engines/tony/gfxengine.cpp | 2 - engines/tony/sound.cpp | 809 ++++++++++++++++++++++++++++++++------------- engines/tony/sound.h | 35 +- engines/tony/tony.cpp | 99 +++--- engines/tony/tony.h | 4 +- 6 files changed, 671 insertions(+), 284 deletions(-) (limited to 'engines') diff --git a/engines/tony/custom.cpp b/engines/tony/custom.cpp index 016c84ab39..ce1c2860f8 100644 --- a/engines/tony/custom.cpp +++ b/engines/tony/custom.cpp @@ -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; } diff --git a/engines/tony/gfxengine.cpp b/engines/tony/gfxengine.cpp index 0785ec534c..cc53a1d8e2 100644 --- a/engines/tony/gfxengine.cpp +++ b/engines/tony/gfxengine.cpp @@ -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(); diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp index 7e786a2f11..484b279cda 100644 --- a/engines/tony/sound.cpp +++ b/engines/tony/sound.cpp @@ -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 +\****************************************************************************/ + /** - * Default constructor. Initializes the attributes. + * 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); - - /* Unlock the buffer */ - lpDSBuffer->Unlock(lpBuf, dwBufferSize / 2, NULL, NULL); + // Uncompress the data from the stream directly into the locked buffer + _codec->decompress(_file.readStream(_file.size()), lpBuf, _dwBufferSize / 2); - /* 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); + // Unlock the buffer +#ifdef REFACTOR_ME + lpDSBuffer->unlock(lpBuf, _dwBufferSize / 2, NULL, NULL); +#endif - /* Start to play the buffer */ - lpDSBuffer->SetCurrentPosition(0); - bIsPlaying = true; + // Create a thread to play the stream + _hThreadEnd = CoroScheduler.createEvent(false, false); + _hPlayThread = CoroScheduler.createProcess(playThread, this, sizeof(FPStream *)); + + // 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 - byte *lpLockBuf; - uint32 dwResult; - byte *lpLockBuf2; - uint32 dwResult2; - bool cicla = true; - uint32 countEnd; - bool bPrecache; - char buf[1024]; +void FPStream::playThread(CORO_PARAM, const void *param) { + CORO_BEGIN_CONTEXT; + byte *lpLockBuf; + uint32 dwResult; + byte *lpLockBuf2; + uint32 dwResult2; + 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); + + _ctx->bPrecache = false; - 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; -// uint32 dwBufStatus; -// This->lpDSBuffer->GetStatus(&dwBufStatus); + CORO_INVOKE_4(CoroScheduler.waitForMultipleObjects, 5, _ctx->hList, false, CORO_INFINITE, &_ctx->dwResult); + // Check to determine which event has been set + if (CoroScheduler.getEvent(This->_hThreadEnd)->signalled) { + /* Must leave the thread */ + _ctx->cicla = false; + + } 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); -// sprintf(buf, "WFMO: %x (buf status: %x) MyThread: 0x%x\n", This->lpDSBuffer, dwBufStatus, GetCurrentThreadId()); -// warning(buf); - dwResult = WaitForMultipleObjects(5, hList, false, CORO_INFINITE); + copyMemory(_ctx->lpLockBuf, This->_lpTempBuffer, This->_dwBufferSize / 2); + This->lpDSBuffer->Unlock(_ctx->lpLockBuf, This->_dwBufferSize / 2, _ctx->lpLockBuf2, 0); - /* uint32 dwPlay, dwWrite; - This->lpDSBuffer->GetCurrentPosition(&dwPlay, &dwWrite); - sprintf(buf, "CP Play: %u, Write: %u\n", dwPlay, dwWrite); - warning(buf); */ + _ctx->bPrecache = true; - /* Make a switch to determine which event has been set */ - switch (dwResult - WAIT_OBJECT_0) { - case 0: - /* Must leave the thread */ - cicla = false; - break; - - 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->_hHot2)->signalled) { + This->lpDSBuffer->Lock(0, This->_dwBufferSize / 2, (void **)&_ctx->lpLockBuf, &_ctx->dwResult, NULL, NULL, 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, 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; + CORO_SLEEP(1); + + This->_bSyncExit = false; + _ctx->cicla = false; break; } - } - break; - - case 4: - This->PlayFast(); - 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 } /** diff --git a/engines/tony/sound.h b/engines/tony/sound.h index 4dd00a3028..38ce6de2a7 100644 --- a/engines/tony/sound.h +++ b/engines/tony/sound.h @@ -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). diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp index 9e9e032e49..2c102f5c8b 100644 --- a/engines/tony/tony.cpp +++ b/engines/tony/tony.cpp @@ -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) { diff --git a/engines/tony/tony.h b/engines/tony/tony.h index 5f6fd8cb44..94dc3de92d 100644 --- a/engines/tony/tony.h +++ b/engines/tony/tony.h @@ -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); -- cgit v1.2.3