diff options
| -rw-r--r-- | engines/tony/custom.cpp | 6 | ||||
| -rw-r--r-- | engines/tony/gfxengine.cpp | 2 | ||||
| -rw-r--r-- | engines/tony/sound.cpp | 809 | ||||
| -rw-r--r-- | engines/tony/sound.h | 35 | ||||
| -rw-r--r-- | engines/tony/tony.cpp | 99 | ||||
| -rw-r--r-- | engines/tony/tony.h | 4 | 
6 files changed, 671 insertions, 284 deletions
| 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); | 
