diff src/win32/DirectSound.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/win32/DirectSound.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,534 @@
     1.4 +#include "stdafx.h"
     1.5 +#include <mmreg.h>
     1.6 +#include <dsound.h>
     1.7 +
     1.8 +#include "resource.h"
     1.9 +#include "AVIWrite.h"
    1.10 +#include "Sound.h"
    1.11 +#include "WavWriter.h"
    1.12 +#include "VBA.h"
    1.13 +
    1.14 +#include "../gba/GBAGlobals.h"
    1.15 +#include "../gba/GBASound.h"
    1.16 +#include "../common/nesvideos-piece.h"
    1.17 +
    1.18 +extern void directXMessage(const char *);
    1.19 +
    1.20 +class DirectSound : public ISound
    1.21 +{
    1.22 +private:
    1.23 +	HINSTANCE			dsoundDLL;
    1.24 +	LPDIRECTSOUND		pDirectSound;
    1.25 +	LPDIRECTSOUNDBUFFER dsbPrimary;
    1.26 +	LPDIRECTSOUNDBUFFER dsbSecondary;
    1.27 +	LPDIRECTSOUNDNOTIFY dsbNotify;
    1.28 +	HANDLE		 dsbEvent;
    1.29 +	WAVEFORMATEX wfx;
    1.30 +	float		 curRate;
    1.31 +public:
    1.32 +	DirectSound();
    1.33 +	virtual ~DirectSound();
    1.34 +
    1.35 +	bool init();
    1.36 +	void pause();
    1.37 +	void reset();
    1.38 +	void resume();
    1.39 +	void write();
    1.40 +	void setSpeed(float rate);
    1.41 +	bool isPlaying();
    1.42 +	void clearAudioBuffer();
    1.43 +};
    1.44 +
    1.45 +DirectSound::DirectSound()
    1.46 +{
    1.47 +	dsoundDLL	 = NULL;
    1.48 +	pDirectSound = NULL;
    1.49 +	dsbPrimary	 = NULL;
    1.50 +	dsbSecondary = NULL;
    1.51 +	dsbNotify	 = NULL;
    1.52 +	dsbEvent	 = NULL;
    1.53 +}
    1.54 +
    1.55 +DirectSound::~DirectSound()
    1.56 +{
    1.57 +	if (theApp.aviRecorder != NULL)
    1.58 +	{
    1.59 +		delete theApp.aviRecorder;
    1.60 +		theApp.aviRecorder	= NULL;
    1.61 +		theApp.aviRecording = false;
    1.62 +	}
    1.63 +
    1.64 +	if (theApp.soundRecording)
    1.65 +	{
    1.66 +		if (theApp.soundRecorder != NULL)
    1.67 +		{
    1.68 +			delete theApp.soundRecorder;
    1.69 +			theApp.soundRecorder = NULL;
    1.70 +		}
    1.71 +		theApp.soundRecording = false;
    1.72 +	}
    1.73 +
    1.74 +	if (dsbNotify != NULL)
    1.75 +	{
    1.76 +		dsbNotify->Release();
    1.77 +		dsbNotify = NULL;
    1.78 +	}
    1.79 +
    1.80 +	if (dsbEvent != NULL)
    1.81 +	{
    1.82 +		CloseHandle(dsbEvent);
    1.83 +		dsbEvent = NULL;
    1.84 +	}
    1.85 +
    1.86 +	if (pDirectSound != NULL)
    1.87 +	{
    1.88 +		if (dsbPrimary != NULL)
    1.89 +		{
    1.90 +			dsbPrimary->Release();
    1.91 +			dsbPrimary = NULL;
    1.92 +		}
    1.93 +
    1.94 +		if (dsbSecondary != NULL)
    1.95 +		{
    1.96 +			dsbSecondary->Release();
    1.97 +			dsbSecondary = NULL;
    1.98 +		}
    1.99 +
   1.100 +		pDirectSound->Release();
   1.101 +		pDirectSound = NULL;
   1.102 +	}
   1.103 +
   1.104 +	if (dsoundDLL != NULL)
   1.105 +	{
   1.106 +		FreeLibrary(dsoundDLL);
   1.107 +		dsoundDLL = NULL;
   1.108 +	}
   1.109 +}
   1.110 +
   1.111 +bool DirectSound::init()
   1.112 +{
   1.113 +	HRESULT hr;
   1.114 +
   1.115 +	dsoundDLL = LoadLibrary("DSOUND.DLL");
   1.116 +	HRESULT (WINAPI *DSoundCreate)(LPCGUID, LPDIRECTSOUND *, IUnknown *);
   1.117 +	if (dsoundDLL != NULL)
   1.118 +	{
   1.119 +		DSoundCreate = (HRESULT (WINAPI *)(LPCGUID, LPDIRECTSOUND *, IUnknown *))
   1.120 +		               GetProcAddress(dsoundDLL, "DirectSoundCreate");
   1.121 +
   1.122 +		if (DSoundCreate == NULL)
   1.123 +		{
   1.124 +			directXMessage("DirectSoundCreate");
   1.125 +			return false;
   1.126 +		}
   1.127 +	}
   1.128 +	else
   1.129 +	{
   1.130 +		directXMessage("DSOUND.DLL");
   1.131 +		return false;
   1.132 +	}
   1.133 +
   1.134 +	if (FAILED(hr = DSoundCreate(NULL, &pDirectSound, NULL)))
   1.135 +	{
   1.136 +		//    errorMessage(myLoadString(IDS_ERROR_SOUND_CREATE), hr);
   1.137 +		systemMessage(IDS_CANNOT_CREATE_DIRECTSOUND,
   1.138 +		              "Cannot create DirectSound %08x", hr);
   1.139 +		pDirectSound = NULL;
   1.140 +		dsbSecondary = NULL;
   1.141 +		return false;
   1.142 +	}
   1.143 +
   1.144 +	if (FAILED(hr = pDirectSound->SetCooperativeLevel((HWND)*theApp.m_pMainWnd, DSSCL_EXCLUSIVE)))
   1.145 +	{
   1.146 +		//    errorMessage(myLoadString(IDS_ERROR_SOUND_LEVEL), hr);
   1.147 +		systemMessage(IDS_CANNOT_SETCOOPERATIVELEVEL,
   1.148 +		              "Cannot SetCooperativeLevel %08x", hr);
   1.149 +		return false;
   1.150 +	}
   1.151 +
   1.152 +	DSBUFFERDESC dsbdesc;
   1.153 +	ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
   1.154 +	dsbdesc.dwSize	= sizeof(DSBUFFERDESC);
   1.155 +	dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
   1.156 +
   1.157 +	if (FAILED(hr = pDirectSound->CreateSoundBuffer(&dsbdesc, &dsbPrimary, NULL)))
   1.158 +	{
   1.159 +		//    errorMessage(myLoadString(IDS_ERROR_SOUND_BUFFER),hr);
   1.160 +		systemMessage(IDS_CANNOT_CREATESOUNDBUFFER,
   1.161 +		              "Cannot CreateSoundBuffer %08x", hr);
   1.162 +		return false;
   1.163 +	}
   1.164 +
   1.165 +	// Set primary buffer format
   1.166 +
   1.167 +	memset(&wfx, 0, sizeof(WAVEFORMATEX));
   1.168 +	wfx.wFormatTag = WAVE_FORMAT_PCM;
   1.169 +	wfx.nChannels  = 2;
   1.170 +	switch (soundQuality)
   1.171 +	{
   1.172 +	case 2:
   1.173 +		wfx.nSamplesPerSec	= 22050;
   1.174 +		soundBufferLen		= 736 * 2;
   1.175 +		soundBufferTotalLen = 7360 * 2;
   1.176 +		break;
   1.177 +	case 4:
   1.178 +		wfx.nSamplesPerSec	= 11025;
   1.179 +		soundBufferLen		= 368 * 2;
   1.180 +		soundBufferTotalLen = 3680 * 2;
   1.181 +		break;
   1.182 +	default:
   1.183 +		soundQuality		= 1;
   1.184 +		wfx.nSamplesPerSec	= 44100;
   1.185 +		soundBufferLen		= 1470 * 2;
   1.186 +		soundBufferTotalLen = 14700 * 2;
   1.187 +	}
   1.188 +	wfx.wBitsPerSample	= 16;
   1.189 +	wfx.nBlockAlign		= (wfx.wBitsPerSample / 8) * wfx.nChannels;
   1.190 +	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
   1.191 +
   1.192 +	if (FAILED(hr = dsbPrimary->SetFormat(&wfx)))
   1.193 +	{
   1.194 +		//    errorMessage(myLoadString(IDS_ERROR_SOUND_PRIMARY),hr);
   1.195 +		systemMessage(IDS_CANNOT_SETFORMAT_PRIMARY,
   1.196 +		              "Cannot SetFormat for primary %08x", hr);
   1.197 +		return false;
   1.198 +	}
   1.199 +
   1.200 +	ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
   1.201 +	dsbdesc.dwSize		  = sizeof(DSBUFFERDESC);
   1.202 +	dsbdesc.dwFlags		  = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS;
   1.203 +	dsbdesc.dwBufferBytes = soundBufferTotalLen;
   1.204 +	dsbdesc.lpwfxFormat	  = &wfx;
   1.205 +
   1.206 +	if (FAILED(hr = pDirectSound->CreateSoundBuffer(&dsbdesc, &dsbSecondary, NULL)))
   1.207 +	{
   1.208 +		bool ok = false;
   1.209 +		while (dsbdesc.dwFlags != DSBCAPS_GETCURRENTPOSITION2)
   1.210 +		{
   1.211 +			if (dsbdesc.dwFlags & DSBCAPS_CTRLFREQUENCY)
   1.212 +				dsbdesc.dwFlags ^= DSBCAPS_CTRLFREQUENCY;
   1.213 +			else if (dsbdesc.dwFlags & DSBCAPS_GLOBALFOCUS)
   1.214 +				dsbdesc.dwFlags ^= DSBCAPS_GLOBALFOCUS;
   1.215 +			else if (dsbdesc.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
   1.216 +				dsbdesc.dwFlags ^= DSBCAPS_CTRLPOSITIONNOTIFY;
   1.217 +			if (SUCCEEDED(hr = pDirectSound->CreateSoundBuffer(&dsbdesc, &dsbSecondary, NULL)))
   1.218 +			{
   1.219 +				ok = true;
   1.220 +				break;
   1.221 +			}
   1.222 +		}
   1.223 +		if (!ok)
   1.224 +		{
   1.225 +			systemMessage(IDS_CANNOT_CREATESOUNDBUFFER_SEC, "Cannot CreateSoundBuffer secondary %08x", hr);
   1.226 +			return false;
   1.227 +		}
   1.228 +
   1.229 +		dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
   1.230 +	}
   1.231 +
   1.232 +	dsbSecondary->SetCurrentPosition(0);
   1.233 +
   1.234 +	if (!theApp.useOldSync)
   1.235 +	{
   1.236 +		hr = dsbSecondary->QueryInterface(IID_IDirectSoundNotify,
   1.237 +		                                  (void * *)&dsbNotify);
   1.238 +		if (!FAILED(hr))
   1.239 +		{
   1.240 +			dsbEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   1.241 +
   1.242 +			DSBPOSITIONNOTIFY notify[10];
   1.243 +
   1.244 +			for (int i = 0; i < 10; i++)
   1.245 +			{
   1.246 +				notify[i].dwOffset	   = i * soundBufferLen;
   1.247 +				notify[i].hEventNotify = dsbEvent;
   1.248 +			}
   1.249 +			if (FAILED(dsbNotify->SetNotificationPositions(10, notify)))
   1.250 +			{
   1.251 +				dsbNotify->Release();
   1.252 +				dsbNotify = NULL;
   1.253 +				CloseHandle(dsbEvent);
   1.254 +				dsbEvent = NULL;
   1.255 +			}
   1.256 +		}
   1.257 +	}
   1.258 +
   1.259 +	hr = dsbPrimary->Play(0, 0, DSBPLAY_LOOPING);
   1.260 +
   1.261 +	if (FAILED(hr))
   1.262 +	{
   1.263 +		//    errorMessage(myLoadString(IDS_ERROR_SOUND_PLAYPRIM), hr);
   1.264 +		systemMessage(IDS_CANNOT_PLAY_PRIMARY, "Cannot Play primary %08x", hr);
   1.265 +		return false;
   1.266 +	}
   1.267 +
   1.268 +	systemSoundOn = true;
   1.269 +
   1.270 +	return true;
   1.271 +}
   1.272 +
   1.273 +void DirectSound::setSpeed(float rate)
   1.274 +{
   1.275 +	if (dsbSecondary == NULL || wfx.nSamplesPerSec <= 0)
   1.276 +		return;
   1.277 +
   1.278 +	if (rate != curRate)
   1.279 +	{
   1.280 +		curRate = rate;
   1.281 +
   1.282 +		if (rate > 4.0f)
   1.283 +			rate = 4.0f;
   1.284 +		if (rate < 0.06f)
   1.285 +			rate = 0.06f;
   1.286 +
   1.287 +		dsbSecondary->SetFrequency((DWORD)((float)wfx.nSamplesPerSec * rate));
   1.288 +	}
   1.289 +}
   1.290 +
   1.291 +void DirectSound::pause()
   1.292 +{
   1.293 +	if (dsbSecondary != NULL)
   1.294 +	{
   1.295 +		DWORD status = 0;
   1.296 +		dsbSecondary->GetStatus(&status);
   1.297 +
   1.298 +		if (status & DSBSTATUS_PLAYING)
   1.299 +		{
   1.300 +			//systemScreenMessage("sound stopped (pause)!", 3);
   1.301 +			dsbSecondary->Stop();
   1.302 +		}
   1.303 +	}
   1.304 +}
   1.305 +
   1.306 +bool DirectSound::isPlaying()
   1.307 +{
   1.308 +	if (dsbSecondary != NULL)
   1.309 +	{
   1.310 +		DWORD status = 0;
   1.311 +		dsbSecondary->GetStatus(&status);
   1.312 +
   1.313 +		if (status & DSBSTATUS_PLAYING)
   1.314 +		{
   1.315 +			return true;
   1.316 +		}
   1.317 +	}
   1.318 +	return false;
   1.319 +}
   1.320 +
   1.321 +void DirectSound::reset()
   1.322 +{
   1.323 +	if (dsbSecondary)
   1.324 +	{
   1.325 +		//systemScreenMessage("sound stopped (reset)!", 3);
   1.326 +		dsbSecondary->Stop();
   1.327 +		dsbSecondary->SetCurrentPosition(0);
   1.328 +	}
   1.329 +}
   1.330 +
   1.331 +void DirectSound::resume()
   1.332 +{
   1.333 +	if (dsbSecondary != NULL)
   1.334 +	{
   1.335 +		dsbSecondary->Play(0, 0, DSBPLAY_LOOPING);
   1.336 +	}
   1.337 +}
   1.338 +
   1.339 +long linearFrameCount	   = 0;
   1.340 +long linearSoundByteCount  = 0;
   1.341 +long linearSoundFrameCount = 0;
   1.342 +
   1.343 +void DirectSound::write()
   1.344 +{
   1.345 +	int	   len = soundBufferLen;
   1.346 +	LPVOID lpvPtr1;
   1.347 +	DWORD  dwBytes1;
   1.348 +	LPVOID lpvPtr2;
   1.349 +	DWORD  dwBytes2;
   1.350 +
   1.351 +	do
   1.352 +	{
   1.353 +		linearSoundByteCount += len;
   1.354 +		if (wfx.nAvgBytesPerSec)
   1.355 +			linearSoundFrameCount = 60 * linearSoundByteCount / wfx.nAvgBytesPerSec;
   1.356 +
   1.357 +		if (pDirectSound != NULL)
   1.358 +		{
   1.359 +			if (theApp.soundRecording)
   1.360 +			{
   1.361 +				if (dsbSecondary)
   1.362 +				{
   1.363 +					if (theApp.soundRecorder == NULL)
   1.364 +					{
   1.365 +						theApp.soundRecorder = new WavWriter;
   1.366 +						WAVEFORMATEX format;
   1.367 +						dsbSecondary->GetFormat(&format, sizeof(format), NULL);
   1.368 +						if (theApp.soundRecorder->Open(theApp.soundRecordName))
   1.369 +							theApp.soundRecorder->SetFormat(&format);
   1.370 +					}
   1.371 +				}
   1.372 +
   1.373 +				if (theApp.soundRecorder)
   1.374 +				{
   1.375 +					theApp.soundRecorder->AddSound((u8 *)soundFinalWave, len);
   1.376 +				}
   1.377 +			}
   1.378 +
   1.379 +			if (theApp.nvAudioLog)
   1.380 +			{
   1.381 +				NESVideoLoggingAudio((u8 *)soundFinalWave, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels, len /
   1.382 +				                     (wfx.nChannels * (wfx.wBitsPerSample / 8)));
   1.383 +			}
   1.384 +
   1.385 +			// alternate avi record routine has been added in VBA.cpp
   1.386 +			if (!theApp.altAviRecordMethod && theApp.aviRecording)
   1.387 +			{
   1.388 +				if (theApp.aviRecorder && !theApp.aviRecorder->IsPaused())
   1.389 +				{
   1.390 +					if (dsbSecondary)
   1.391 +					{
   1.392 +						if (!theApp.aviRecorder->IsSoundAdded())
   1.393 +						{
   1.394 +							WAVEFORMATEX format;
   1.395 +							dsbSecondary->GetFormat(&format, sizeof(format), NULL);
   1.396 +							theApp.aviRecorder->SetSoundFormat(&format);
   1.397 +						}
   1.398 +					}
   1.399 +
   1.400 +					theApp.aviRecorder->AddSound((u8 *)soundFinalWave, len);
   1.401 +				}
   1.402 +			}
   1.403 +		}
   1.404 +	}
   1.405 +	while (linearSoundFrameCount <= linearFrameCount);
   1.406 +
   1.407 +	// arbitrarily wrap counters at 10000 frames to avoid mismatching wrap-around freeze
   1.408 +	if (linearSoundFrameCount > 10000 && linearFrameCount > 10000)
   1.409 +	{
   1.410 +		linearFrameCount	 -= 10000;
   1.411 +		linearSoundByteCount -= wfx.nAvgBytesPerSec * 10000 / 60;
   1.412 +		linearSoundFrameCount = 60 * linearSoundByteCount / wfx.nAvgBytesPerSec;
   1.413 +	}
   1.414 +
   1.415 +	if (!pDirectSound)
   1.416 +		return;
   1.417 +
   1.418 +	HRESULT hr;
   1.419 +
   1.420 +	bool fastForward = speedup;
   1.421 +#if (defined(WIN32) && !defined(SDL))
   1.422 +	fastForward |= theApp.frameSearchSkipping;
   1.423 +#endif
   1.424 +
   1.425 +	// slows down emulator to match up with the sound speed
   1.426 +	if (!fastForward && synchronize && !(theApp.throttle > 100 && theApp.accuratePitchThrottle)
   1.427 +		&& theApp.throttle >= 6 && theApp.throttle <= 400)
   1.428 +	{
   1.429 +		DWORD status = 0;
   1.430 +		hr = dsbSecondary->GetStatus(&status);
   1.431 +		if (status & DSBSTATUS_PLAYING)
   1.432 +		{
   1.433 +			if (!soundPaused)
   1.434 +			{
   1.435 +				DWORD play;
   1.436 +				while (true)
   1.437 +				{
   1.438 +					dsbSecondary->GetCurrentPosition(&play, NULL);
   1.439 +
   1.440 +					if (soundNextPosition + soundBufferLen < soundBufferTotalLen)
   1.441 +					{
   1.442 +						if (play < soundNextPosition
   1.443 +						    || play > soundNextPosition + soundBufferLen)
   1.444 +							break;
   1.445 +					}
   1.446 +					else
   1.447 +					{
   1.448 +						if (play < soundNextPosition
   1.449 +						    && play > (soundNextPosition + soundBufferLen) % soundBufferTotalLen)
   1.450 +							break;
   1.451 +					}
   1.452 +
   1.453 +					if (dsbEvent)
   1.454 +					{
   1.455 +						WaitForSingleObject(dsbEvent, 50);
   1.456 +					}
   1.457 +				}
   1.458 +			}
   1.459 +		}
   1.460 +		else
   1.461 +		{
   1.462 +			soundPaused = 1;
   1.463 +		}
   1.464 +	}
   1.465 +
   1.466 +	// Obtain memory address of write block. This will be in two parts
   1.467 +	// if the block wraps around.
   1.468 +	hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen,
   1.469 +	                        &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2,
   1.470 +	                        0);
   1.471 +
   1.472 +	if (FAILED(hr))
   1.473 +	{
   1.474 +		char str [256];
   1.475 +		sprintf(str, "Locking secondary failed with %d", hr);
   1.476 +		systemScreenMessage(str);
   1.477 +	}
   1.478 +
   1.479 +	// If DSERR_BUFFERLOST is returned, restore and retry lock.
   1.480 +	if (DSERR_BUFFERLOST == hr)
   1.481 +	{
   1.482 +		dsbSecondary->Restore();
   1.483 +		hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen,
   1.484 +		                        &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2,
   1.485 +		                        0);
   1.486 +	}
   1.487 +
   1.488 +	if (SUCCEEDED(hr))
   1.489 +	{
   1.490 +		if (theApp.muteFrameAdvance && theApp.winPauseNextFrame || theApp.winMuteForNow)
   1.491 +		{
   1.492 +			// Write 0 to pointers.
   1.493 +			if (NULL != lpvPtr1)
   1.494 +				ZeroMemory(lpvPtr1, dwBytes1);
   1.495 +			if (NULL != lpvPtr2)
   1.496 +				ZeroMemory(lpvPtr2, dwBytes2);
   1.497 +		}
   1.498 +		else
   1.499 +		{
   1.500 +			// Write to pointers.
   1.501 +			if (NULL != lpvPtr1)
   1.502 +				CopyMemory(lpvPtr1, soundFinalWave, dwBytes1);
   1.503 +			if (NULL != lpvPtr2)
   1.504 +				CopyMemory(lpvPtr2, soundFinalWave + dwBytes1, dwBytes2);
   1.505 +		}
   1.506 +
   1.507 +		// Release the data back to DirectSound.
   1.508 +		hr = dsbSecondary->Unlock(lpvPtr1, dwBytes1, lpvPtr2,
   1.509 +		                          dwBytes2);
   1.510 +	}
   1.511 +
   1.512 +	soundNextPosition += soundBufferLen;
   1.513 +	soundNextPosition %= soundBufferTotalLen;
   1.514 +}
   1.515 +
   1.516 +void DirectSound::clearAudioBuffer()
   1.517 +{
   1.518 +	LPVOID	lpvPtr1;
   1.519 +	DWORD	dwBytes1;
   1.520 +	LPVOID	lpvPtr2;
   1.521 +	DWORD	dwBytes2;
   1.522 +	HRESULT hr = dsbSecondary->Lock(0, soundBufferTotalLen, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
   1.523 +	if (!FAILED(hr))
   1.524 +	{
   1.525 +		if (lpvPtr1)
   1.526 +			memset(lpvPtr1, 0, dwBytes1);
   1.527 +		if (lpvPtr2)
   1.528 +			memset(lpvPtr2, 0, dwBytes2);
   1.529 +		hr = dsbSecondary->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
   1.530 +	}
   1.531 +}
   1.532 +
   1.533 +ISound *newDirectSound()
   1.534 +{
   1.535 +	return new DirectSound();
   1.536 +}
   1.537 +