Я использую C ++ для кодирования нейробиологического эксперимента в моей исследовательской лаборатории. Мы изучаем тактильное восприятие и используем параллельный порт для запуска устройства, стимулирующего мозг. Время очень важно.
Недавно мы начали использовать xaudio2 для воспроизведения очень простых файлов WAV, которые используются для запуска наших вибротактильных стимуляторов (например, наши «тактильные» стимулы — это звуки 100 и 200 Гц с длительностью 100 мс, которые перемещают пьезоэлектрический стимулятор, который находится на руке).
Наша проблема заключается в том, что нам нужно отправить 3 команды на стимулятор мозга через параллельный порт: один раз за 40 мс до тактильного стимула, один раз через 10 мс после начала стимула и третий раз за 60 мс до стимула. Помните, что тактильный стимул длится 100 мс.
Однако способ, которым xaudio2 запускает звук, состоит в том, что он воспроизводит волну и блокирует, пока не закончится. Как следствие, программа игнорирует две команды параллельного порта, которые должны быть отправлены во время стимула.
Кто-нибудь знает, как я могу убедиться, что тактильный стимул все еще срабатывает в течение всей его длительности 100 мс, но также отправлять команды параллельного порта во время него? Я использую MSDN XAudio2Samples в качестве базовой структуры для воспроизведения файлов WAV, а функция PlayWave «блокирует» любой другой ввод во время воспроизведения файла WAV, но я не могу понять, как его изменить. что он также будет принимать мои команды параллельного порта (которые Out32 (888,1)) во время воспроизведения звука.
Спасибо!
Вот код для функции PlayWave:
//--------------------------------------------------------------------------------------
// 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*/)
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;
}
Задача ещё не решена.
Других решений пока нет …