2018-12-18 13:59:11 +00:00
# ifndef NO_FAUDIO
2018-12-18 04:20:29 +00:00
// Application
# include "wxvbam.h"
# include <stdio.h>
// Interface
# include "../common/ConfigManager.h"
# include "../common/SoundDriver.h"
2018-12-25 20:29:11 +00:00
// FAudio
2018-12-18 04:20:29 +00:00
# include <faudio.h>
// MMDevice API
# include <mmdeviceapi.h>
# include <string>
# include <vector>
// Internals
# include "../System.h" // for systemMessage()
# include "../gba/Globals.h"
2018-12-18 15:46:45 +00:00
int GetFADevices ( FAudio * fa , wxArrayString * names , wxArrayString * ids ,
2018-12-18 04:20:29 +00:00
const wxString * match )
{
HRESULT hr ;
UINT32 dev_count = 0 ;
2018-12-25 20:29:11 +00:00
hr = FAudio_GetDeviceCount ( fa , & dev_count ) ;
2018-12-18 04:20:29 +00:00
if ( hr ! = S_OK ) {
2018-12-18 13:59:11 +00:00
wxLogError ( _ ( " FAudio: Enumerating devices failed! " ) ) ;
2018-12-18 04:20:29 +00:00
return true ;
} else {
2018-12-25 20:29:11 +00:00
FAudioDeviceDetails dd ;
2018-12-18 04:20:29 +00:00
for ( UINT32 i = 0 ; i < dev_count ; i + + ) {
2018-12-25 20:29:11 +00:00
hr = FAudio_GetDeviceDetails ( fa , i , & dd ) ;
2018-12-18 04:20:29 +00:00
if ( hr ! = S_OK ) {
continue ;
} else {
if ( ids ) {
2018-12-25 20:40:14 +00:00
ids - > push_back ( ( wchar_t * ) dd . DeviceID ) ; //FAudio is an interesting beast, but not that hard to adapt... once you get used to it, XAudio2 wouldn't need this, but FAudio declares FAudioDeviceDetails as int32_t
2018-12-25 20:29:11 +00:00
names - > push_back ( ( wchar_t * ) dd . DisplayName ) ;
2018-12-18 04:20:29 +00:00
} else if ( * match = = dd . DeviceID )
return i ;
}
}
}
return - 1 ;
}
2018-12-18 15:46:45 +00:00
bool GetFADevices ( wxArrayString & names , wxArrayString & ids )
2018-12-18 04:20:29 +00:00
{
HRESULT hr ;
2018-12-18 13:59:11 +00:00
FAudio * fa = NULL ;
2018-12-18 04:20:29 +00:00
UINT32 flags = 0 ;
# ifdef _DEBUG
flags = FAUDIO_DEBUG_ENGINE ;
# endif
2018-12-25 20:40:14 +00:00
hr = FAudioCreate ( & fa , flags , FAUDIO_DEFAULT_PROCESSOR ) ; //Apparently this needs 3 parameters, the processor.
2018-12-18 04:20:29 +00:00
if ( hr ! = S_OK ) {
2018-12-18 13:59:11 +00:00
wxLogError ( _ ( " The FAudio interface failed to initialize! " ) ) ;
2018-12-18 04:20:29 +00:00
return false ;
}
2018-12-18 15:46:45 +00:00
GetFADevices ( fa , & names , & ids , NULL ) ;
2018-12-25 21:07:12 +00:00
//fa->Release();
FAudio_Release ( fa ) ;
2018-12-18 04:20:29 +00:00
return true ;
}
2018-12-18 15:46:45 +00:00
static int FAGetDev ( FAudio * fa )
2018-12-18 04:20:29 +00:00
{
if ( gopts . audio_dev . empty ( ) )
return 0 ;
else {
2018-12-18 15:46:45 +00:00
int ret = GetFADevices ( fa , NULL , NULL , & gopts . audio_dev ) ;
2018-12-18 04:20:29 +00:00
return ret < 0 ? 0 : ret ;
}
}
2018-12-18 13:59:11 +00:00
class FAudio_Output ;
2018-12-18 04:20:29 +00:00
2018-12-18 13:59:11 +00:00
static void faudio_device_changed ( FAudio_Output * ) ;
2018-12-18 04:20:29 +00:00
2018-12-18 13:59:11 +00:00
class FAudio_Device_Notifier : public IMMNotificationClient {
2018-12-18 04:20:29 +00:00
volatile LONG registered ;
IMMDeviceEnumerator * pEnumerator ;
std : : wstring last_device ;
CRITICAL_SECTION lock ;
2018-12-18 13:59:11 +00:00
std : : vector < FAudio_Output * > instances ;
2018-12-18 04:20:29 +00:00
public :
2018-12-18 13:59:11 +00:00
FAudio_Device_Notifier ( )
2018-12-18 04:20:29 +00:00
: registered ( 0 )
{
InitializeCriticalSection ( & lock ) ;
}
2018-12-18 13:59:11 +00:00
~ FAudio_Device_Notifier ( )
2018-12-18 04:20:29 +00:00
{
DeleteCriticalSection ( & lock ) ;
}
ULONG STDMETHODCALLTYPE AddRef ( )
{
return 1 ;
}
ULONG STDMETHODCALLTYPE Release ( )
{
return 1 ;
}
HRESULT STDMETHODCALLTYPE QueryInterface ( REFIID riid , VOID * * ppvInterface )
{
if ( IID_IUnknown = = riid ) {
* ppvInterface = ( IUnknown * ) this ;
} else if ( __uuidof ( IMMNotificationClient ) = = riid ) {
* ppvInterface = ( IMMNotificationClient * ) this ;
} else {
* ppvInterface = NULL ;
return E_NOINTERFACE ;
}
return S_OK ;
}
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged ( EDataFlow flow , ERole role , LPCWSTR pwstrDeviceId )
{
if ( flow = = eRender & & last_device . compare ( pwstrDeviceId ) ! = 0 ) {
last_device = pwstrDeviceId ;
EnterCriticalSection ( & lock ) ;
for ( auto it = instances . begin ( ) ; it < instances . end ( ) ; + + it ) {
2018-12-18 13:59:11 +00:00
faudio_device_changed ( * it ) ;
2018-12-18 04:20:29 +00:00
}
LeaveCriticalSection ( & lock ) ;
}
return S_OK ;
}
HRESULT STDMETHODCALLTYPE OnDeviceAdded ( LPCWSTR pwstrDeviceId ) { return S_OK ; }
HRESULT STDMETHODCALLTYPE OnDeviceRemoved ( LPCWSTR pwstrDeviceId ) { return S_OK ; }
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged ( LPCWSTR pwstrDeviceId , DWORD dwNewState ) { return S_OK ; }
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged ( LPCWSTR pwstrDeviceId , const PROPERTYKEY key ) { return S_OK ; }
2018-12-18 13:59:11 +00:00
void do_register ( FAudio_Output * p_instance )
2018-12-18 04:20:29 +00:00
{
if ( InterlockedIncrement ( & registered ) = = 1 ) {
pEnumerator = NULL ;
HRESULT hr = CoCreateInstance ( __uuidof ( MMDeviceEnumerator ) , NULL , CLSCTX_INPROC_SERVER , __uuidof ( IMMDeviceEnumerator ) , ( void * * ) & pEnumerator ) ;
if ( SUCCEEDED ( hr ) ) {
pEnumerator - > RegisterEndpointNotificationCallback ( this ) ;
}
}
EnterCriticalSection ( & lock ) ;
instances . push_back ( p_instance ) ;
LeaveCriticalSection ( & lock ) ;
}
2018-12-18 13:59:11 +00:00
void do_unregister ( FAudio_Output * p_instance )
2018-12-18 04:20:29 +00:00
{
if ( InterlockedDecrement ( & registered ) = = 0 ) {
if ( pEnumerator ) {
pEnumerator - > UnregisterEndpointNotificationCallback ( this ) ;
pEnumerator - > Release ( ) ;
pEnumerator = NULL ;
}
}
EnterCriticalSection ( & lock ) ;
for ( auto it = instances . begin ( ) ; it < instances . end ( ) ; + + it ) {
if ( * it = = p_instance ) {
instances . erase ( it ) ;
break ;
}
}
LeaveCriticalSection ( & lock ) ;
}
} g_notifier ;
// Synchronization Event
2018-12-18 13:59:11 +00:00
class FAudio_BufferNotify : public FAudioVoiceCallback {
2018-12-18 04:20:29 +00:00
public :
HANDLE hBufferEndEvent ;
2018-12-18 13:59:11 +00:00
FAudio_BufferNotify ( )
2018-12-18 04:20:29 +00:00
{
hBufferEndEvent = NULL ;
hBufferEndEvent = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
assert ( hBufferEndEvent ! = NULL ) ;
}
2018-12-18 13:59:11 +00:00
~ FAudio_BufferNotify ( )
2018-12-18 04:20:29 +00:00
{
CloseHandle ( hBufferEndEvent ) ;
hBufferEndEvent = NULL ;
}
STDMETHOD_ ( void , OnBufferEnd )
( void * pBufferContext )
{
assert ( hBufferEndEvent ! = NULL ) ;
SetEvent ( hBufferEndEvent ) ;
}
// dummies:
STDMETHOD_ ( void , OnVoiceProcessingPassStart )
( UINT32 BytesRequired ) { }
STDMETHOD_ ( void , OnVoiceProcessingPassEnd )
( ) { }
STDMETHOD_ ( void , OnStreamEnd )
( ) { }
STDMETHOD_ ( void , OnBufferStart )
( void * pBufferContext ) { }
STDMETHOD_ ( void , OnLoopEnd )
( void * pBufferContext ) { }
STDMETHOD_ ( void , OnVoiceError )
( void * pBufferContext , HRESULT Error ) { } ;
} ;
// Class Declaration
2018-12-18 13:59:11 +00:00
class FAudio_Output
2018-12-18 04:20:29 +00:00
: public SoundDriver {
public :
2018-12-18 13:59:11 +00:00
FAudio_Output ( ) ;
~ FAudio_Output ( ) ;
2018-12-18 04:20:29 +00:00
// Initialization
bool init ( long sampleRate ) ;
// Sound Data Feed
void write ( uint16_t * finalWave , int length ) ;
// Play Control
void pause ( ) ;
void resume ( ) ;
void reset ( ) ;
void close ( ) ;
void device_change ( ) ;
// Configuration Changes
void setThrottle ( unsigned short throttle ) ;
private :
bool failed ;
bool initialized ;
bool playing ;
UINT32 freq ;
UINT32 bufferCount ;
BYTE * buffers ;
int currentBuffer ;
int soundBufferLen ;
volatile bool device_changed ;
2018-12-18 13:59:11 +00:00
FAudio * faud ;
FAudioMasteringVoice * mVoice ; // listener
FAudioSourceVoice * sVoice ; // sound source
FAudioBuffer buf ;
FAudioVoiceState vState ;
FAudio_BufferNotify notify ; // buffer end notification
2018-12-18 04:20:29 +00:00
} ;
// Class Implementation
2018-12-18 13:59:11 +00:00
FAudio_Output : : FAudio_Output ( )
2018-12-18 04:20:29 +00:00
{
failed = false ;
initialized = false ;
playing = false ;
freq = 0 ;
bufferCount = gopts . audio_buffers ;
buffers = NULL ;
currentBuffer = 0 ;
device_changed = false ;
2018-12-18 13:59:11 +00:00
faud = NULL ;
2018-12-18 04:20:29 +00:00
mVoice = NULL ;
sVoice = NULL ;
ZeroMemory ( & buf , sizeof ( buf ) ) ;
ZeroMemory ( & vState , sizeof ( vState ) ) ;
g_notifier . do_register ( this ) ;
}
2018-12-18 13:59:11 +00:00
FAudio_Output : : ~ FAudio_Output ( )
2018-12-18 04:20:29 +00:00
{
g_notifier . do_unregister ( this ) ;
close ( ) ;
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : close ( )
2018-12-18 04:20:29 +00:00
{
initialized = false ;
if ( sVoice ) {
if ( playing ) {
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_Stop ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
}
2018-12-25 22:47:21 +00:00
FAudioVoice_DestroyVoice ( sVoice ) ;
2018-12-18 04:20:29 +00:00
sVoice = NULL ;
}
if ( buffers ) {
free ( buffers ) ;
buffers = NULL ;
}
if ( mVoice ) {
2018-12-25 22:47:21 +00:00
FAudioVoice_DestroyVoice ( mVoice ) ;
2018-12-18 04:20:29 +00:00
mVoice = NULL ;
}
2018-12-18 13:59:11 +00:00
if ( faud ) {
2018-12-25 22:31:22 +00:00
FAudio_Release ( faud ) ;
2018-12-18 13:59:11 +00:00
faud = NULL ;
2018-12-18 04:20:29 +00:00
}
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : device_change ( )
2018-12-18 04:20:29 +00:00
{
device_changed = true ;
}
2018-12-18 13:59:11 +00:00
bool FAudio_Output : : init ( long sampleRate )
2018-12-18 04:20:29 +00:00
{
if ( failed | | initialized )
return false ;
HRESULT hr ;
2018-12-18 13:59:11 +00:00
// Initialize FAudio
2018-12-18 04:20:29 +00:00
UINT32 flags = 0 ;
//#ifdef _DEBUG
2018-12-18 13:59:11 +00:00
// flags = FAUDIO_DEBUG_ENGINE;
2018-12-18 04:20:29 +00:00
//#endif
2018-12-25 22:31:22 +00:00
hr = FAudioCreate ( & faud , flags , FAUDIO_DEFAULT_CHANNELS ) ;
2018-12-18 04:20:29 +00:00
if ( hr ! = S_OK ) {
2018-12-18 13:59:11 +00:00
wxLogError ( _ ( " The FAudio interface failed to initialize! " ) ) ;
2018-12-18 04:20:29 +00:00
failed = true ;
return false ;
}
freq = sampleRate ;
// 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 to store sound data because it must not be
// manipulated while the voice plays from it
buffers = ( BYTE * ) malloc ( ( bufferCount + 1 ) * soundBufferLen ) ;
// + 1 because we need one temporary buffer when all others are in use
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
2018-12-25 22:47:21 +00:00
hr = FAudio_CreateMasteringVoice (
faud ,
2018-12-18 04:20:29 +00:00
& mVoice ,
2018-12-18 13:59:11 +00:00
FAUDIO_DEFAULT_CHANNELS ,
FAUDIO_DEFAULT_SAMPLERATE ,
2018-12-18 04:20:29 +00:00
0 ,
2018-12-18 13:59:11 +00:00
FAGetDev ( faud ) ,
2018-12-18 04:20:29 +00:00
NULL ) ;
if ( hr ! = S_OK ) {
2018-12-18 13:59:11 +00:00
wxLogError ( _ ( " FAudio: Creating mastering voice failed! " ) ) ;
2018-12-18 04:20:29 +00:00
failed = true ;
return false ;
}
2018-12-25 22:31:22 +00:00
// create sound emitter
//This should be FAudio_CreateSourceVoice()
//hr = faud->CreateSourceVoice(&sVoice, &wfx, 0, 4.0f, ¬ify);
2018-12-25 23:48:55 +00:00
hr = FAudio_CreateSourceVoice ( faud , & sVoice , ( const FAudioWaveFormatEx * ) & wfx , 0 , 4.0f , & notify ) ;
2018-12-18 04:20:29 +00:00
if ( hr ! = S_OK ) {
2018-12-18 13:59:11 +00:00
wxLogError ( _ ( " FAudio: Creating source voice failed! " ) ) ;
2018-12-18 04:20:29 +00:00
failed = true ;
return false ;
}
if ( gopts . upmix ) {
// set up stereo upmixing
2018-12-18 13:59:11 +00:00
FAudioDeviceDetails dd ;
2018-12-18 04:20:29 +00:00
ZeroMemory ( & dd , sizeof ( dd ) ) ;
2018-12-25 22:47:21 +00:00
hr = FAudio_GetDeviceDetails ( faud , 0 , & dd ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
float * matrix = NULL ;
matrix = ( float * ) malloc ( sizeof ( float ) * 2 * dd . OutputFormat . Format . nChannels ) ;
if ( matrix = = NULL )
return false ;
bool matrixAvailable = true ;
switch ( dd . OutputFormat . Format . nChannels ) {
case 4 : // 4.0
//Speaker \ Left Source Right Source
/*Front L*/ matrix [ 0 ] = 1.0000f ;
matrix [ 1 ] = 0.0000f ;
/*Front R*/ matrix [ 2 ] = 0.0000f ;
matrix [ 3 ] = 1.0000f ;
/*Back L*/ matrix [ 4 ] = 1.0000f ;
matrix [ 5 ] = 0.0000f ;
/*Back R*/ matrix [ 6 ] = 0.0000f ;
matrix [ 7 ] = 1.0000f ;
break ;
case 5 : // 5.0
//Speaker \ Left Source Right Source
/*Front L*/ matrix [ 0 ] = 1.0000f ;
matrix [ 1 ] = 0.0000f ;
/*Front R*/ matrix [ 2 ] = 0.0000f ;
matrix [ 3 ] = 1.0000f ;
/*Front C*/ matrix [ 4 ] = 0.7071f ;
matrix [ 5 ] = 0.7071f ;
/*Side L*/ matrix [ 6 ] = 1.0000f ;
matrix [ 7 ] = 0.0000f ;
/*Side R*/ matrix [ 8 ] = 0.0000f ;
matrix [ 9 ] = 1.0000f ;
break ;
case 6 : // 5.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix [ 0 ] = 1.0000f ;
matrix [ 1 ] = 0.0000f ;
/*Front R*/ matrix [ 2 ] = 0.0000f ;
matrix [ 3 ] = 1.0000f ;
/*Front C*/ matrix [ 4 ] = 0.7071f ;
matrix [ 5 ] = 0.7071f ;
/*LFE */ matrix [ 6 ] = 0.0000f ;
matrix [ 7 ] = 0.0000f ;
/*Side L*/ matrix [ 8 ] = 1.0000f ;
matrix [ 9 ] = 0.0000f ;
/*Side R*/ matrix [ 10 ] = 0.0000f ;
matrix [ 11 ] = 1.0000f ;
break ;
case 7 : // 6.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix [ 0 ] = 1.0000f ;
matrix [ 1 ] = 0.0000f ;
/*Front R*/ matrix [ 2 ] = 0.0000f ;
matrix [ 3 ] = 1.0000f ;
/*Front C*/ matrix [ 4 ] = 0.7071f ;
matrix [ 5 ] = 0.7071f ;
/*LFE */ matrix [ 6 ] = 0.0000f ;
matrix [ 7 ] = 0.0000f ;
/*Side L*/ matrix [ 8 ] = 1.0000f ;
matrix [ 9 ] = 0.0000f ;
/*Side R*/ matrix [ 10 ] = 0.0000f ;
matrix [ 11 ] = 1.0000f ;
/*Back C*/ matrix [ 12 ] = 0.7071f ;
matrix [ 13 ] = 0.7071f ;
break ;
case 8 : // 7.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix [ 0 ] = 1.0000f ;
matrix [ 1 ] = 0.0000f ;
/*Front R*/ matrix [ 2 ] = 0.0000f ;
matrix [ 3 ] = 1.0000f ;
/*Front C*/ matrix [ 4 ] = 0.7071f ;
matrix [ 5 ] = 0.7071f ;
/*LFE */ matrix [ 6 ] = 0.0000f ;
matrix [ 7 ] = 0.0000f ;
/*Back L*/ matrix [ 8 ] = 1.0000f ;
matrix [ 9 ] = 0.0000f ;
/*Back R*/ matrix [ 10 ] = 0.0000f ;
matrix [ 11 ] = 1.0000f ;
/*Side L*/ matrix [ 12 ] = 1.0000f ;
matrix [ 13 ] = 0.0000f ;
/*Side R*/ matrix [ 14 ] = 0.0000f ;
matrix [ 15 ] = 1.0000f ;
break ;
default :
matrixAvailable = false ;
break ;
}
if ( matrixAvailable ) {
2018-12-25 23:48:55 +00:00
hr = FAudioVoice_SetOutputMatrix ( sVoice , NULL , 2 , dd . OutputFormat . Format . nChannels , matrix , FAUDIO_DEFAULT_CHANNELS ) ; //What I have here for the OperationSet maybe wrong...
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
}
free ( matrix ) ;
matrix = NULL ;
}
2018-12-25 23:48:55 +00:00
hr = FAudioSourceVoice_Start ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
playing = true ;
currentBuffer = 0 ;
device_changed = false ;
initialized = true ;
return true ;
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : write ( uint16_t * finalWave , int length )
2018-12-25 23:48:55 +00:00
{
UINT32 flags = 0 ;
2018-12-18 04:20:29 +00:00
if ( ! initialized | | failed )
return ;
while ( true ) {
if ( device_changed ) {
close ( ) ;
if ( ! init ( freq ) )
return ;
}
2018-12-25 23:48:55 +00:00
FAudioSourceVoice_GetState ( sVoice , & vState , flags ) ;
2018-12-18 04:20:29 +00:00
assert ( vState . BuffersQueued < = bufferCount ) ;
if ( vState . BuffersQueued < bufferCount ) {
if ( vState . BuffersQueued = = 0 ) {
// buffers ran dry
if ( systemVerbose & VERBOSE_SOUNDOUTPUT ) {
static unsigned int i = 0 ;
2018-12-18 13:59:11 +00:00
log ( " FAudio: Buffers were not refilled fast enough (i=%i) \n " , i + + ) ;
2018-12-18 04:20:29 +00:00
}
}
// there is at least one free buffer
break ;
} else {
// the maximum number of buffers is currently queued
if ( ! speedup & & throttle & & ! gba_joybus_active ) {
// wait for one buffer to finish playing
if ( WaitForSingleObject ( notify . hBufferEndEvent , 10000 ) = = WAIT_TIMEOUT ) {
device_changed = true ;
}
} else {
// drop current audio frame
return ;
}
}
}
// copy & protect the audio data in own memory area while playing it
CopyMemory ( & buffers [ currentBuffer * soundBufferLen ] , finalWave , soundBufferLen ) ;
buf . AudioBytes = soundBufferLen ;
buf . pAudioData = & buffers [ currentBuffer * soundBufferLen ] ;
currentBuffer + + ;
currentBuffer % = ( bufferCount + 1 ) ; // + 1 because we need one temporary buffer
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_SubmitSourceBuffer ( sVoice , & buf ) ; // send buffer to queue.
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : pause ( )
2018-12-18 04:20:29 +00:00
{
if ( ! initialized | | failed )
return ;
if ( playing ) {
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_Stop ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
playing = false ;
}
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : resume ( )
2018-12-18 04:20:29 +00:00
{
if ( ! initialized | | failed )
return ;
if ( ! playing ) {
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_Start ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
playing = true ;
}
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : reset ( )
2018-12-18 04:20:29 +00:00
{
if ( ! initialized | | failed )
return ;
if ( playing ) {
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_Stop ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
}
2018-12-25 22:47:21 +00:00
FAudioSourceVoice_FlushSourceBuffers ( sVoice ) ;
2018-12-25 23:48:55 +00:00
FAudioSourceVoice_Start ( sVoice , 0 , FAUDIO_COMMIT_NOW ) ;
2018-12-18 04:20:29 +00:00
playing = true ;
}
2018-12-18 13:59:11 +00:00
void FAudio_Output : : setThrottle ( unsigned short throttle_ )
2018-12-18 04:20:29 +00:00
{
if ( ! initialized | | failed )
return ;
if ( throttle_ = = 0 )
throttle_ = 100 ;
2018-12-25 23:48:55 +00:00
HRESULT hr = FAudioSourceVoice_SetFrequencyRatio ( sVoice , ( float ) throttle_ / 100.0f , FAUDIO_MAX_FILTER_FREQUENCY ) ;
2018-12-18 04:20:29 +00:00
assert ( hr = = S_OK ) ;
}
2018-12-18 13:59:11 +00:00
void faudio_device_changed ( FAudio_Output * instance )
2018-12-18 04:20:29 +00:00
{
instance - > device_change ( ) ;
}
2018-12-18 13:59:11 +00:00
SoundDriver * newFAudio_Output ( )
2018-12-18 04:20:29 +00:00
{
2018-12-18 13:59:11 +00:00
return new FAudio_Output ( ) ;
2018-12-18 04:20:29 +00:00
}
2018-12-18 13:59:11 +00:00
# endif // #ifndef NO_FAUDIO