| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-18 19:24:46 +00:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2011-01-31 08:19:27 +00:00
										 |  |  | #include <functional>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "AudioCommon/AudioCommon.h"
 | 
					
						
							|  |  |  | #include "AudioCommon/DSoundStream.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | #include "Common/StdThread.h"
 | 
					
						
							|  |  |  | #include "Common/Thread.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2013-06-22 23:23:53 -04:00
										 |  |  | 	dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	HRESULT res = ds->CreateSoundBuffer(&dsbdesc, &dsBuffer, nullptr); | 
					
						
							| 
									
										
										
										
											2009-01-29 00:57:55 +00:00
										 |  |  | 	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.
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | 		PanicAlertT("Sound buffer creation failed: %08x", res); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		dsBuffer = nullptr; | 
					
						
							| 
									
										
										
										
											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-02-20 22:04:52 +00:00
										 |  |  | void DSound::SoundLoop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-30 20:22:48 -08:00
										 |  |  | 	Common::SetCurrentThreadName("Audio thread - dsound"); | 
					
						
							| 
									
										
										
										
											2011-12-18 02:25:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							|  |  |  | 	if (FAILED(DirectSoundCreate8(0, &ds, 0))) | 
					
						
							| 
									
										
										
										
											2013-03-19 21:51:12 -04:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2011-01-28 18:39:30 +00:00
										 |  |  | 	if (hWnd) | 
					
						
							| 
									
										
										
										
											2009-03-27 14:12:59 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-01-28 18:39:30 +00:00
										 |  |  | 		HRESULT hr = ds->SetCooperativeLevel((HWND)hWnd, DSSCL_PRIORITY); | 
					
						
							| 
									
										
										
										
											2009-03-27 14:12:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	if (!CreateBuffer()) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD num1; | 
					
						
							|  |  |  | 	short* p1; | 
					
						
							| 
									
										
										
										
											2011-12-30 20:22:48 -08:00
										 |  |  | 	dsBuffer->Lock(0, bufferSize, (void* *)&p1, &num1, 0, 0, DSBLOCK_ENTIREBUFFER); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	memset(p1, 0, num1); | 
					
						
							|  |  |  | 	dsBuffer->Unlock(p1, num1, 0, 0); | 
					
						
							| 
									
										
										
										
											2014-04-01 12:09:22 -04:00
										 |  |  | 	thread = std::thread(std::mem_fn(&DSound::SoundLoop), 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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	if (dsBuffer != nullptr) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	if (dsBuffer != nullptr) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-27 20:47:58 +00:00
										 |  |  | 	thread.join(); | 
					
						
							| 
									
										
										
										
											2009-12-18 19:52:04 +00:00
										 |  |  | 	dsBuffer->Stop(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:25:12 +00:00
										 |  |  | 	dsBuffer->Release(); | 
					
						
							|  |  |  | 	ds->Release(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-12-10 21:00:52 +00:00
										 |  |  | 
 |