ADDED sound output using Microsoft's new XAudio2 API

This commit is contained in:
spacy51 2008-03-09 14:01:34 +00:00
parent 8359ac8351
commit 8c9a679eca
12 changed files with 410 additions and 67 deletions

View File

@ -901,6 +901,10 @@
RelativePath=".\src\win32\OpenGL.cpp"
>
</File>
<File
RelativePath=".\src\win32\XAudio2.cpp"
>
</File>
</Filter>
<Filter
Name="Linking"
@ -1438,36 +1442,44 @@
</Filter>
</Filter>
<Filter
Name="Res"
Name="Resources"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\res\DevInfo.txt"
>
</File>
<File
RelativePath=".\res\gpl.txt"
>
</File>
<File
RelativePath=".\res\Known Bugs.txt"
>
</File>
<File
RelativePath=".\res\ReadMe.txt"
>
</File>
<File
RelativePath=".\src\win32\resource.h"
>
</File>
<File
RelativePath=".\src\win32\VBA-M.ico"
>
</File>
<File
RelativePath=".\src\win32\VBA.rc"
>
</File>
</Filter>
<Filter
Name="Documentation"
>
<File
RelativePath=".\src\win32\vba.rc2"
RelativePath=".\doc\authors.txt"
>
</File>
<File
RelativePath=".\doc\DevInfo.txt"
>
</File>
<File
RelativePath=".\doc\Known Bugs.txt"
>
</File>
<File
RelativePath=".\doc\ReadMe.txt"
>
</File>
<File
RelativePath=".\doc\todo.txt"
>
</File>
</Filter>

View File

@ -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)

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
};
/////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

295
src/win32/XAudio2.cpp Normal file
View File

@ -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 <Xaudio2.h>
// 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

View File

@ -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

View File

@ -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 <afxcmn.h>
#include <afxdlgs.h>
#include "VBA.h"
#include "resource.h"