medfall

A super great game engine
Log | Files | Refs

win32_audio_output.cc (3808B)


      1 // https://github.com/walbourn/directx-sdk-samples/blob/master/XAudio2/XAudio2AsyncStream/XAudio2AsyncStream.cpp
      2 
      3 #include <windows.h>
      4 #include <wrl/client.h>
      5 #include <comdecl.h>
      6 
      7 #pragma warning( push )
      8 #pragma warning( disable : 4800 )
      9 #include <xaudio2.h>
     10 #pragma warning( pop )
     11 
     12 #include "intrinsics.h"
     13 #include "log.h"
     14 #include "platform_audio_output.h"
     15 #include "platform_library.h"
     16 #include "platform_thread.h"
     17 #include "platform_atomic.h"
     18 
     19 struct XAudioCallbacks : public IXAudio2VoiceCallback {
     20 	void __stdcall OnBufferEnd( void * data ) {
     21 		HANDLE event = ( HANDLE ) data;
     22 		SetEvent( event );
     23 	}
     24 
     25 	void __stdcall OnBufferStart( void * ) { }
     26 	void __stdcall OnLoopEnd( void * ) { }
     27 	void __stdcall OnStreamEnd() { }
     28 	void __stdcall OnVoiceError( void *, HRESULT ) { }
     29 	void __stdcall OnVoiceProcessingPassStart( u32 ) { }
     30 	void __stdcall OnVoiceProcessingPassEnd() { }
     31 };
     32 
     33 static Library xaudio2_lib = NULL;
     34 
     35 static IXAudio2 * xaudio2 = NULL;
     36 static IXAudio2MasteringVoice * mastering_voice = NULL;
     37 
     38 static XAudioCallbacks callbacks;
     39 
     40 void audio_output_init() {
     41 	if( FAILED( CoInitializeEx( nullptr, COINIT_MULTITHREADED ) ) ) {
     42 		FATAL( "CoInitializeEx" );
     43 	}
     44 
     45 	xaudio2_lib = library_open( "XAudio2_7.dll" );
     46 	if( xaudio2_lib == NULL ) {
     47 		FATAL( "Couldn't open XAudio2_7.dll: {}", library_last_error() );
     48 	}
     49 
     50 	if( FAILED( XAudio2Create( &xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR ) ) ) {
     51 		FATAL( "XAudio2Create" );
     52 	}
     53 
     54 	if( FAILED( xaudio2->CreateMasteringVoice( &mastering_voice ) ) ) {
     55 		FATAL( "CreateMasteringVoice" );
     56 	}
     57 }
     58 
     59 void audio_output_term() {
     60 	xaudio2->StopEngine();
     61 	mastering_voice->DestroyVoice();
     62 	xaudio2->Release();
     63 	library_close( xaudio2_lib );
     64 	CoUninitialize();
     65 
     66 	xaudio2_lib = NULL;
     67 	xaudio2 = NULL;
     68 	mastering_voice = NULL;
     69 }
     70 
     71 static THREAD( audio_output_thread ) {
     72 	AudioOutputDevice * device = ( AudioOutputDevice * ) data;
     73 
     74 	while( load_acquire( &device->shutting_down ) == 0 ) {
     75 		constexpr u32 num_samples = 512;
     76 		STATIC_ASSERT( ARRAY_COUNT( device->buffer.samples ) % num_samples == 0 );
     77 
     78 		for( ;; ) {
     79 			XAUDIO2_VOICE_STATE state;
     80 			device->voice->GetState( &state );
     81 			if( state.BuffersQueued < 2 ) {
     82 				break;
     83 			}
     84 
     85 			WaitForSingleObject( device->event, INFINITE );
     86 		}
     87 
     88 		u32 cursor = load_acquire( &device->buffer.cursor );
     89 
     90 		XAUDIO2_BUFFER buf = { };
     91 		buf.AudioBytes = num_samples * sizeof( device->buffer.samples[ 0 ] );
     92 		buf.pAudioData = ( const BYTE * )( device->buffer.samples + cursor );
     93 		buf.pContext = device->event;
     94 
     95 		if( FAILED( device->voice->SubmitSourceBuffer( &buf ) ) ) {
     96 			FATAL( "SubmitSourceBuffer" );
     97 		}
     98 
     99 		store_release( &device->buffer.cursor, ( cursor + num_samples ) % ARRAY_COUNT( device->buffer.samples ) );
    100 	}
    101 
    102 	THREAD_END;
    103 }
    104 
    105 void audio_output_open( AudioOutputDevice * device ) {
    106 	WAVEFORMATEX format = { };
    107 	format.wFormatTag = WAVE_FORMAT_PCM;
    108 	format.nChannels = 1;
    109 	format.nSamplesPerSec = 44100;
    110 	format.wBitsPerSample = 16;
    111 	format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
    112 	format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
    113 
    114 	if( FAILED( xaudio2->CreateSourceVoice( &device->voice, &format, 0, 1.0f, &callbacks ) ) ) {
    115 		FATAL( "CreateSourceVoice" );
    116 	}
    117 
    118 	device->event = CreateEvent( NULL, FALSE, FALSE, NULL );
    119 	if( device->event == NULL ) {
    120 		FATAL( "CreateEvent" );
    121 	}
    122 
    123 	device->voice->Start( 0 );
    124 
    125 	memset( &device->buffer, 0, sizeof( device->buffer ) );
    126 
    127 	store_release( &device->shutting_down, 0 );
    128 	thread_init( &device->thread, audio_output_thread, device );
    129 }
    130 
    131 void audio_output_close( AudioOutputDevice * device ) {
    132 	store_release( &device->shutting_down, 1 );
    133 	thread_join( &device->thread );
    134 
    135 	device->voice->Stop( 0 );
    136 	device->voice->FlushSourceBuffers();
    137 	device->voice->DestroyVoice();
    138 	if( CloseHandle( device->event ) == 0 ) {
    139 		FATAL( "CloseHandle" );
    140 	}
    141 }