diff --git a/VBA2008.vcproj b/VBA2008.vcproj
index b21bb87a..dcd7ba99 100644
--- a/VBA2008.vcproj
+++ b/VBA2008.vcproj
@@ -901,6 +901,10 @@
RelativePath=".\src\win32\OpenGL.cpp"
>
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/DevInfo.txt b/doc/DevInfo.txt
index d0f729c4..65c379f6 100644
--- a/doc/DevInfo.txt
+++ b/doc/DevInfo.txt
@@ -15,6 +15,7 @@ Known preprocessor switches:
- NO_OGL: Exclude OpenGL code
- NO_D3D: Exclude Direct3D code
- NO_OAL: Exclude OpenAL code
+- NO_XAUDIO2: Exclude XAudio2 code (supersedes DirectSound)
diff --git a/doc/Known Bugs.txt b/doc/Known Bugs.txt
index 0a7ff33f..456aabaa 100644
--- a/doc/Known Bugs.txt
+++ b/doc/Known Bugs.txt
@@ -11,7 +11,6 @@ Known Bugs:
- Audio core: assertation error occurs when disabling GB sound
- I think its best we mute sound instead, since some games rely on audio for timing.
Plus, blargg's GB_Snd_Emu is extremely optimized stuff. (Mudlord)
-- x64: Needs optimizations (x64 native code, whatever)
- Wrong bit depth image is displayed for 2 frames when switching from/to HQ3x/4x ASM
- This is caused by the 16bit hack which does not re-process the emulated image.
It results in the display devices treating the image at pix with the wrong bit depth.
\ No newline at end of file
diff --git a/src/win32/MainWnd.cpp b/src/win32/MainWnd.cpp
index 36816dfa..20fdc80f 100644
--- a/src/win32/MainWnd.cpp
+++ b/src/win32/MainWnd.cpp
@@ -434,6 +434,9 @@ BEGIN_MESSAGE_MAP(MainWnd, CWnd)
ON_WM_WINDOWPOSCHANGING()
ON_COMMAND(ID_EMULATOR_BIOSFILES, &MainWnd::OnEmulatorBiosfiles)
ON_COMMAND(ID_FILE_OPEN_GBC, &MainWnd::OnFileOpenGbc)
+ ON_WM_NCRBUTTONDOWN()
+ ON_COMMAND(ID_OUTPUTAPI_XAUDIO2, &MainWnd::OnOutputapiXaudio2)
+ ON_UPDATE_COMMAND_UI(ID_OUTPUTAPI_XAUDIO2, &MainWnd::OnUpdateOutputapiXaudio2)
END_MESSAGE_MAP()
@@ -1303,3 +1306,13 @@ void MainWnd::OnWindowPosChanging(WINDOWPOS* lpwndpos)
soundPause();
}
}
+
+void MainWnd::OnNcRButtonDown(UINT nHitTest, CPoint point)
+{
+ // pause sound before process is halted
+ if( emulating ) {
+ soundPause();
+ }
+
+ CWnd::OnNcRButtonDown(nHitTest, point);
+}
diff --git a/src/win32/MainWnd.h b/src/win32/MainWnd.h
index 16a5874a..4c56e68c 100644
--- a/src/win32/MainWnd.h
+++ b/src/win32/MainWnd.h
@@ -422,6 +422,9 @@ public:
afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos);
afx_msg void OnEmulatorBiosfiles();
afx_msg void OnFileOpenGbc();
+ afx_msg void OnNcRButtonDown(UINT nHitTest, CPoint point);
+ afx_msg void OnOutputapiXaudio2();
+ afx_msg void OnUpdateOutputapiXaudio2(CCmdUI *pCmdUI);
};
/////////////////////////////////////////////////////////////////////////////
diff --git a/src/win32/MainWndOptions.cpp b/src/win32/MainWndOptions.cpp
index 5efe3479..ef8842f0 100644
--- a/src/win32/MainWndOptions.cpp
+++ b/src/win32/MainWndOptions.cpp
@@ -1740,6 +1740,27 @@ void MainWnd::OnUpdateOutputapiDirectsound(CCmdUI *pCmdUI)
pCmdUI->Enable(!theApp.aviRecording && !theApp.soundRecording);
}
+void MainWnd::OnOutputapiXaudio2()
+{
+#ifndef NO_XAUDIO2
+ if( theApp.audioAPI != XAUDIO2 ) {
+ theApp.audioAPI = XAUDIO2;
+ systemSoundShutdown();
+ systemSoundInit();
+ }
+#endif
+}
+
+void MainWnd::OnUpdateOutputapiXaudio2(CCmdUI *pCmdUI)
+{
+#ifndef NO_XAUDIO2
+ pCmdUI->SetCheck( ( theApp.audioAPI == XAUDIO2 ) ? 1 : 0 );
+ pCmdUI->Enable(!theApp.aviRecording && !theApp.soundRecording);
+#else
+ pCmdUI->Enable( FALSE );
+#endif
+}
+
void MainWnd::OnOutputapiOpenal()
{
#ifndef NO_OAL
diff --git a/src/win32/Sound.h b/src/win32/Sound.h
index 773a44b2..dd1cebd1 100644
--- a/src/win32/Sound.h
+++ b/src/win32/Sound.h
@@ -21,9 +21,12 @@
#define VBA_WIN32_SOUND_H
enum AUDIO_API {
- DIRECTSOUND
+ DIRECTSOUND = 0
#ifndef NO_OAL
- , OPENAL_SOUND
+ , OPENAL_SOUND = 1
+#endif
+#ifndef NO_XAUDIO2
+ , XAUDIO2 = 2
#endif
};
@@ -37,6 +40,8 @@ class ISound
virtual void reset() = 0;
virtual void resume() = 0;
virtual void write() = 0;
+
+ virtual void setThrottle( unsigned short throttle ) {};
};
#endif
diff --git a/src/win32/VBA.cpp b/src/win32/VBA.cpp
index aa71e85a..11ce90cb 100644
--- a/src/win32/VBA.cpp
+++ b/src/win32/VBA.cpp
@@ -111,6 +111,9 @@ extern ISound *newDirectSound();
#ifndef NO_OAL
extern ISound *newOpenAL();
#endif
+#ifndef NO_XAUDIO2
+extern ISound *newXAudio2_Output();
+#endif
extern void remoteStubSignal(int, int);
extern void remoteOutput(char *, u32);
@@ -902,7 +905,6 @@ void VBA::updateThrottle( unsigned short throttle )
if( throttle == 0 ) {
autoFrameSkip = false;
- return;
} else {
Sm60FPS::K_fCpuSpeed = (float)throttle;
Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100;
@@ -910,7 +912,10 @@ void VBA::updateThrottle( unsigned short throttle )
autoFrameSkip = true;
frameSkip = 0;
systemFrameSkip = 0;
- return;
+ }
+
+ if( theApp.sound ) {
+ theApp.sound->setThrottle( throttle );
}
}
@@ -1197,10 +1202,21 @@ bool systemSoundInit()
case OPENAL_SOUND:
theApp.sound = newOpenAL();
break;
+#endif
+#ifndef NO_XAUDIO2
+ case XAUDIO2:
+ theApp.sound = newXAudio2_Output();
+ break;
#endif
}
- return theApp.sound->init();
+ bool retVal = theApp.sound->init();
+
+ if( retVal ) {
+ theApp.sound->setThrottle( theApp.throttle );
+ }
+
+ return retVal;
}
@@ -1448,6 +1464,9 @@ void VBA::loadSettings()
if( ( audioAPI != DIRECTSOUND )
#ifndef NO_OAL
&& ( audioAPI != OPENAL_SOUND )
+#endif
+#ifndef NO_XAUDIO2
+ && ( audioAPI != XAUDIO2 )
#endif
) {
audioAPI = DIRECTSOUND;
diff --git a/src/win32/VBA.rc b/src/win32/VBA.rc
index 28548f18..61be4139 100644
--- a/src/win32/VBA.rc
+++ b/src/win32/VBA.rc
@@ -9,39 +9,10 @@
//
#include "afxres.h"
+
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-// German (Germany) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
-#ifdef _WIN32
-LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-#endif // German (Germany) resources
-/////////////////////////////////////////////////////////////////////////////
-
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
@@ -1698,6 +1669,8 @@ BEGIN
BEGIN
MENUITEM "DirectSound", ID_OUTPUTAPI_DIRECTSOUND
MENUITEM SEPARATOR
+ MENUITEM "XAudio2", ID_OUTPUTAPI_XAUDIO2
+ MENUITEM SEPARATOR
MENUITEM "OpenAL", ID_OUTPUTAPI_OPENAL
MENUITEM " Configuration...", ID_OUTPUTAPI_OALCONFIGURATION
MENUITEM SEPARATOR
@@ -2219,6 +2192,12 @@ BEGIN
IDS_AVI_CANNOT_WRITE_VIDEO "Cannot write video frame to AVI file."
IDS_AVI_CANNOT_WRITE_AUDIO "Cannot write audio frame to AVI file."
IDS_FILTER_GBCROM "Game Boy Color ROMs_*.GBC;*.CGB;*.ZIP;*.7Z;*.Z;*.GZ__"
+ IDS_COM_FAILURE "The COM (Component Object Model) failed to initialize!"
+ IDS_XAUDIO2_FAILURE "The XAudio2 interface failed to initialize!"
+ IDS_XAUDIO2_CANNOT_CREATE_MASTERINGVOICE
+ "XAudio2: Creating mastering voice failed!"
+ IDS_XAUDIO2_CANNOT_CREATE_SOURCEVOICE
+ "XAudio2: Creating source voice failed!"
END
#endif // English (U.S.) resources
@@ -2242,7 +2221,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
2 TEXTINCLUDE
BEGIN
- "#include ""afxres.h""\r\0"
+ "#include ""afxres.h""\r\r\0"
END
#endif // APSTUDIO_INVOKED
@@ -2251,12 +2230,3 @@ END
/////////////////////////////////////////////////////////////////////////////
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/src/win32/XAudio2.cpp b/src/win32/XAudio2.cpp
new file mode 100644
index 00000000..67b64a80
--- /dev/null
+++ b/src/win32/XAudio2.cpp
@@ -0,0 +1,295 @@
+// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
+// Copyright (C) 1999-2003 Forgotten
+// Copyright (C) 2004 Forgotten and the VBA development team
+// Copyright (C) 2005-2006 VBA development team
+// Copyright (C) 2007-2008 VBA-M development team
+
+// 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; either version 2, or(at your option)
+// any later version.
+//
+// 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 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef NO_XAUDIO2
+
+
+#define NBUFFERS 4
+
+// MFC
+#include "stdafx.h"
+
+// Interface
+#include "Sound.h"
+
+// XAudio2
+#include
+
+// Internals
+#include "../Sound.h" // for soundBufferLen, soundFinalWave and soundQuality
+#include "../System.h" // for systemMessage()
+#include "../Globals.h" // for 'speedup' and 'synchronize'
+
+
+// Class Declaration
+class XAudio2_Output
+ : public ISound
+{
+public:
+ XAudio2_Output();
+ ~XAudio2_Output();
+
+ // Initialization
+ bool init();
+
+ // Sound Data Feed
+ void write();
+
+ // Play Control
+ void pause();
+ void resume();
+ void reset();
+
+ // Configuration Changes
+ void setThrottle( unsigned short throttle );
+
+
+private:
+ bool failed;
+ bool initialized;
+ bool playing;
+ UINT32 freq;
+ BYTE *buffers;
+ int currentBuffer;
+
+ IXAudio2 *xaud;
+ IXAudio2MasteringVoice *mVoice; // dest
+ IXAudio2SourceVoice *sVoice; // source
+ XAUDIO2_BUFFER buf;
+ XAUDIO2_VOICE_STATE vState;
+};
+
+
+// Class Implementation
+XAudio2_Output::XAudio2_Output()
+{
+ failed = false;
+ initialized = false;
+ playing = false;
+ freq = 0;
+ buffers = 0;
+ currentBuffer = 0;
+
+ xaud = NULL;
+ mVoice = NULL;
+ sVoice = NULL;
+ ZeroMemory( &buf, sizeof( buf ) );
+ ZeroMemory( &vState, sizeof( vState ) );
+
+ if( S_OK != CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) {
+ systemMessage( IDS_COM_FAILURE, NULL );
+ failed = true;
+ return;
+ }
+}
+
+
+XAudio2_Output::~XAudio2_Output()
+{
+ initialized = false;
+
+ if( sVoice ) {
+ if( playing ) {
+ sVoice->Stop( 0 );
+ }
+ sVoice->DestroyVoice();
+ }
+
+ if( buffers ) {
+ free( buffers );
+ }
+
+ if( mVoice ) {
+ mVoice->DestroyVoice();
+ }
+
+ if( xaud ) {
+ xaud->Release();
+ }
+
+ CoUninitialize();
+}
+
+
+bool XAudio2_Output::init()
+{
+ if( failed || initialized ) return false;
+
+ HRESULT hr;
+ UINT32 flags = 0;
+
+#ifdef _DEBUG
+ flags |= XAUDIO2_DEBUG_ENGINE;
+#endif
+
+ hr = XAudio2Create( &xaud, flags );
+
+ if( FAILED( hr ) ) {
+ systemMessage( IDS_XAUDIO2_FAILURE, NULL );
+ failed = true;
+ return false;
+ }
+
+
+ freq = 44100 / (UINT32)soundQuality;
+
+ // calculate the number of samples per frame first
+ // then multiply it with the size of a sample frame (16 bit * stereo)
+ soundBufferLen = ( freq / 60 ) * 4;
+
+ // create own buffers because sound data must not be manipulated
+ // by the audio emulation core while it is still being played back
+ buffers = (BYTE *)malloc( ( NBUFFERS + 1 ) * soundBufferLen );
+ // + 1 because we need one temporary buffer when all others are still playing
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof( wfx ) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = 2;
+ wfx.nSamplesPerSec = freq;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = wfx.nChannels * ( wfx.wBitsPerSample / 8 );
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+
+ // Create Sound Receiver
+ hr = xaud->CreateMasteringVoice( &mVoice, 2, freq );
+
+ if( FAILED( hr ) ) {
+ systemMessage( IDS_XAUDIO2_CANNOT_CREATE_MASTERINGVOICE, NULL );
+ failed = true;
+ return false;
+ }
+
+
+ // Create Sound Emitter
+ hr = xaud->CreateSourceVoice( &sVoice, &wfx, 0, XAUDIO2_MAX_FREQ_RATIO );
+
+ if( FAILED( hr ) ) {
+ systemMessage( IDS_XAUDIO2_CANNOT_CREATE_SOURCEVOICE, NULL );
+ failed = true;
+ return false;
+ }
+
+ sVoice->Start( 0 );
+ playing = true;
+
+
+ setsystemSoundOn( true );
+ initialized = true;
+ return true;
+}
+
+
+void XAudio2_Output::write()
+{
+ if( !initialized || failed ) return;
+
+ bool drop = false;
+
+ // copy & protect the audio data in own memory area while playing it
+ CopyMemory( &buffers[ currentBuffer * soundBufferLen ], soundFinalWave, soundBufferLen );
+
+ buf.AudioBytes = soundBufferLen;
+ buf.pAudioData = &buffers[ currentBuffer * soundBufferLen ];
+
+ currentBuffer++;
+ currentBuffer %= ( NBUFFERS + 1 );
+
+ while( true ) {
+ sVoice->GetState( &vState );
+ ASSERT( vState.BuffersQueued <= NBUFFERS );
+
+ if( vState.BuffersQueued == NBUFFERS ) {
+ // all buffers filled
+ if( speedup || !synchronize || theApp.throttle ) {
+ drop = true;
+ break;
+ }
+
+ if( synchronize ) {
+ // wait for about half the time one buffer needs to finish
+ // unoptimized: ( sourceBufferLen * 1000 ) / ( freq * 2 * 2 ) * 1/2
+ Sleep( soundBufferLen / ( freq >> 7 ) );
+ }
+ } else {
+ // still room for new audio
+ break;
+ }
+ }
+
+ if( !drop ) {
+ // add the sound buffer to the queue
+ sVoice->SubmitSourceBuffer( &buf );
+ }
+}
+
+
+void XAudio2_Output::pause()
+{
+ if( !initialized || failed ) return;
+
+ if( playing ) {
+ sVoice->Stop( 0 );
+ playing = false;
+ }
+}
+
+
+void XAudio2_Output::resume()
+{
+ if( !initialized || failed ) return;
+
+ if( !playing ) {
+ sVoice->Start( 0 );
+ playing = true;
+ }
+}
+
+
+void XAudio2_Output::reset()
+{
+ if( !initialized || failed ) return;
+
+ if( playing ) {
+ sVoice->Stop( 0 );
+ }
+
+ sVoice->FlushSourceBuffers();
+ sVoice->Start( 0 );
+ playing = true;
+}
+
+
+void XAudio2_Output::setThrottle( unsigned short throttle )
+{
+ if( throttle == 0 ) throttle = 100;
+ sVoice->SetFrequencyRatio( (float)throttle / 100.0f );
+}
+
+
+ISound *newXAudio2_Output()
+{
+ return new XAudio2_Output();
+}
+
+
+#endif // #ifndef NO_XAUDIO2
diff --git a/src/win32/resource.h b/src/win32/resource.h
index ba81ee1a..a9b4a259 100644
--- a/src/win32/resource.h
+++ b/src/win32/resource.h
@@ -538,6 +538,10 @@
#define IDS_AVI_CANNOT_WRITE_VIDEO 2005
#define IDS_AVI_CANNOT_WRITE_AUDIO 2006
#define IDS_FILTER_GBCROM 2007
+#define IDS_COM_FAILURE 2008
+#define IDS_XAUDIO2_FAILURE 2009
+#define IDS_XAUDIO2_CANNOT_CREATE_MASTERINGVOICE 2010
+#define IDS_XAUDIO2_CANNOT_CREATE_SOURCEVOICE 2011
#define ID_HELP_ABOUT 40001
#define ID_FILE_EXIT 40002
#define ID_OPTIONS_VIDEO_FRAMESKIP_0 40003
@@ -845,13 +849,14 @@
#define ID_EMULATOR_BIOSFILES 40356
#define ID_FILE_OPENGBC 40357
#define ID_FILE_OPEN_GBC 40358
+#define ID_OUTPUTAPI_XAUDIO2 40359
// Next default values for new objects
-//
+//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 163
-#define _APS_NEXT_COMMAND_VALUE 40359
+#define _APS_NEXT_COMMAND_VALUE 40360
#define _APS_NEXT_CONTROL_VALUE 1284
#define _APS_NEXT_SYMED_VALUE 103
#endif
diff --git a/src/win32/stdafx.h b/src/win32/stdafx.h
index 29146ff2..77c15e38 100644
--- a/src/win32/stdafx.h
+++ b/src/win32/stdafx.h
@@ -26,7 +26,6 @@
// Target for Windows 2000 (Required by GetMenuBar and other functions)
#define NTDDI_VERSION NTDDI_WIN2K // new
#define _WIN32_WINNT 0x0500 // old
-//#define WINVER 0x0500
// Enable STRICT type checking
#define STRICT
@@ -36,3 +35,4 @@
#include
#include
#include "VBA.h"
+#include "resource.h"