static void XAUDIO2_WaitDone(_THIS) { IXAudio2SourceVoice *source = _this->hidden->source; XAUDIO2_VOICE_STATE state; SDL_assert(!_this->enabled); /* flag that stops playing. */ source->Discontinuity(); source->GetState(&state); while (state.BuffersQueued > 0) { WaitForSingleObjectEx(_this->hidden->semaphore, INFINITE, 0); source->GetState(&state); } }
void GameAudio::playMusicOnce(MusicTypes musicType) { if (musicRegistrationMap[musicType] == true) { IXAudio2SourceVoice *sourceVoice = musicMap[musicType]; XAUDIO2_VOICE_STATE voiceState; sourceVoice->GetState(&voiceState); if (musicType == ENUM_MUSIC_LEVEL_COMPLETE) { if (levelCompleteMusicBuffered == false) { XAUDIO2_BUFFER *proto = musicBufferPrototypeMap[musicType]; bool ssbSuccess = SUCCEEDED(sourceVoice->SubmitSourceBuffer(proto)); sourceVoice->Start(); levelCompleteMusicBuffered = true; } } /// here put the game over music else if (musicType == ENUM_MUSIC_GAMEOVER) { if (gameOverMusicBuffered == false) { XAUDIO2_BUFFER *proto = musicBufferPrototypeMap[musicType]; bool ssbSuccess = SUCCEEDED(sourceVoice->SubmitSourceBuffer(proto)); sourceVoice->Start(); gameOverMusicBuffered = true; } } } }
void GameAudio::processHealSound() { if (soundEffectRegistrationMap[ENUM_SOUND_EFFECT_HEAL] == true) { Game *game = Game::getSingleton(); GameStateManager *gsm = game->getGSM(); SpriteManager *spriteMgr = gsm->getSpriteManager(); PlayerSprite *player = spriteMgr->getPlayer(); bool isHealing = player->getIshealing(); if (isHealing == true) { IXAudio2SourceVoice *healSound = soundEffectMap[ENUM_SOUND_EFFECT_HEAL]; XAUDIO2_VOICE_STATE voiceState; healSound->GetState(&voiceState); //// [voiceState.BuffersQueued <= 0] means there are nothing in the buffer //// so let's make a new buffer to queue the sound if (voiceState.BuffersQueued <= 0) { XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_HEAL]; bool ssbSuccess = SUCCEEDED(healSound->SubmitSourceBuffer(proto)); healSound->Start(); //// After all, there will be only one buffer node in the queue always ... } //// if there is something in the buffer else { /// do nothing } } } }
void GameAudio::processPunchSound() { if (soundEffectRegistrationMap[ENUM_SOUND_EFFECT_PUNCH] == true) { Game *game = Game::getSingleton(); GameStateManager *gsm = game->getGSM(); SpriteManager *spriteMgr = gsm->getSpriteManager(); PlayerSprite *player = spriteMgr->getPlayer(); wstring playerState = player->getCurrentState(); if (playerState.compare(L"PUNCH_LEFT") == 0 || playerState.compare(L"PUNCH_RIGHT") == 0 || playerState.compare(L"PUNCH_BACK") == 0 || playerState.compare(L"PUNCH_FRONT") == 0) { IXAudio2SourceVoice *punchSound = soundEffectMap[ENUM_SOUND_EFFECT_PUNCH]; XAUDIO2_VOICE_STATE voiceState; punchSound->GetState(&voiceState); //// [voiceState.BuffersQueued <= 0] means there are nothing in the buffer //// so let's make a new buffer to queue the sound if (voiceState.BuffersQueued <= 0) { XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_PUNCH]; bool ssbSuccess = SUCCEEDED(punchSound->SubmitSourceBuffer(proto)); punchSound->Start(); } //// if there is something in the buffer else { /// do nothing } } } }
virtual const char* write_frame( void * buffer, unsigned num_samples, bool wait ) { if ( paused ) { if ( wait ) Sleep( MulDiv( num_samples / nch, 1000, sample_rate ) ); return 0; } if ( reopen_count ) { if ( ! --reopen_count ) { const char * err = open( hwnd, sample_rate, nch, max_samples_per_frame, num_frames ); if ( err ) { reopen_count = 60 * 5; return err; } } else { if ( wait ) Sleep( MulDiv( num_samples / nch, 1000, sample_rate ) ); return 0; } } for (;;) { sVoice->GetState( &vState ); assert( vState.BuffersQueued <= num_frames ); if( vState.BuffersQueued < num_frames ) { if( vState.BuffersQueued == 0 ) { // buffers ran dry } // there is at least one free buffer break; } else { // wait for one buffer to finish playing ResetEvent( notify.hBufferEndEvent ); WaitForSingleObject( notify.hBufferEndEvent, INFINITE ); } } samples_in_buffer[ buffer_write_cursor ] = num_samples / nch; XAUDIO2_BUFFER buf = {0}; unsigned num_bytes = num_samples * 2; buf.AudioBytes = num_bytes; buf.pAudioData = ( const BYTE * )( sample_buffer + max_samples_per_frame * buffer_write_cursor ); buf.pContext = this; buffer_write_cursor = ( buffer_write_cursor + 1 ) % num_frames; memcpy( ( void * ) buf.pAudioData, buffer, num_bytes ); if( sVoice->SubmitSourceBuffer( &buf ) == S_OK ) { InterlockedIncrement( &buffered_count ); return 0; } close(); reopen_count = 60 * 5; return 0; }
virtual double buffered() { sVoice->GetState( &vState ); double buffered_count = vState.BuffersQueued; INT64 samples_played = vState.SamplesPlayed - this->samples_played; buffered_count -= double( samples_played ) / double( max_samples_per_frame / nch ); return buffered_count; }
void XAudio2_Output::write(u16 * finalWave, int length) { if( !initialized || failed ) return; while( true ) { if ( device_changed ) { close(); if (!init(freq)) return; } sVoice->GetState( &vState ); ASSERT( vState.BuffersQueued <= bufferCount ); if( vState.BuffersQueued < bufferCount ) { if( vState.BuffersQueued == 0 ) { // buffers ran dry if( systemVerbose & VERBOSE_SOUNDOUTPUT ) { static unsigned int i = 0; log( "XAudio2: Buffers were not refilled fast enough (i=%i)\n", i++ ); } } // there is at least one free buffer break; } else { // the maximum number of buffers is currently queued if( synchronize && !speedup && !theApp.throttle ) { // 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 HRESULT hr = sVoice->SubmitSourceBuffer( &buf ); // send buffer to queue ASSERT( hr == S_OK ); }
void GameAudio::playMusicRepeat(MusicTypes musicType) { if (musicRegistrationMap[musicType] == true) { IXAudio2SourceVoice *sourceVoice = musicMap[musicType]; XAUDIO2_VOICE_STATE voiceState; sourceVoice->GetState(&voiceState); if (voiceState.BuffersQueued <= 0) { XAUDIO2_BUFFER *proto = musicBufferPrototypeMap[musicType]; bool ssbSuccess = SUCCEEDED(sourceVoice->SubmitSourceBuffer(proto)); sourceVoice->Start(); } } }
void GameAudio::processMoneySound() { if (soundEffectRegistrationMap[ENUM_SOUND_EFFECT_MONEY] == true) { if (moneySoundSignal == true) { IXAudio2SourceVoice *moneySound = soundEffectMap[ENUM_SOUND_EFFECT_MONEY]; XAUDIO2_VOICE_STATE voiceState; moneySound->GetState(&voiceState); XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_MONEY]; bool ssbSuccess = SUCCEEDED(moneySound->SubmitSourceBuffer(proto)); moneySound->Start(); moneySoundSignal = false; } } }
void XAudio2Streamer::Stream( void const *pSamples ) { // Verify buffer availability XAUDIO2_VOICE_STATE xa2vs; m_pXAudio2SourceVoice->GetState( &xa2vs ); if( xa2vs.BuffersQueued == m_count ) return; // Copy samples to buffer Sample *pBuffer( &m_samples[ m_index * m_size ] ); using std::memcpy; memcpy( pBuffer, pSamples, m_size ); // Submit buffer to voice XAUDIO2_BUFFER xa2b = {}; xa2b.AudioBytes = UINT32( m_size ); xa2b.pAudioData = pBuffer; if( FAILED( m_pXAudio2SourceVoice->SubmitSourceBuffer( &xa2b ) ) ) return; // Select next buffer m_index = ( m_index + 1 ) % m_count; }
void GameAudio::processShootSound() { if (soundEffectRegistrationMap[ENUM_SOUND_EFFECT_SHOOT] == true) { Game *game = Game::getSingleton(); GameStateManager *gsm = game->getGSM(); SpriteManager *spriteMgr = gsm->getSpriteManager(); /*if (moneySoundSignal == true) { IXAudio2SourceVoice *moneySound = soundEffectMap[ENUM_SOUND_EFFECT_MONEY]; XAUDIO2_VOICE_STATE voiceState; moneySound->GetState(&voiceState); XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_MONEY]; bool ssbSuccess = SUCCEEDED(moneySound->SubmitSourceBuffer(proto)); moneySound->Start(); moneySoundSignal = false; } */ if (shootSoundSignal == true) { IXAudio2SourceVoice *shootSound = soundEffectMap[ENUM_SOUND_EFFECT_SHOOT]; XAUDIO2_VOICE_STATE voiceState; shootSound->GetState(&voiceState); XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_SHOOT]; bool ssbSuccess = SUCCEEDED(shootSound->SubmitSourceBuffer(proto)); shootSound->Start(); shootSoundSignal = false; } /* list<Bot*>::iterator botIt = spriteMgr->getBotsIterator(); list<Bot*>::iterator endBotIt = spriteMgr->getEndOfBotsIterator(); while (botIt != endBotIt) { Bot *bot = (*botIt); wstring botCurState = bot->getCurrentState(); if (botCurState.compare(L"SHOOT_LEFT") == 0 || botCurState.compare(L"SHOOT_RIGHT") == 0 || botCurState.compare(L"SHOOT_BACK") == 0 || botCurState.compare(L"SHOOT_FRONT") == 0) { IXAudio2SourceVoice *shootSound = soundEffectMap[ENUM_SOUND_EFFECT_SHOOT]; XAUDIO2_VOICE_STATE voiceState; shootSound->GetState(&voiceState); if (voiceState.BuffersQueued <= 0) { XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_SHOOT]; bool ssbSuccess = SUCCEEDED(shootSound->SubmitSourceBuffer(proto)); shootSound->Start(); } } botIt++; } PlayerSprite *player = spriteMgr->getPlayer(); wstring playerState = player->getCurrentState(); if (playerState.compare(L"SHOOT_LEFT") == 0 || playerState.compare(L"SHOOT_RIGHT") == 0 || playerState.compare(L"SHOOT_BACK") == 0 || playerState.compare(L"SHOOT_FRONT") == 0) { IXAudio2SourceVoice *shootSound = soundEffectMap[ENUM_SOUND_EFFECT_SHOOT]; XAUDIO2_VOICE_STATE voiceState; shootSound->GetState(&voiceState); //// [voiceState.BuffersQueued <= 0] means there are nothing in the buffer //// so let's make a new buffer to queue the sound if (voiceState.BuffersQueued <= 0) { XAUDIO2_BUFFER *proto = audioBufferPrototypeMap[ENUM_SOUND_EFFECT_SHOOT]; bool ssbSuccess = SUCCEEDED(shootSound->SubmitSourceBuffer(proto)); shootSound->Start(); } //// if there is something in the buffer else { /// do nothing } } */ } }
HRESULT WMA::OnSample(DWORD dwOutputNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer *pSample) { if( !m_bOpen ) { if(m_hRespondEvent) { SetEvent(m_hRespondEvent); } return S_OK; } if( m_bEOF ) { SetEvent(m_hRespondEvent); return S_OK; } /*BYTE* pBuf; DWORD dwLen; if(!pSample) return E_FAIL; HRESULT hr = pSample->GetBuffer(&pBuf); if(FAILED(hr)) return E_FAIL; hr = pSample->GetLength(&dwLen); if(FAILED(hr)) return E_FAIL; //Expand the decoding buffer if it's needed if((m_nWritePtr + dwLen) > m_nBufferSize) { uint32_t nNewBufferSize = m_nWritePtr + dwLen + DECODING_BUFFER_ERROR; uint8_t* pNewBuffer = new uint8_t[nNewBufferSize]; memcpy( pNewBuffer, m_pBuffer, m_nWritePtr ); if(m_pBuffer) { delete [] m_pBuffer; m_pBuffer = 0; } m_pBuffer = pNewBuffer; m_nBufferSize = nNewBufferSize; } memcpy(m_pBuffer + m_nWritePtr, pBuf, dwLen); m_nWritePtr += dwLen; if(m_nWritePtr >= m_nTargetPtr) { SetEvent(m_hRespondEvent); EnterCriticalSection(&m_csTerm); WaitForSingleObject(m_hWaitEvent, INFINITE); LeaveCriticalSection(&m_csTerm); //this should be happening when shit gets poped of the stack probably? }*/ BYTE* pBuf; //BYTE* leakyBuffer; DWORD dwLen; if(!pSample) return E_FAIL; HRESULT hr = pSample->GetBuffer(&pBuf); if(FAILED(hr)) return E_FAIL; hr = pSample->GetLength(&dwLen); if(FAILED(hr)) return E_FAIL; //leakyBuffer = new BYTE[dwLen]; XAUDIO2_VOICE_STATE state; for(; ; ) { mSourceVoice->GetState( &state ); if( state.BuffersQueued < MAX_BUFFER_COUNT ) { break; } //std::cout << "Blocking..." << std::cout; WaitForSingleObject( mVoiceCallback.hBufferEndEvent, INFINITE ); } memcpy(&(mDecodedBuffers[mCurrentBuffer * mMaxBufferSize]), pBuf, dwLen); //memcpy( leakyBuffer, pBuf, dwLen ); XAUDIO2_BUFFER buffer = {0}; buffer.AudioBytes = dwLen; //buffer.Flags = XAUDIO2_END_OF_STREAM; buffer.Flags = 0; //buffer.pAudioData = leakyBuffer; buffer.pAudioData = &(mDecodedBuffers[mCurrentBuffer * mMaxBufferSize]); mSourceVoice->SubmitSourceBuffer( &buffer ); mCurrentTime = cnsSampleTime + cnsSampleDuration; mCurrentBuffer++; mCurrentBuffer %= MAX_BUFFER_COUNT; //probably not an awesome way to do this, since we're dropping audio -- use a ring buffer? //uint32_t copyLen = dwLen; //std::cout << dwLen << std::endl; //if(m_nWritePtr + copyLen > mMaxBufferSize) { // copyLen = mMaxBufferSize - m_nWritePtr; //} /*memcpy(&(mDecodedBuffers[mCurrentBuffer * mMaxBufferSize]) + m_nWritePtr, pBuf, copyLen); m_nWritePtr += dwLen; if( m_nWritePtr >= mMaxBufferSize ) { //std::cout << "Starting Buffer Queue" << std::endl; //std::cout << "Actually Queuing Buffer" << std::endl; XAUDIO2_BUFFER buffer = {0}; buffer.AudioBytes = m_nWritePtr; //buffer.Flags = XAUDIO2_END_OF_STREAM; buffer.Flags = 0; buffer.pAudioData = &(mDecodedBuffers[mCurrentBuffer * mMaxBufferSize]); mSourceVoice->SubmitSourceBuffer( &buffer ); XAUDIO2_VOICE_STATE state; for(; ; ) { mSourceVoice->GetState( &state ); if( state.BuffersQueued < MAX_BUFFER_COUNT ) { break; } //std::cout << "Blocking..." << std::cout; WaitForSingleObject( mVoiceCallback.hBufferEndEvent, INFINITE ); } //std::cout << "Continuing" << std::endl; mCurrentBuffer++; mCurrentBuffer %= MAX_BUFFER_COUNT; m_nWritePtr = 0; }*/ //XAUDIO2_VOICE_STATE state; //mSourceVoice->GetState( &state ); std::cout << cnsSampleTime << std::endl; return S_OK; }
//the streaming thread procedure DWORD WINAPI StreamProc(LPVOID pContext) { //required by XAudio2 CoInitializeEx(NULL, COINIT_MULTITHREADED); if(pContext == NULL) { CoUninitialize(); return -1; } StreamContext* sc = (StreamContext*)pContext; //instantiate the voice's callback class StreamingVoiceCallback callback; //load a file for streaming, non-buffered disk reads (no system cacheing) StreamingWave inFile; if(!inFile.load(sc->filename)) { SetEvent(sc->VoiceLoadEvent); CoUninitialize(); return -3; } //create the voice IXAudio2SourceVoice* source = NULL; if(FAILED(XAudio2->CreateSourceVoice(&source, &inFile.waveFormat.Format, 0, 2.0f, &callback))) { SetEvent(sc->VoiceLoadEvent); CoUninitialize(); return -5; } //fill and queue the maximum number of buffers (except the one needed for reading new wave data) bool somethingsWrong = false; XAUDIO2_VOICE_STATE voiceState = {0}; source->GetState(&voiceState); while(voiceState.BuffersQueued < STREAMINGWAVE_BUFFER_COUNT - 1 && !somethingsWrong) { //read and fill the next buffer to present switch(inFile.prepare()) { case StreamingWave::PR_EOF: //if end of file, loop the file read inFile.resetFile(); //intentionally fall-through to loop sound case StreamingWave::PR_SUCCESS: //present the next available buffer inFile.swap(); //submit another buffer source->SubmitSourceBuffer(inFile.buffer()); source->GetState(&voiceState); break; case StreamingWave::PR_FAILURE: somethingsWrong = true; break; } } //return the created voice through the context pointer sc->pVoice = &source; //signal that the voice has prepared for streaming, and ready to start SetEvent(sc->VoiceLoadEvent); //group the events for the Wait function HANDLE Events[2] = {callback.BufferEndEvent, QuitEvent}; bool quitting = false; while(!quitting) { //wait until either the source voice is ready for another buffer, or the abort signal is set DWORD eventFired = WaitForMultipleObjects(2, Events, FALSE, INFINITE); switch(eventFired) { case 0: //buffer ended event for source voice //reset the event manually ResetEvent(Events[0]); //make sure there's a full number of buffers source->GetState(&voiceState); while(voiceState.BuffersQueued < STREAMINGWAVE_BUFFER_COUNT - 1 && !somethingsWrong) { //read and fill the next buffer to present switch(inFile.prepare()) { case StreamingWave::PR_EOF: //if end of file, loop the file read inFile.resetFile(); //intentionally fall-through to loop sound case StreamingWave::PR_SUCCESS: //present the next available buffer inFile.swap(); //submit another buffer source->SubmitSourceBuffer(inFile.buffer()); source->GetState(&voiceState); break; case StreamingWave::PR_FAILURE: somethingsWrong = true; break; } } break; default: //something's wrong... quitting = true; } } //stop and destroy the voice source->Stop(); source->FlushSourceBuffers(); source->DestroyVoice(); //close the streaming wave file; //this is done automatically in the class destructor, //so this is redundant inFile.close(); //cleanup CoUninitialize(); return 0; }
//-------------------------------------------------------------------------------------- // Name: PlayWave // Desc: Plays a wave and blocks until the wave finishes playing //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT PlayWave( IXAudio2* pXaudio2, LPCWSTR szFilename ) { // // Locate the wave file // WCHAR strFilePath[MAX_PATH]; HRESULT hr = FindMediaFileCch( strFilePath, MAX_PATH, szFilename ); if( FAILED( hr ) ) { wprintf( L"Failed to find media file: %s\n", szFilename ); return hr; } // // Read in the wave file // std::unique_ptr<uint8_t[]> waveFile; DirectX::WAVData waveData; if ( FAILED( hr = DirectX::LoadWAVAudioFromFileEx( strFilePath, waveFile, waveData ) ) ) { wprintf( L"Failed reading WAV file: %#X (%s)\n", hr, strFilePath ); return hr; } // // Play the wave using a XAudio2SourceVoice // // Create the source voice IXAudio2SourceVoice* pSourceVoice; if( FAILED( hr = pXaudio2->CreateSourceVoice( &pSourceVoice, waveData.wfx ) ) ) { wprintf( L"Error %#X creating source voice\n", hr ); return hr; } // Submit the wave sample data using an XAUDIO2_BUFFER structure XAUDIO2_BUFFER buffer = {0}; buffer.pAudioData = waveData.startAudio; buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer buffer.AudioBytes = waveData.audioBytes; if ( waveData.loopLength > 0 ) { buffer.LoopBegin = waveData.loopStart; buffer.LoopLength = waveData.loopLength; buffer.LoopCount = 1; // We'll just assume we play the loop twice } #if (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/ ) if ( waveData.seek ) { XAUDIO2_BUFFER_WMA xwmaBuffer = {0}; xwmaBuffer.pDecodedPacketCumulativeBytes = waveData.seek; xwmaBuffer.PacketCount = waveData.seekCount; if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer, &xwmaBuffer ) ) ) { wprintf( L"Error %#X submitting source buffer (xWMA)\n", hr ); pSourceVoice->DestroyVoice(); return hr; } } #else if ( waveData.seek ) { wprintf( L"This platform does not support xWMA or XMA2\n" ); pSourceVoice->DestroyVoice(); return hr; } #endif else if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer ) ) ) { wprintf( L"Error %#X submitting source buffer\n", hr ); pSourceVoice->DestroyVoice(); return hr; } hr = pSourceVoice->Start( 0 ); // Let the sound play BOOL isRunning = TRUE; while( SUCCEEDED( hr ) && isRunning ) { XAUDIO2_VOICE_STATE state; pSourceVoice->GetState( &state ); isRunning = ( state.BuffersQueued > 0 ) != 0; // Wait till the escape key is pressed if( GetAsyncKeyState( VK_ESCAPE ) ) break; Sleep( 10 ); } // Wait till the escape key is released while( GetAsyncKeyState( VK_ESCAPE ) ) Sleep( 10 ); pSourceVoice->DestroyVoice(); return hr; }
//-------------------------------------------------------------------------------------- // Name: PlayWaveFromWaveBank // Desc: Plays a wave and blocks until the wave finishes playing //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT PlayWaveFromWaveBank( IXAudio2* pXaudio2, WaveBankReader& wb, uint32_t index ) { if ( index >= wb.Count() ) return E_INVALIDARG; uint8_t waveFormat[64]; auto pwfx = reinterpret_cast<WAVEFORMATEX*>( &waveFormat ); HRESULT hr = wb.GetFormat( index, pwfx, 64 ); if ( FAILED(hr) ) return hr; const uint8_t* waveData = nullptr; uint32_t waveSize; hr = wb.GetWaveData( index, &waveData, waveSize ); if ( FAILED(hr) ) return hr; WaveBankReader::Metadata metadata; hr = wb.GetMetadata( index, metadata ); if ( FAILED(hr) ) return hr; // // Play the wave using a XAudio2SourceVoice // // Create the source voice IXAudio2SourceVoice* pSourceVoice; if( FAILED( hr = pXaudio2->CreateSourceVoice( &pSourceVoice, pwfx ) ) ) { wprintf( L"Error %#X creating source voice\n", hr ); return hr; } // Submit the wave sample data using an XAUDIO2_BUFFER structure XAUDIO2_BUFFER buffer = {0}; buffer.pAudioData = waveData; buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer buffer.AudioBytes = waveSize; if ( metadata.loopLength > 0 && metadata.loopLength != metadata.duration ) { buffer.LoopBegin = metadata.loopStart; buffer.LoopLength = metadata.loopLength; buffer.LoopCount = 1; // We'll just assume we play the loop twice } const uint32_t* seekTable; uint32_t seekTableCount; uint32_t tag; hr = wb.GetSeekTable( index, &seekTable, seekTableCount, tag ); if ( seekTable ) { if ( tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3 ) { #if (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/ ) XAUDIO2_BUFFER_WMA xwmaBuffer = {0}; xwmaBuffer.pDecodedPacketCumulativeBytes = seekTable; xwmaBuffer.PacketCount = seekTableCount; if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer, &xwmaBuffer ) ) ) { wprintf( L"Error %#X submitting source buffer (xWMA)\n", hr ); pSourceVoice->DestroyVoice(); return hr; } #else wprintf( L"This platform does not support xWMA\n" ); pSourceVoice->DestroyVoice(); return hr; #endif } else if ( tag == 0x166 /* WAVE_FORMAT_XMA2 */ ) { wprintf( L"This platform does not support XMA2\n" ); pSourceVoice->DestroyVoice(); return hr; } } else if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer ) ) ) { wprintf( L"Error %#X submitting source buffer\n", hr ); pSourceVoice->DestroyVoice(); return hr; } hr = pSourceVoice->Start( 0 ); // Let the sound play BOOL isRunning = TRUE; while( SUCCEEDED( hr ) && isRunning ) { XAUDIO2_VOICE_STATE state; pSourceVoice->GetState( &state ); isRunning = ( state.BuffersQueued > 0 ) != 0; // Wait till the escape key is pressed if( GetAsyncKeyState( VK_ESCAPE ) ) break; Sleep( 10 ); } // Wait till the escape key is released while( GetAsyncKeyState( VK_ESCAPE ) ) Sleep( 10 ); pSourceVoice->DestroyVoice(); return hr; }