我在我的研究实验室中使用 C++ 编写神经科学实验。我们正在研究触觉感知,我们使用并行端口来触发我们的大脑刺激设备。时机非常重要。我们最近开始使用 xaudio2 播放非常简单的 WAV 文件,这些文件用于触发我们的振动触觉刺激器(例如,我们的“触觉”刺激是 100 和 200 Hz 的声音,持续时间为 100 ms,它移动压电刺激器放在手上)。我们的问题是,我们需要通过并行端口向大脑刺激器发送 3 个命令:在触觉刺激前 40 毫秒一次,在刺激开始后 10 毫秒一次,在刺激开始后 60 毫秒第三次。请记住,触觉刺激持续 100 毫秒。但是,xaudio2 触发声音的方式是它播放波形并阻塞直到完成。结果,程序忽略了应该在激励期间发送的两个并行端口命令。有谁知道我如何确保在整个 100 毫秒的持续时间内仍然触发触觉刺激,而且在此期间还发送并行端口命令?我使用 MSDN XAudio2Samples 作为播放 wav 文件的基本结构,而 PlayWave 功能是在播放 Wav 文件时“阻止”任何其他输入的功能 - 但我不知道如何修改它所以在播放声音时,它还将接受我的并行端口命令(即 Out32(888,1))。谢谢!有谁知道我如何确保在整个 100 毫秒的持续时间内仍然触发触觉刺激,而且在此期间还发送并行端口命令?我使用 MSDN XAudio2Samples 作为播放 wav 文件的基本结构,而 PlayWave 功能是在播放 Wav 文件时“阻止”任何其他输入的功能 - 但我不知道如何修改它所以在播放声音时,它还将接受我的并行端口命令(即 Out32(888,1))。谢谢!有谁知道我如何确保在整个 100 毫秒的持续时间内仍然触发触觉刺激,而且在此期间还发送并行端口命令?我使用 MSDN XAudio2Samples 作为播放 wav 文件的基本结构,而 PlayWave 功能是在播放 Wav 文件时“阻止”任何其他输入的功能 - 但我不知道如何修改它所以在播放声音时,它还将接受我的并行端口命令(即 Out32(888,1))。谢谢!t 弄清楚如何修改它,以便在播放声音时它也会接受我的并行端口命令(即 Out32(888,1))。谢谢!t 弄清楚如何修改它,以便在播放声音时它也会接受我的并行端口命令(即 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;
}