| 
									
										
										
										
											2009-07-28 21:32:10 +00:00
										 |  |  | // Copyright (C) 2003 Dolphin Project.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU General Public License 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-23 20:00:12 +00:00
										 |  |  | #include <windows.h>
 | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2009-02-14 01:07:20 +00:00
										 |  |  | #include <dxerr.h>
 | 
					
						
							| 
									
										
										
										
											2009-12-13 11:51:29 +00:00
										 |  |  | #include "AudioCommon.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | #include "DSoundStream.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | bool DSound::CreateBuffer() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	PCMWAVEFORMAT pcmwf; | 
					
						
							|  |  |  | 	DSBUFFERDESC dsbdesc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT)); | 
					
						
							|  |  |  | 	memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; | 
					
						
							|  |  |  | 	pcmwf.wf.nChannels = 2; | 
					
						
							| 
									
										
										
										
											2009-03-26 10:15:11 +00:00
										 |  |  | 	pcmwf.wf.nSamplesPerSec = m_mixer->GetSampleRate(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	pcmwf.wf.nBlockAlign = 4; | 
					
						
							|  |  |  | 	pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; | 
					
						
							|  |  |  | 	pcmwf.wBitsPerSample = 16; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | 	// Fill out DSound buffer description.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	dsbdesc.dwSize  = sizeof(DSBUFFERDESC); | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | 	dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS | DSBCAPS_CTRLVOLUME; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	dsbdesc.dwBufferBytes = bufferSize = BUFSIZE; | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 	dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&pcmwf; | 
					
						
							| 
									
										
										
										
											2009-03-27 14:12:59 +00:00
										 |  |  | 	dsbdesc.guid3DAlgorithm = DS3DALG_DEFAULT; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 	HRESULT res = ds->CreateSoundBuffer(&dsbdesc, &dsBuffer, NULL); | 
					
						
							|  |  |  | 	if (SUCCEEDED(res)) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		dsBuffer->SetCurrentPosition(0); | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | 		dsBuffer->SetVolume(m_volume); | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 		return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		// Failed.
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 		PanicAlert("Sound buffer creation failed: %s", DXGetErrorString(res));  | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		dsBuffer = NULL; | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | bool DSound::WriteDataToBuffer(DWORD dwOffset,                  // Our own write cursor.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		char* soundData, // Start of our data.
 | 
					
						
							|  |  |  | 		DWORD dwSoundBytes) // Size of block to copy.
 | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-14 01:07:20 +00:00
										 |  |  | 	// I want to record the regular audio to, how do I do that?
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | 	void *ptr1, *ptr2; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	DWORD numBytes1, numBytes2; | 
					
						
							|  |  |  | 	// Obtain memory address of write block. This will be in two parts if the block wraps around.
 | 
					
						
							|  |  |  | 	HRESULT hr = dsBuffer->Lock(dwOffset, dwSoundBytes, &ptr1, &numBytes1, &ptr2, &numBytes2, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If the buffer was lost, restore and retry lock.
 | 
					
						
							|  |  |  | 	if (DSERR_BUFFERLOST == hr) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		dsBuffer->Restore(); | 
					
						
							|  |  |  | 		hr = dsBuffer->Lock(dwOffset, dwSoundBytes, &ptr1, &numBytes1, &ptr2, &numBytes2, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		memcpy(ptr1, soundData, numBytes1); | 
					
						
							|  |  |  | 		if (ptr2 != 0) | 
					
						
							|  |  |  | 			memcpy(ptr2, soundData + numBytes1, numBytes2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Release the data back to DirectSound.
 | 
					
						
							|  |  |  | 		dsBuffer->Unlock(ptr1, numBytes1, ptr2, numBytes2); | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 		return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | // The audio thread.
 | 
					
						
							| 
									
										
										
										
											2009-07-10 20:22:25 +00:00
										 |  |  | THREAD_RETURN soundThread(void* args) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | 	(reinterpret_cast<DSound *>(args))->SoundLoop(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | void DSound::SoundLoop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	currentPos = 0; | 
					
						
							|  |  |  | 	lastPos = 0; | 
					
						
							| 
									
										
										
										
											2009-12-18 19:52:04 +00:00
										 |  |  | 	dsBuffer->Play(0, 0, DSBPLAY_LOOPING); | 
					
						
							| 
									
										
										
										
											2009-03-27 14:12:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  | 	while (!threadData) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		// No blocking inside the csection
 | 
					
						
							|  |  |  | 		dsBuffer->GetCurrentPosition((DWORD*)¤tPos, 0); | 
					
						
							| 
									
										
										
										
											2009-02-09 19:50:06 +00:00
										 |  |  | 		int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos)); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		if (numBytesToRender >= 256) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2009-12-25 11:59:04 +00:00
										 |  |  | 			if (numBytesToRender > sizeof(realtimeBuffer)) | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 				PanicAlert("soundThread: too big render call"); | 
					
						
							| 
									
										
										
										
											2009-12-23 15:34:14 +00:00
										 |  |  | 			m_mixer->Mix(realtimeBuffer, numBytesToRender / 4); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 			WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender); | 
					
						
							| 
									
										
										
										
											2009-12-23 15:34:14 +00:00
										 |  |  | 			lastPos = ModBufferSize(lastPos + numBytesToRender); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-02-23 19:47:58 +00:00
										 |  |  | 		soundSyncEvent.Wait(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | bool DSound::Start() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-23 19:47:58 +00:00
										 |  |  | 	soundSyncEvent.Init(); | 
					
						
							| 
									
										
										
										
											2009-12-18 19:52:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	if (FAILED(DirectSoundCreate8(0, &ds, 0))) | 
					
						
							| 
									
										
										
										
											2009-02-20 22:04:52 +00:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2009-03-27 14:12:59 +00:00
										 |  |  | 	if (g_dspInitialize.hWnd) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		HRESULT hr = ds->SetCooperativeLevel((HWND)g_dspInitialize.hWnd, DSSCL_PRIORITY); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	if (!CreateBuffer()) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD num1; | 
					
						
							|  |  |  | 	short* p1; | 
					
						
							|  |  |  | 	dsBuffer->Lock(0, bufferSize, (void* *)&p1, &num1, 0, 0, 0); | 
					
						
							|  |  |  | 	memset(p1, 0, num1); | 
					
						
							|  |  |  | 	dsBuffer->Unlock(p1, num1, 0, 0); | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 	thread = new Common::Thread(soundThread, (void *)this); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | void DSound::SetVolume(int volume) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// This is in "dBA attenuation" from 0 to -10000, logarithmic
 | 
					
						
							|  |  |  | 	m_volume = (int)floor(log10((float)volume) * 5000.0f) - 10000; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-03 20:09:48 +00:00
										 |  |  | 	if (dsBuffer != NULL) | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | 		dsBuffer->SetVolume(m_volume); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | void DSound::Update() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-23 19:47:58 +00:00
										 |  |  | 	soundSyncEvent.Set(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-13 11:51:29 +00:00
										 |  |  | void DSound::Clear(bool mute) | 
					
						
							| 
									
										
										
										
											2009-11-07 20:01:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-13 11:51:29 +00:00
										 |  |  | 	m_muted = mute; | 
					
						
							| 
									
										
										
										
											2009-12-18 19:52:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-08 13:28:12 +00:00
										 |  |  | 	if (dsBuffer != NULL) | 
					
						
							| 
									
										
										
										
											2009-12-12 22:30:53 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-06-08 13:28:12 +00:00
										 |  |  | 		if (m_muted) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-03-08 08:03:42 +00:00
										 |  |  | 			dsBuffer->Stop(); | 
					
						
							| 
									
										
										
										
											2010-06-08 13:28:12 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			dsBuffer->Play(0, 0, DSBPLAY_LOOPING); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-12-12 22:30:53 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-07 20:01:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | void DSound::Stop() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	threadData = 1; | 
					
						
							|  |  |  | 	// kick the thread if it's waiting
 | 
					
						
							| 
									
										
										
										
											2009-02-23 19:47:58 +00:00
										 |  |  | 	soundSyncEvent.Set(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-18 19:52:04 +00:00
										 |  |  | 	delete thread; | 
					
						
							|  |  |  | 	thread = NULL; | 
					
						
							|  |  |  | 	dsBuffer->Stop(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	dsBuffer->Release(); | 
					
						
							|  |  |  | 	ds->Release(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-23 19:47:58 +00:00
										 |  |  | 	soundSyncEvent.Shutdown(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-12-10 21:00:52 +00:00
										 |  |  | 
 |