Trying reciprocal latency measurement implementation with Portaudio using ASIO host API

parent 27cd064b
......@@ -26,4 +26,3 @@ svnaccess
*.lib
*.exp
*.log
*.txt
......@@ -26,12 +26,3 @@ vista_install( NativeAsioThreadedMultiInstanceTest )
vista_create_default_info_file( NativeAsioThreadedMultiInstanceTest )
set_property( TARGET NativeAsioThreadedMultiInstanceTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Asio" )
add_executable( ReciprocalDAADLatencyMeasurement ReciprocalDAADLatencyMeasurement.cpp )
target_link_libraries( ReciprocalDAADLatencyMeasurement ${VISTA_USE_PACKAGE_LIBRARIES} )
vista_configure_app( ReciprocalDAADLatencyMeasurement )
vista_install( ReciprocalDAADLatencyMeasurement )
vista_create_default_info_file( ReciprocalDAADLatencyMeasurement )
set_property( TARGET ReciprocalDAADLatencyMeasurement PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Asio" )
#include <cassert>
#include <conio.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <host/asiodrivers.h>
#include <common/asio.h>
#include <VistaBase/VistaTimeUtils.h>
using namespace std;
ASIOTime* AsioBufferSwitchTimeInfoA( ASIOTime *timeInfo, long, ASIOBool )
{
return timeInfo;
};
void AsioBufferSwitchA( long nIndex, ASIOBool processNow )
{
ASIOTime timeInfo;
memset( &timeInfo, 0, sizeof( timeInfo ) );
if( ASIOGetSamplePosition( &timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime ) == ASE_OK )
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
AsioBufferSwitchTimeInfoA( &timeInfo, nIndex, processNow );
};
void AsioSampleRateChangedA( ASIOSampleRate fs )
{
cout << "Sample rate changed to " << fs << endl;
return;
};
long AsioMessagesA( long, long, void*, double* )
{
return 0;
};
ASIOTime* AsioBufferSwitchTimeInfoB( ASIOTime *timeInfo, long, ASIOBool )
{
return timeInfo;
};
void AsioBufferSwitchB( long nIndex, ASIOBool processNow )
{
ASIOTime timeInfo;
memset( &timeInfo, 0, sizeof( timeInfo ) );
if( ASIOGetSamplePosition( &timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime ) == ASE_OK )
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
AsioBufferSwitchTimeInfoB( &timeInfo, nIndex, processNow );
};
void AsioSampleRateChangedB( ASIOSampleRate fs )
{
cout << "Sample rate changed to " << fs << endl;
return;
};
long AsioMessagesB( long, long, void*, double* )
{
return 0;
};
int main( int, char[] )
{
ASIOError ae;
AsioDriverList* pDrivers = new AsioDriverList();
long nNumDrivers = pDrivers->asioGetNumDev();
cout << "Number of ASIO drivers: " << nNumDrivers << endl;
delete pDrivers;
// Driver A
int iDriverIndexA = 1;
AsioDrivers* pDriverA = new AsioDrivers();
string sDriverNameA;
sDriverNameA.resize( 256 );
pDriverA->asioGetDriverName( iDriverIndexA, &sDriverNameA[ 0 ], int( sDriverNameA.size() ) );
sDriverNameA = std::string( sDriverNameA.c_str() ); // Strip
cout << "Driver name: " << sDriverNameA << "." << endl;
int iDriverIndexB = 1;
//AsioDrivers* pDriverB = new AsioDrivers();
string sDriverNameB;
sDriverNameB.resize( 256 );
pDriverA->asioGetDriverName( iDriverIndexB, &sDriverNameB[ 0 ], int( sDriverNameB.size() ) );
sDriverNameB = std::string( sDriverNameB.c_str() ); // Strip
cout << "Driver name: " << sDriverNameB << "." << endl;
bool bLoadSuccessA = pDriverA->loadDriver( &sDriverNameA[ 0 ] );
assert( bLoadSuccessA );
bool bLoadSuccessB = pDriverA->loadDriver( &sDriverNameB[ 0 ] );
assert( bLoadSuccessB );
ASIODriverInfo oDriverInfo;
oDriverInfo.asioVersion = 2;
if( ASIOInit( &oDriverInfo ) != ASE_OK )
{
cout << "Could not initialize " << sDriverNameA << ", skipping." << endl;
return 255;
}
ASIOCallbacks oAsioCallbackA;
oAsioCallbackA.asioMessage = &AsioMessagesA;
oAsioCallbackA.bufferSwitch = &AsioBufferSwitchA;
oAsioCallbackA.bufferSwitchTimeInfo = &AsioBufferSwitchTimeInfoA;
oAsioCallbackA.sampleRateDidChange = &AsioSampleRateChangedA;
vector< ASIOBufferInfo > voBufferInfosA( 4 );
voBufferInfosA[ 0 ].buffers;
voBufferInfosA[ 0 ].channelNum = 0;
voBufferInfosA[ 0 ].isInput = ASIOTrue;
voBufferInfosA[ 1 ].buffers;
voBufferInfosA[ 1 ].channelNum = 1;
voBufferInfosA[ 1 ].isInput = ASIOTrue;
voBufferInfosA[ 2 ].buffers;
voBufferInfosA[ 2 ].channelNum = 0;
voBufferInfosA[ 2 ].isInput = ASIOFalse;
voBufferInfosA[ 3 ].buffers;
voBufferInfosA[ 3 ].channelNum = 1;
voBufferInfosA[ 3 ].isInput = ASIOFalse;
ASIOSampleRate fs;
if( ASIOGetSampleRate( &fs ) == ASE_NotPresent )
return 255;
long minSize, maxSize, preferredSize, granularity;
ae = ASIOGetBufferSize( &minSize, &maxSize, &preferredSize, &granularity );
preferredSize = ( preferredSize == 0 ? min( 1024, maxSize ) : preferredSize );
ae = ASIOCreateBuffers( &voBufferInfosA.front(), 4, preferredSize, &oAsioCallbackA );
assert( ae == ASE_OK );
ae = ASIOStart();
assert( ae == ASE_OK );
VistaTimeUtils::Sleep( int( 2e3 ) );
ae = ASIOStop();
assert( ae == ASE_OK );
// Driver B
ASIODriverInfo oDriverInfoB;
oDriverInfoB.asioVersion = 2;
if( ASIOInit( &oDriverInfoB ) != ASE_OK )
{
cout << "Could not initialize " << sDriverNameB << ", skipping." << endl;
return 255;
}
ASIOCallbacks oAsioCallbackB;
oAsioCallbackB.asioMessage = &AsioMessagesB;
oAsioCallbackB.bufferSwitch = &AsioBufferSwitchB;
oAsioCallbackB.bufferSwitchTimeInfo = &AsioBufferSwitchTimeInfoB;
oAsioCallbackB.sampleRateDidChange = &AsioSampleRateChangedB;
vector< ASIOBufferInfo > voBufferInfosB( 4 );
voBufferInfosB[ 0 ].buffers;
voBufferInfosB[ 0 ].channelNum = 0;
voBufferInfosB[ 0 ].isInput = ASIOTrue;
voBufferInfosB[ 1 ].buffers;
voBufferInfosB[ 1 ].channelNum = 1;
voBufferInfosB[ 1 ].isInput = ASIOTrue;
voBufferInfosB[ 2 ].buffers;
voBufferInfosB[ 2 ].channelNum = 0;
voBufferInfosB[ 2 ].isInput = ASIOFalse;
voBufferInfosB[ 3 ].buffers;
voBufferInfosB[ 3 ].channelNum = 1;
voBufferInfosB[ 3 ].isInput = ASIOFalse;
if( ASIOGetSampleRate( &fs ) == ASE_NotPresent )
return 255;
ae = ASIOGetBufferSize( &minSize, &maxSize, &preferredSize, &granularity );
preferredSize = ( preferredSize == 0 ? min( 1024, maxSize ) : preferredSize );
ae = ASIOCreateBuffers( &voBufferInfosB.front(), 4, preferredSize, &oAsioCallbackB );
assert( ae == ASE_OK );
ae = ASIOStart();
assert( ae == ASE_OK );
VistaTimeUtils::Sleep( int( 2e3 ) );
ae = ASIOStop();
assert( ae == ASE_OK );
pDriverA->removeCurrentDriver();
delete pDriverA;
// pDriverB->removeCurrentDriver();
//delete pDriverB;
return 0;
}
......@@ -37,3 +37,14 @@ vista_install( ITAPortaudioMeasurementTest )
vista_create_default_info_file( ITAPortaudioMeasurementTest )
set_property( TARGET ITAPortaudioMeasurementTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Portaudio" )
add_executable( ReciprocalDAADLatencyMeasurement ReciprocalDAADLatencyMeasurement.cpp )
target_link_libraries( ReciprocalDAADLatencyMeasurement ${VISTA_USE_PACKAGE_LIBRARIES} )
vista_set_target_msvc_arguments( ReciprocalDAADLatencyMeasurement 1 1 "${CMAKE_CURRENT_SOURCE_DIR}/sweep.wav ${CMAKE_CURRENT_SOURCE_DIR}/recordA.wav ${CMAKE_CURRENT_SOURCE_DIR}/recordB.wav 44100 2048" )
vista_configure_app( ReciprocalDAADLatencyMeasurement )
vista_install( ReciprocalDAADLatencyMeasurement )
vista_create_default_info_file( ReciprocalDAADLatencyMeasurement )
set_property( TARGET ReciprocalDAADLatencyMeasurement PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Portaudio" )
#include <ITADataSourceUtils.h>
#include <ITAPortaudioInterface.h>
#include <ITAStreamProbe.h>
#include <ITAFileDataSource.h>
#include <ITAException.h>
#include <ITAStringUtils.h>
#include <iostream>
#include <string>
using namespace std;
int main( int argc, char *argv[] )
{
if( argc != 8 )
ITA_EXCEPT1( INVALID_PARAMETER, "Syntax error: ReciprocalDAADLatencyMeasurement.exe DeviceIndexA DeviceIndexB excitation.wav recordingA.wav recordingB.wav samplerate blocklength" );
try
{
// Arguments
int iDeviceA = StringToInt( string( argv[ 1 ] ) );
int iDeviceB = StringToInt( string( argv[ 2 ] ) );
string sExcitationSignalPath = string( argv[ 3 ] );
string sRecordingSignalPathA = string( argv[ 4 ] );
string sRecordingSignalPathB = string( argv[ 5 ] );
double dSampleRate = StringToDouble( string( argv[ 6 ] ) );
int iBlockLength = StringToInt( string( argv[ 7 ] ) );
// --- Device A ---
ITAPortaudioInterface oPADeviceA( dSampleRate, iBlockLength );
oPADeviceA.Initialize( iDeviceA );
string sInDevice = oPADeviceA.GetDeviceName( iDeviceA );
cout << "Input device identifier: " << sInDevice << endl;
int iNumInputChannelsA, iNumOutputChannelsA;
oPADeviceA.GetNumChannels( iDeviceA, iNumInputChannelsA, iNumOutputChannelsA );
assert( iNumInputChannelsA > 1 && iNumOutputChannelsA > 1 );
ITAFileDatasource oPlaybackA( sExcitationSignalPath, iBlockLength );
oPADeviceA.SetPlaybackEnabled( true );
oPADeviceA.SetPlaybackDatasource( &oPlaybackA );
oPADeviceA.SetRecordEnabled( true );
ITAStreamProbe oRecordStreamProbeA( oPADeviceA.GetRecordDatasource(), sRecordingSignalPathA );
// --- Device B ---
ITAPortaudioInterface oPADeviceB( dSampleRate, iBlockLength );
oPADeviceB.Initialize( iDeviceB );
sInDevice = oPADeviceB.GetDeviceName( iDeviceB );
cout << "Input device identifier: " << sInDevice << endl;
int iNumInputChannelsB, iNumOutputChannelsB;
oPADeviceB.GetNumChannels( iDeviceB, iNumInputChannelsB, iNumOutputChannelsB );
ITAFileDatasource oPlaybackB( sExcitationSignalPath, iBlockLength );
oPADeviceB.SetPlaybackEnabled( true );
oPADeviceB.SetPlaybackDatasource( &oPlaybackB );
oPADeviceB.SetRecordEnabled( true );
ITAStreamProbe oRecordStreamProbeB( oPADeviceB.GetRecordDatasource(), sRecordingSignalPathB );
// --- Run latency measurement ---
// Open
oPADeviceA.Open();
oPADeviceA.Open();
// Start streaming
oPADeviceA.Start();
oPADeviceB.Start();
// Measurement
WriteFromDatasourceToFile( &oRecordStreamProbeA, sRecordingSignalPathA, oPlaybackA.GetFileCapacity(), 1.0, true, true );
WriteFromDatasourceToFile( &oRecordStreamProbeB, sRecordingSignalPathA, oPlaybackB.GetFileCapacity(), 1.0, true, true );
// Stop streaming
oPADeviceA.Stop();
oPADeviceB.Stop();
// Close
oPADeviceA.Close();
oPADeviceB.Close();
// Finalize
oPADeviceA.Finalize();
oPADeviceB.Finalize();
}
catch( const ITAException& e )
{
cerr << e << endl;
}
return 0;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment