diff --git a/.gitignore b/.gitignore index 16198959b9074145ad9bb20e8221ce0d4fa3bca5..17bb7578c6802614ced57e9f232e94463da3b0e7 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,3 @@ svnaccess *.lib *.exp *.log -*.txt diff --git a/README.md b/README.md index 5e0807fca19b6f38138d0ed129be0b26a923e371..28224410bae5147e19e0b47ddc07db1e77866e23 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,27 @@ ## ITADataSources ITADataSources is a C++ library for component-oriented audio streaming providing basic modules to manipulate samples in a block-based audio processing. -It is marked deprecated because it will be substituted by the module-base [ITAStreaming](https://git.rwth-aachen.de/ita/ITAStreaming) project in the future, but is still heavily used and updated. -ITADataSources is a component from [ITACoreLibs](https://git.rwth-aachen.de/ita/ITACoreLibs), a collection of C++ libraries for virtual acoustics. +In future it may be substituted by the new module-base [ITAStreaming](https://git.rwth-aachen.de/ita/ITAStreaming) project, but is still heavily used and therefore also updated. +ITADataSources is a component of [ITACoreLibs](https://git.rwth-aachen.de/ita/ITACoreLibs), a collection of C++ libraries for virtual acoustics. + ### License -See [LICENSE](LICENSE.md) file. +Copyright 2015-2017 Institute of Technical Acoustics, RWTH Aachen University + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use files of this project except in compliance with the License. +You may obtain a copy of the License at + +<http://www.apache.org/licenses/LICENSE-2.0> + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + ### Quick build guide -Follow instructions from Wiki pages of [ITABase](https://git.rwth-aachen.de/ita/ITABase/wikis/home) project. +It is recommended to clone and follow the build guide of the parent project [ITACoreLibs](https://git.rwth-aachen.de/ita/ITACoreLibs/wikis/home), which includes this project as a submodule. diff --git a/include/ITABufferDataSource.h b/include/ITABufferDataSource.h index f834a8085f7633a8be658c6c1c0131e06c7c1fc9..674b48aec6877cfa4edc7fef6b4dbc5c52c39ebf 100644 --- a/include/ITABufferDataSource.h +++ b/include/ITABufferDataSource.h @@ -20,7 +20,7 @@ #define INCLUDE_WATCHER_ITA_BUFFER_DATA_SOURCE #include <ITADataSourcesDefinitions.h> - + #include <ITADataSource.h> #include <ITAAtomicPrimitives.h> @@ -38,7 +38,7 @@ * legt ITABufferDatasource die Kapazit�t als n�chstkleineres Blockl�nge-Vielfaches * der Buffergr��e (uiBufferSize) fest. * - * Die Klasse bietet ferner die M�glichkeit einen bestimmten Bereich der Puffer + * Die Klasse bietet ferner die M�glichkeit einen bestimmten Bereich der Puffer * f�r das Freisetzen der Audiodaten zu benutzen, den sogenannten Arbeitsbereich * (<i>region of interest, ROI</i>). Zwei Wiedergabemodi werden unterst�tzt: * Einmaliges Freisetzen/Abspielen und Wiederholung. @@ -46,7 +46,7 @@ * �ber den gesch�tzen Konstruktor und die gesch�tzte Init-Methode k�nnen von * ITABufferDatasource abgeleitete Klasse eine verz�gert Initialisierung und damit * Festgelegung auf konkrete Puffer und Parameter realisieren. Dies ist notwendig, - * wenn beim Aufruf des ITABufferDatasource-Konstruktors diese Parameter noch nicht + * wenn beim Aufruf des ITABufferDatasource-Konstruktors diese Parameter noch nicht * bekannt sind. Instanzen m�ssen dann mittels der Init-Methode initialisiert werden. * * \important <b>Thread-Safety</b>: Ist in dieser Implementierung nicht konsequent durchgezogen. @@ -54,10 +54,11 @@ * und einem speziellen Einsatzschema der Klasse, beidem Thread-safety ausserhalb * der Klasse realisiert wird, wurde auf eine strikte Thread-sichere Implementierung zun�chst * verzichtet. But remember: <b>You have been warned!</b> :-P [fwe: Dezember 2005] - * + * * \ingroup datasources */ -class ITA_DATA_SOURCES_API ITABufferDatasource : public ITADatasource { +class ITA_DATA_SOURCES_API ITABufferDatasource : public ITADatasource +{ public: //! Konstruktor (2D-Array) /** @@ -68,14 +69,9 @@ public: * \param uiBlocklength Blockl�nge mit der die Datenquelle arbeiten soll * \param bLoopMode Wiederholungsmodus? [Optional] * - * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ LLCException ausgel�st + * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ ITAException ausgel�st */ - ITABufferDatasource(const float** ppfBuffer, - unsigned int uiChannels, - unsigned int uiBuffersize, - double dSamplerate, - unsigned int uiBlocklength, - bool bLoopMode=false); + ITABufferDatasource( const float** ppfBuffer, unsigned int uiChannels, unsigned int uiBuffersize, double dSamplerate, unsigned int uiBlocklength, bool bLoopMode = false ); //! Konstruktor (Vektor von Arrays) /** @@ -86,13 +82,9 @@ public: * \param bLoopMode Wiederholungsmodus? [Optional] * * \note Die Kanalanzahl wird aus der Anzahl der Elemente im Vektor bestimmt - * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ LLCException ausgel�st + * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ CIAException ausgel�st */ - ITABufferDatasource(const std::vector<float*>& vpfBuffer, - unsigned int uiBuffersize, - double dSamplerate, - unsigned int uiBlocklength, - bool bLoopMode=false); + ITABufferDatasource( const std::vector< float* >& vpfBuffer, unsigned int uiBuffersize, double dSamplerate, unsigned int uiBlocklength, bool bLoopMode = false ); //! Spezieller Konstruktor (Einkanal-Betrieb) /** @@ -104,18 +96,18 @@ public: * \param uiBlocklength Blockl�nge mit der die Datenquelle arbeiten soll * \param bLoopMode Wiederholungsmodus? [Optional] * - * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ LLCException ausgel�st + * \note Bei ung�ltigen Parametern wird eine Ausnahme vom Typ CITAException ausgel�st */ - ITABufferDatasource(const float* pfBuffer, - unsigned int uiBuffersize, - double dSamplerate, - unsigned int uiBlocklength, - bool bLoopMode=false); + ITABufferDatasource( const float* pfBuffer, + unsigned int uiBuffersize, + double dSamplerate, + unsigned int uiBlocklength, + bool bLoopMode = false ); //! Kapazit�t der Datenquelle zur�ckgeben - /** + /** * Gibt die Anzahl der Samples der Daten der Quelle zur�ck. - * Dieser Wert ist das n�chstkleinere Blockl�ngen-Vielfache der + * Dieser Wert ist das n�chstkleinere Blockl�ngen-Vielfache der * Pufferl�nge uiBuffersize und mu� somit nicht unbedingt dem * wert uiBuffersize entsprechen. Er ist unabh�ngig von der * Wahl des Start- und Endcursors und kann als Obergrenze f�r @@ -137,30 +129,30 @@ public: unsigned int GetCursor(); //! Wiedergabeposition setzen bezogen auf den Arbeitsbereich - void SetCursor(unsigned int uiNewCursor); + void SetCursor( unsigned int uiNewCursor ); //! Wiedergabe pausiert? bool IsPaused() const; - + //! Pausierung f�r Wiedergabe ein-/ausschalten - void SetPaused(bool bPaused); + void SetPaused( bool bPaused ); //! Zur�ckgeben ob die Wiederholung eingeschaltet ist bool GetLoopMode(); //! Wiederholung Ein-/Ausschalten - void SetLoopMode(bool bLoopMode); + void SetLoopMode( bool bLoopMode ); //! Sets the looping mode /** * @param[in] bLoopingEnabled True means looping, false will play until EOF */ void SetIsLooping( bool bLoopingEnabled ); - + //! Looping mode getter /** * @return True means looping, false will play until EOF - */ + */ bool GetIsLooping(); //! Arbeitsbereich (region of interest) festlegen @@ -168,15 +160,15 @@ public: * Legt den Arbeitsbereich fest, d.h. das Interval in den Quellendaten, aus dem die * Quelle ihre Daten freisetzt. Dabei stellt uiStartOffset die Nummer des Samples * dar, an dem der Arbeitsbereich beginnt. Dieser Wert mu� NICHT unbedingt ein Vielfaches der - * Bl�ckl�nge sein und darf frei gew�hlt werden. Der Wert uiEndOffset ist die Nummer + * Bl�ckl�nge sein und darf frei gew�hlt werden. Der Wert uiEndOffset ist die Nummer * des ersten Samples, welches nicht mehr im Arbeitsbereich enthalten ist. - * Somit ist definieren beide Werte das HALBOFFENE Interval [uiStartOffset, uiEndOffset). + * Somit ist definieren beide Werte das HALBOFFENE Interval [uiStartOffset, uiEndOffset). * Die Datenquelle setzt also Audiodaten aus dem Bereich [uiStartOffset, uiEndOffset-1] * frei. Das Ende des Arbeitsbereiches uiEndOffset wird von der Methode so * angepasst, das die Differenz uiEndOffset-uiStartOffset das n�chstkleinere Vielfache * der Blockl�nge ergibt. */ - void SetROI(unsigned int uiStartOffset, unsigned int uiEndOffset); + void SetROI( unsigned int uiStartOffset, unsigned int uiEndOffset ); //! Startposition des Arbeitsbereiches (region of interest) zur�ckgeben unsigned int GetROIStart(); @@ -206,7 +198,7 @@ public: unsigned int GetNumberOfChannels() const; double GetSampleRate() const; - const float* GetBlockPointer(unsigned int uiChannel, const ITAStreamInfo* pStreamInfo); + const float* GetBlockPointer( unsigned int uiChannel, const ITAStreamInfo* pStreamInfo ); void IncrementBlockPointer(); protected: @@ -226,11 +218,11 @@ protected: /** * Zu benutzen im Verbund mit dem gesch�tzen Konstruktor. */ - void Init(const std::vector<float*>& vpfBuffer, - unsigned int uiBuffersize, - double dSamplerate, - unsigned int uiBlocklength, - bool bLoopMode); + void Init( const std::vector<float*>& vpfBuffer, + unsigned int uiBuffersize, + double dSamplerate, + unsigned int uiBlocklength, + bool bLoopMode ); private: unsigned int m_uiBuffersize; // Gr��e der einzelnen Kanalpuffer diff --git a/include/ITADataSourceUtils.h b/include/ITADataSourceUtils.h index 904e8834f32c5d47c0ccb96e98c530656793ae53..be4a00fd5a7ad837871b2e58f5d9171d8654d85a 100644 --- a/include/ITADataSourceUtils.h +++ b/include/ITADataSourceUtils.h @@ -41,20 +41,15 @@ class ITADatasource; * \param uiNumberOfSamples Anzahl der Samples * \param dGain Verst�rkungsfaktor (optional) * \param bOnline Echtzeit-Modus verwenden? (d.h. reale Dauern zwischen den - * Datenanforderungen verwenden). Falls false, werden die + * Datenanforderungen verwenden). Falls false, werden die * Daten direkt hintereinander angefordert (Maximaler Datendurchsatz) * \param bDisplayProgress Fortschritt auf der Konsole ausgeben? (Optional, Standard: Nein) * - * \note Gibt die Datenquelle den Nullzeiger zur�ck, wird f�r + * \note Gibt die Datenquelle den Nullzeiger zur�ck, wird f�r * den betreffenden Block Stille in den Puffer geschrieben * \note Ausnahmebehandlung mittels der Klasse ITAException */ -ITA_DATA_SOURCES_API void WriteFromDatasourceToBuffer(ITADatasource* pSource, - float** ppfDest, - unsigned int uiNumberOfSamples, - double dGain=1.0, - bool bOnline=true, - bool bDisplayProgress=false); +ITA_DATA_SOURCES_API void WriteFromDatasourceToBuffer( ITADatasource* pSource, float** ppfDest, unsigned int uiNumberOfSamples, double dGain = 1.0, bool bOnline = true, bool bDisplayProgress = false ); //! Daten einer Datenquelle in eine Datei schreiben /** @@ -66,20 +61,14 @@ ITA_DATA_SOURCES_API void WriteFromDatasourceToBuffer(ITADatasource* pSource, * \param uiNumberOfSamples Anzahl der Samples * \param dGain Verst�rkungsfaktor (optional) * \param bOnline Echtzeit-Modus verwenden? (d.h. reale Dauern zwischen den - * Datenanforderungen verwenden). Falls false, werden die + * Datenanforderungen verwenden). Falls false, werden die * Daten direkt hintereinander angefordert (Maximaler Datendurchsatz) * \param bDisplayProgress Fortschritt auf der Konsole ausgeben? (Optional, Standard: Nein) * - * \note Gibt die Datenquelle den Nullzeiger zur�ck, wird f�r + * \note Gibt die Datenquelle den Nullzeiger zur�ck, wird f�r * den betreffenden Block Stille in die Datei geschrieben * \note Ausnahmebehandlung mittels der Klasse ITAException */ -ITA_DATA_SOURCES_API void WriteFromDatasourceToFile(ITADatasource* pSource, - std::string sFilename, - unsigned int uiNumberOfSamples, - double dGain=1.0, - bool bOnline=true, - bool bDisplayProgress=false); - +ITA_DATA_SOURCES_API void WriteFromDatasourceToFile( ITADatasource* pSource, std::string sFilename, unsigned int uiNumberOfSamples, double dGain = 1.0, bool bOnline = true, bool bDisplayProgress = false ); #endif // INCLUDE_WATCHER_ITA_DATA_SOURCES_UTILS diff --git a/src/ITADataSourceUtils.cpp b/src/ITADataSourceUtils.cpp index a6019249c62d399800bf71546b89413aa7c6a5e2..1ed2d2dc443a22c9e2076d1630ef5c76a7f9f381 100644 --- a/src/ITADataSourceUtils.cpp +++ b/src/ITADataSourceUtils.cpp @@ -2,7 +2,9 @@ // Wichtig: Folgendes Makro definiert Windows-NT als Umgebung und // bewirkt somit die Nutzbarkeit der WaitableTimer. -#define _WIN32_WINNT 0x0500 +#ifndef _WIN32_WINNT // @todo: remove +#define _WIN32_WINNT 0x0501 +#endif #include <ITADataSource.h> #include <ITAStreamInfo.h> @@ -22,59 +24,62 @@ #include <unistd.h> #endif -void WriteFromDatasourceToBuffer(ITADatasource* pSource, - float** ppfDest, - unsigned int uiNumberOfSamples, - double dGain, - bool bOnline, - bool bDisplayProgress) { +void WriteFromDatasourceToBuffer( ITADatasource* pSource, float** ppfDest, unsigned int uiNumberOfSamples, double dGain, bool bOnline, bool bDisplayProgress ) +{ // Nullzeiger ausschlie�en // TODO: Fehlerbehandlung - if (!pSource) return; + if( !pSource ) + return; unsigned int uiChannels = pSource->GetNumberOfChannels(); double dSamplerate = pSource->GetSampleRate(); unsigned int uiBlocklength = pSource->GetBlocklength(); ITAStreamInfo siState; - long periodMs = (long)ceil(uiBlocklength / dSamplerate * 1000); + long periodMs = ( long ) ceil( uiBlocklength / dSamplerate * 1000 ); #ifdef _WIN32 - HANDLE hTimer=0; - if (bOnline) { + HANDLE hTimer = 0; + if( bOnline ) + { // Timer erzeugen - if (FAILED(hTimer = CreateWaitableTimer(NULL, false, NULL))) - ITA_EXCEPT1(UNKNOWN, "Timer konnte nicht erzeugt werden"); + if( FAILED( hTimer = CreateWaitableTimer( NULL, false, NULL ) ) ) + ITA_EXCEPT1( UNKNOWN, "Timer konnte nicht erzeugt werden" ); LARGE_INTEGER liDueTime; liDueTime.QuadPart = 0; - SetWaitableTimer(hTimer, &liDueTime, periodMs, NULL, NULL, true); + SetWaitableTimer( hTimer, &liDueTime, periodMs, NULL, NULL, true ); } #endif try { - unsigned int n=0; + unsigned int n = 0; float fProgress = 0.0f; - while (n < uiNumberOfSamples) + while( n < uiNumberOfSamples ) { #ifdef _WIN32 // Warten - if (bOnline) WaitForSingleObject(hTimer, INFINITE); + if( bOnline ) + WaitForSingleObject( hTimer, INFINITE ); #else - if (bOnline) usleep(periodMs * 1000); + if( bOnline ) + usleep( periodMs * 1000 ); #endif // Daten von der Quelle holen - for (unsigned int i=0; i<uiChannels; i++) { - const float* pfData = pSource->GetBlockPointer(i, &siState); + for( unsigned int i = 0; i < uiChannels; i++ ) + { + const float* pfData = pSource->GetBlockPointer( i, &siState ); - unsigned int k = (uiNumberOfSamples - n); - if (k > uiBlocklength) k = uiBlocklength; + unsigned int k = ( uiNumberOfSamples - n ); + if( k > uiBlocklength ) + k = uiBlocklength; if( !pfData ) - { // Stille einf�gen + { + // Stille einf�gen for( unsigned int j = 0; j < uiBlocklength; j++ ) ppfDest[ i ][ n + j ] = 0; } @@ -92,52 +97,52 @@ void WriteFromDatasourceToBuffer(ITADatasource* pSource, n += uiBlocklength; siState.nSamples += uiBlocklength; - siState.dStreamTimeCode = (double) (siState.nSamples) / dSamplerate; + siState.dStreamTimeCode = ( double ) ( siState.nSamples ) / dSamplerate; siState.dSysTimeCode = ITAClock::getDefaultClock()->getTime(); - if (bDisplayProgress) + if( bDisplayProgress ) { - float p = 100 * (float) n / uiNumberOfSamples; - if(p > fProgress + 5.0f) + float p = 100 * ( float ) n / uiNumberOfSamples; + if( p > fProgress + 5.0f ) { fProgress = p; - printf("WriteFromDatasourceToBuffer: %0.2f%% geschrieben", p); + printf( "WriteFromDatasourceToBuffer: %0.2f%% geschrieben", p ); } } } - } catch (...) { + } + catch( ... ) + { #ifdef _WIN32 - if (bOnline) CloseHandle(hTimer); + if( bOnline ) + CloseHandle( hTimer ); #endif throw; } - if (bDisplayProgress) - printf("WriteFromDatasourceToBuffer: 100,00%% geschrieben"); + if( bDisplayProgress ) + printf( "WriteFromDatasourceToBuffer: 100,00%% geschrieben" ); #ifdef _WIN32 - if (bOnline) - CloseHandle(hTimer); + if( bOnline ) + CloseHandle( hTimer ); #endif } -void WriteFromDatasourceToFile(ITADatasource* pSource, - std::string sFilename, - unsigned int uiNumberOfSamples, - double dGain, - bool bOnline, - bool bDisplayProgress) { +void WriteFromDatasourceToFile( ITADatasource* pSource, std::string sFilename, unsigned int uiNumberOfSamples, double dGain, bool bOnline, bool bDisplayProgress ) +{ // Nullzeiger ausschlie�en // TODO: Fehlerbehandlung - if (!pSource) return; + if( !pSource ) + return; unsigned int uiChannels = pSource->GetNumberOfChannels(); unsigned int uiBlocklength = pSource->GetBlocklength(); double dSamplerate = pSource->GetSampleRate(); std::vector<float*> vpfData; - for (unsigned int i=0; i<uiChannels; i++) - vpfData.push_back(new float[uiBlocklength]); + for( unsigned int i = 0; i < uiChannels; i++ ) + vpfData.push_back( new float[ uiBlocklength ] ); ITAAudiofileProperties props; props.iChannels = uiChannels; @@ -145,91 +150,103 @@ void WriteFromDatasourceToFile(ITADatasource* pSource, props.eQuantization = ITAQuantization::ITA_FLOAT; props.eDomain = ITADomain::ITA_TIME_DOMAIN; props.iLength = uiNumberOfSamples; - ITAAudiofileWriter* writer = ITAAudiofileWriter::create(sFilename, props); + ITAAudiofileWriter* writer = ITAAudiofileWriter::create( sFilename, props ); ITAStreamInfo siState; - long periodMs = (long)ceil(uiBlocklength / dSamplerate * 1000); + long periodMs = ( long ) ceil( uiBlocklength / dSamplerate * 1000 ); #ifdef _WIN32 - HANDLE hTimer=0; + HANDLE hTimer = 0; - if (bOnline) { + if( bOnline ) + { // Timer erzeugen - if (FAILED(hTimer = CreateWaitableTimer(NULL, false, NULL))) { + if( FAILED( hTimer = CreateWaitableTimer( NULL, false, NULL ) ) ) + { delete writer; - ITA_EXCEPT1(UNKNOWN, "Timer konnte nicht erzeugt werden"); + ITA_EXCEPT1( UNKNOWN, "Timer konnte nicht erzeugt werden" ); } - + LARGE_INTEGER liDueTime; - liDueTime.QuadPart=0; - - SetWaitableTimer(hTimer, &liDueTime, periodMs, NULL, NULL, true); + liDueTime.QuadPart = 0; + + SetWaitableTimer( hTimer, &liDueTime, periodMs, NULL, NULL, true ); } #endif try { - unsigned int n=0; + unsigned int n = 0; float fProgress = 0.0; - while (n < uiNumberOfSamples) { + while( n < uiNumberOfSamples ) + { #ifdef _WIN32 // Warten - if (bOnline) WaitForSingleObject(hTimer, INFINITE); + if( bOnline ) + WaitForSingleObject( hTimer, INFINITE ); #else - if (bOnline) usleep(periodMs * 1000); + if( bOnline ) + usleep( periodMs * 1000 ); #endif // Daten von der Quelle holen - for (unsigned int i=0; i<uiChannels; i++) { - const float* pfSource = pSource->GetBlockPointer(i, &siState); - float* pfDest = vpfData[i]; - if (!pfSource) + for( unsigned int i = 0; i < uiChannels; i++ ) + { + const float* pfSource = pSource->GetBlockPointer( i, &siState ); + float* pfDest = vpfData[ i ]; + if( !pfSource ) + { // Stille einf�gen - for (unsigned int j=0; j<uiBlocklength; j++) pfDest[j] = 0; - else { - if (dGain == 1) - memcpy(pfDest, pfSource, uiBlocklength*sizeof(float)); - else - for (unsigned int j=0; j<uiBlocklength; j++) - pfDest[j] = pfSource[j] * (float) dGain; + for( unsigned int j = 0; j < uiBlocklength; j++ ) + pfDest[ j ] = 0; + } + else + { + if( dGain == 1 ) + memcpy( pfDest, pfSource, uiBlocklength*sizeof( float ) ); + else + for( unsigned int j = 0; j < uiBlocklength; j++ ) + pfDest[ j ] = pfSource[ j ] * ( float ) dGain; } } pSource->IncrementBlockPointer(); - + siState.nSamples += uiBlocklength; - siState.dStreamTimeCode = (double) (siState.nSamples) / dSamplerate; + siState.dStreamTimeCode = ( double ) ( siState.nSamples ) / dSamplerate; siState.dSysTimeCode = ITAClock::getDefaultClock()->getTime(); // Daten schreiben - writer->write((std::min)(uiBlocklength, (uiNumberOfSamples - n)), vpfData); + writer->write( ( std::min )( uiBlocklength, ( uiNumberOfSamples - n ) ), vpfData ); n += uiBlocklength; - if (bDisplayProgress) + if( bDisplayProgress ) { - float p = 100 * (float) n / uiNumberOfSamples; - if(p > fProgress + 5.0f) + float p = 100 * ( float ) n / uiNumberOfSamples; + if( p > fProgress + 5.0f ) { fProgress = p; - printf("WriteFromDatasourceToFile: %0.2f%% geschrieben\r", p); + printf( "WriteFromDatasourceToFile: %0.2f%% written\r", p ); } } } - } catch (...) { + } + catch( ... ) + { #ifdef _WIN32 - if (bOnline) CloseHandle(hTimer); + if( bOnline ) + CloseHandle( hTimer ); #endif delete writer; throw; } - if (bDisplayProgress) - printf("WriteFromDatasourceToFile: 100,00%% geschrieben\r"); + if( bDisplayProgress ) + printf( "WriteFromDatasourceToFile: 100,00%% written\r" ); #ifdef _WIN32 - if (bOnline) - CloseHandle(hTimer); + if( bOnline ) + CloseHandle( hTimer ); #endif delete writer; } - diff --git a/src/ITAStreamFunctionGenerator.cpp b/src/ITAStreamFunctionGenerator.cpp index 9138837bde80fbecbebd7be12d2169cb168fab88..12a9d0ec5f7a9ce1a1ca833858b0d825732db2bf 100644 --- a/src/ITAStreamFunctionGenerator.cpp +++ b/src/ITAStreamFunctionGenerator.cpp @@ -1,4 +1,4 @@ -#include "ITAStreamFunctionGenerator.h" + #include "ITAStreamFunctionGenerator.h" #include <ITAConstants.h> #include <ITADataSourceRealization.h> @@ -13,28 +13,20 @@ #include <memory.h> #endif -ITAStreamFunctionGenerator::ITAStreamFunctionGenerator(unsigned int uiChannels, - double dSamplerate, - unsigned int uiBlocklength, - int iSignalFunction, - double dFrequency, - float fAmplitude, - bool bPeriodic) -: ITADatasourceRealization(uiChannels, dSamplerate, uiBlocklength), - - // Initial values - m_iFunction(iSignalFunction), - m_bPeriodic(bPeriodic), - m_bMuted(false), - m_fAmplitude(fAmplitude), - m_iSampleCount(0), - m_fPhase(0.0f) -{ - assert(uiChannels > 0); - assert(dSamplerate > 0); - assert(uiBlocklength > 0); - - SetFrequency(dFrequency); +ITAStreamFunctionGenerator::ITAStreamFunctionGenerator( unsigned int uiChannels, double dSamplerate, unsigned int uiBlocklength, int iSignalFunction, double dFrequency, float fAmplitude, bool bPeriodic ) + : ITADatasourceRealization( uiChannels, dSamplerate, uiBlocklength ), + m_iFunction( iSignalFunction ), + m_bPeriodic( bPeriodic ), + m_bMuted( false ), + m_fAmplitude( fAmplitude ), + m_iSampleCount( 0 ), + m_fPhase( 0.0f ) +{ + assert( uiChannels > 0 ); + assert( dSamplerate > 0 ); + assert( uiBlocklength > 0 ); + + SetFrequency( dFrequency ); Reset(); } @@ -49,20 +41,20 @@ int ITAStreamFunctionGenerator::GetFunction() const return m_iFunction; } -void ITAStreamFunctionGenerator::SetFunction(int iFunction) +void ITAStreamFunctionGenerator::SetFunction( int iFunction ) { m_iFunction = iFunction; } double ITAStreamFunctionGenerator::GetFrequency() const { - return m_dSampleRate / (double) m_iPeriodLengthSamples; + return m_dSampleRate / ( double ) m_iPeriodLengthSamples; } -void ITAStreamFunctionGenerator::SetFrequency(double dFrequency) +void ITAStreamFunctionGenerator::SetFrequency( double dFrequency ) { assert( dFrequency >= 0 ); - m_iPeriodLengthSamples = (int) round( m_dSampleRate / dFrequency ); + m_iPeriodLengthSamples = ( int ) round( m_dSampleRate / dFrequency ); } int ITAStreamFunctionGenerator::GetPeriodAsSamples() const @@ -70,7 +62,7 @@ int ITAStreamFunctionGenerator::GetPeriodAsSamples() const return m_iPeriodLengthSamples; } -void ITAStreamFunctionGenerator::SetPeriodAsSamples(int iNumSamples) +void ITAStreamFunctionGenerator::SetPeriodAsSamples( int iNumSamples ) { assert( iNumSamples >= 0 ); m_iPeriodLengthSamples = iNumSamples; @@ -78,12 +70,12 @@ void ITAStreamFunctionGenerator::SetPeriodAsSamples(int iNumSamples) double ITAStreamFunctionGenerator::GetPeriodAsTime() const { - return (double) m_iPeriodLengthSamples / m_dSampleRate; + return ( double ) m_iPeriodLengthSamples / m_dSampleRate; } -void ITAStreamFunctionGenerator::SetPeriodAsTime(double dPeriodLength) +void ITAStreamFunctionGenerator::SetPeriodAsTime( double dPeriodLength ) { - m_iPeriodLengthSamples = (int) round(dPeriodLength * m_dSampleRate); + m_iPeriodLengthSamples = ( int ) round( dPeriodLength * m_dSampleRate ); } bool ITAStreamFunctionGenerator::IsPeriodic() const @@ -91,7 +83,7 @@ bool ITAStreamFunctionGenerator::IsPeriodic() const return m_bPeriodic; } -void ITAStreamFunctionGenerator::SetPeriodic(bool bPeriodic) +void ITAStreamFunctionGenerator::SetPeriodic( bool bPeriodic ) { m_bPeriodic = bPeriodic; } @@ -101,7 +93,7 @@ bool ITAStreamFunctionGenerator::IsMuted() const return m_bMuted; } -void ITAStreamFunctionGenerator::SetMuted(bool bMuted) +void ITAStreamFunctionGenerator::SetMuted( bool bMuted ) { m_bMuted = bMuted; } @@ -111,112 +103,115 @@ float ITAStreamFunctionGenerator::GetAmplitude() const return m_fAmplitude; } -void ITAStreamFunctionGenerator::SetAmplitude(float fAmplitude) +void ITAStreamFunctionGenerator::SetAmplitude( float fAmplitude ) { - m_fAmplitude = (float) fAmplitude; + m_fAmplitude = ( float ) fAmplitude; } -void ITAStreamFunctionGenerator::ProcessStream(const ITAStreamInfo* pStreamInfo) +void ITAStreamFunctionGenerator::ProcessStream( const ITAStreamInfo* ) { // Generate the next output samples - float* pfOutputData = GetWritePointer(0); - fm_zero(pfOutputData, m_uiBlocklength); + float* pfOutputData = GetWritePointer( 0 ); + fm_zero( pfOutputData, m_uiBlocklength ); // Variables int N = m_iPeriodLengthSamples; float a = m_fAmplitude; - + float omega; - float gradient = a / (float) (N-1); // Steigung der S�gezahn und Dreieck + float gradient = a / ( float ) ( N - 1 ); // Steigung der S�gezahn und Dreieck int iZero; // Offset �bergang 1=>0 bei Rechteck int iNumSamples; // Anzahl zu erzeugender Samples - - switch (m_iFunction) { + + switch( m_iFunction ) { case SINE: - omega = ITAConstants::TWO_PI_F / (float) N; // 2*pi/T - - iNumSamples = m_bPeriodic ? (int) m_uiBlocklength : (std::min)( (int) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount); + omega = ITAConstants::TWO_PI_F / ( float ) N; // 2*pi/T + + iNumSamples = m_bPeriodic ? ( int ) m_uiBlocklength : ( std::min )( ( int ) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ); - for (int i=0;i<iNumSamples;i++) { - pfOutputData[i] = a * sin(omega*i + m_fPhase); + for( int i = 0; i < iNumSamples; i++ ) { + pfOutputData[ i ] = a * sin( omega*i + m_fPhase ); } m_fPhase = fmodf( iNumSamples*omega + m_fPhase, ITAConstants::TWO_PI_F ); m_iSampleCount += iNumSamples; - + break; case TRIANGLE: - iNumSamples = (m_bPeriodic ? (int)m_uiBlocklength : (std::min)( (int)m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount) ); + iNumSamples = ( m_bPeriodic ? ( int ) m_uiBlocklength : ( std::min )( ( int ) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ) ); - for (int i=0;i<iNumSamples;i++) { - float x = fmodf((float) m_iSampleCount++, (float) m_iPeriodLengthSamples); + for( int i = 0; i < iNumSamples; i++ ) + { + float x = fmodf( ( float ) m_iSampleCount++, ( float ) m_iPeriodLengthSamples ); - pfOutputData[i] = x < N/2 ? 2*(x*gradient) : 2*((-x*gradient)+a); + pfOutputData[ i ] = x < N / 2 ? 2 * ( x*gradient ) : 2 * ( ( -x*gradient ) + a ); } break; - + case SAWTOOTH: // S�gezahn - iNumSamples = (m_bPeriodic ? (int) m_uiBlocklength : (std::min)( (int) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount) ); - - for (int i=0;i<iNumSamples;i++) { + iNumSamples = ( m_bPeriodic ? ( int ) m_uiBlocklength : ( std::min )( ( int ) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ) ); - float x = fmodf((float) m_iSampleCount++, (float) m_iPeriodLengthSamples); - pfOutputData[i] = a * (x*gradient); + for( int i = 0; i < iNumSamples; i++ ) { + + float x = fmodf( ( float ) m_iSampleCount++, ( float ) m_iPeriodLengthSamples ); + pfOutputData[ i ] = a * ( x*gradient ); } break; - + case RECTANGLE: - // Position des Wechsels von 1 zu 0 innerhalb einer Periode - iZero = (int)(m_iPeriodLengthSamples / 2); - iNumSamples = (m_bPeriodic ? (int) m_uiBlocklength : (std::min)((int) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount) ); + // Position des Wechsels von 1 zu 0 innerhalb einer Periode + iZero = ( int ) ( m_iPeriodLengthSamples / 2 ); + iNumSamples = ( m_bPeriodic ? ( int ) m_uiBlocklength : ( std::min )( ( int ) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ) ); - for (int i=0; i<iNumSamples; i++) - { - // Position innerhalb einer Periodenl�nge - float x = fmodf((float) m_iSampleCount++, (float) m_iPeriodLengthSamples); - int iOffset = (int) roundf(x); - pfOutputData[i] = (iOffset < iZero ? a : 0); - } + for( int i = 0; i < iNumSamples; i++ ) + { + // Position innerhalb einer Periodenl�nge + float x = fmodf( ( float ) m_iSampleCount++, ( float ) m_iPeriodLengthSamples ); + int iOffset = ( int ) roundf( x ); + pfOutputData[ i ] = ( iOffset < iZero ? a : 0 ); + } - break; + break; case DIRAC: - - iNumSamples = (m_bPeriodic ? (int) m_uiBlocklength : (std::min)( (int) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ) ); - - if (m_bPeriodic) { - - for (int i=0;i<iNumSamples;i++) pfOutputData[i] = ( m_iSampleCount++ % N ? 0 : a ); - } else { - pfOutputData[0] = (m_iSampleCount == 0 ? a : 0); - for (int i=1;i<iNumSamples;i++) pfOutputData[i] = 0; + + iNumSamples = ( m_bPeriodic ? ( int ) m_uiBlocklength : ( std::min )( ( int ) m_uiBlocklength, m_iPeriodLengthSamples - m_iSampleCount ) ); + + if( m_bPeriodic ) + { + + for( int i = 0; i < iNumSamples; i++ ) pfOutputData[ i ] = ( m_iSampleCount++ % N ? 0 : a ); + } + else { + pfOutputData[ 0 ] = ( m_iSampleCount == 0 ? a : 0 ); + for( int i = 1; i < iNumSamples; i++ ) pfOutputData[ i ] = 0; m_iSampleCount += iNumSamples; } break; - case WHITE_NOISE: + case WHITE_NOISE: + + srand( 100 ); + for( unsigned int i = 0; i < m_uiBlocklength; i++ ) + pfOutputData[ i ] = a * ( float ) rand() / RAND_MAX; - srand(100); - for(unsigned int i= 0; i< m_uiBlocklength; i++) - pfOutputData[i] = a * (float)rand()/ RAND_MAX; - - break; - // ... + break; + // ... default: // Case: Invalid signal function => Generate zeros - for (unsigned int i=0; i<m_uiBlocklength; i++) - pfOutputData[i] = 0; + for( unsigned int i = 0; i < m_uiBlocklength; i++ ) + pfOutputData[ i ] = 0; } /* @@ -225,9 +220,9 @@ void ITAStreamFunctionGenerator::ProcessStream(const ITAStreamInfo* pStreamInfo) * then copy the data into all further channels. */ - for (unsigned int c=1; c<m_uiChannels; c++) - memcpy( GetWritePointer(c), pfOutputData, m_uiBlocklength * sizeof(float) ); - + for( unsigned int c = 1; c < m_uiChannels; c++ ) + memcpy( GetWritePointer( c ), pfOutputData, m_uiBlocklength * sizeof( float ) ); + IncrementWritePointer(); } diff --git a/tests/AsioTests/CMakeLists.txt b/tests/AsioTests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..84d328a0bb2090b820167e6cde40392769e1b486 --- /dev/null +++ b/tests/AsioTests/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required( VERSION 2.8 ) + +project( NativeAsioSingleInstanceTests ) +list( APPEND CMAKE_MODULE_PATH "$ENV{VISTA_CMAKE_COMMON}" ) +include( VistaCommon ) + +vista_use_package( asio REQUIRED FIND_DEPENDENCIES ) +vista_use_package( VistaCoreLibs REQUIRED COMPONENTS VistaBase VistaInterProcComm FIND_DEPENDENCIES ) + +add_definitions( -DIEEE754_64FLOAT ) # ASIOSamplerate -> double + +add_executable( NativeAsioSingleInstanceTest NativeAsioSingleInstanceTest.cpp ) +target_link_libraries( NativeAsioSingleInstanceTest ${VISTA_USE_PACKAGE_LIBRARIES} ) + +vista_configure_app( NativeAsioSingleInstanceTest ) +vista_install( NativeAsioSingleInstanceTest ) +vista_create_default_info_file( NativeAsioSingleInstanceTest ) + +set_property( TARGET NativeAsioSingleInstanceTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Asio" ) + +add_executable( NativeAsioThreadedMultiInstanceTest NativeAsioThreadedMultiInstanceTest.cpp ) +target_link_libraries( NativeAsioThreadedMultiInstanceTest ${VISTA_USE_PACKAGE_LIBRARIES} ) + +vista_configure_app( NativeAsioThreadedMultiInstanceTest ) +vista_install( NativeAsioThreadedMultiInstanceTest ) +vista_create_default_info_file( NativeAsioThreadedMultiInstanceTest ) + +set_property( TARGET NativeAsioThreadedMultiInstanceTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/Asio" ) diff --git a/tests/AsioTests/NativeAsioSingleInstanceTest.cpp b/tests/AsioTests/NativeAsioSingleInstanceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cc1f3b9aeab6cd1b925e4b39b1862585edcbb52 --- /dev/null +++ b/tests/AsioTests/NativeAsioSingleInstanceTest.cpp @@ -0,0 +1,136 @@ +#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* AsioBufferSwitchTimeInfo( ASIOTime *timeInfo, long, ASIOBool ) +{ + return timeInfo; +}; + +void AsioBufferSwitch( 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; + + AsioBufferSwitchTimeInfo( &timeInfo, nIndex, processNow ); +}; + +void AsioSampleRateChanged( ASIOSampleRate fs ) +{ + cout << "Sample rate changed to " << fs << endl; + return; +}; + +long AsioMessages( 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; + + for( int i = 0; i < nNumDrivers; i++ ) + { + int iDriverIndex = int( i ); + AsioDrivers* pDriver = new AsioDrivers(); + + string sDriverName; + sDriverName.resize( 256 ); + pDriver->asioGetDriverName( iDriverIndex, &sDriverName[ 0 ], int( sDriverName.size() ) ); + sDriverName = std::string( sDriverName.c_str() ); // Strip + cout << "Driver name: " << sDriverName << "." << endl; + + bool bLoadSuccess = pDriver->loadDriver( &sDriverName[ 0 ] ); + if( bLoadSuccess ) + { + string sDriverPath; + sDriverPath.resize( 256 ); + pDriver->asioGetDriverPath( iDriverIndex, &sDriverPath[ 0 ], int( sDriverPath.size() ) ); + sDriverPath = std::string( sDriverPath.c_str() ); // Strip + cout << "Driver path: " << sDriverPath << endl; + + cout << "Current driver index: " << pDriver->getCurrentDriverIndex() << endl; + + string sCurrentDriverName; + sCurrentDriverName.resize( 256 ); + pDriver->getCurrentDriverName( &sCurrentDriverName[ 0 ] ); + sCurrentDriverName = std::string( sCurrentDriverName.c_str() ); // Strip + cout << "Current driver name: " << sCurrentDriverName << endl; + + ASIODriverInfo oDriverInfo; + oDriverInfo.asioVersion = 2; + if( ASIOInit( &oDriverInfo ) != ASE_OK ) + { + cout << "Could not initialize " << sCurrentDriverName << ", skipping." << endl; + continue; + } + + long iInputLatencyDeviceA, iOutputLatencyDeviceA; + ASIOError ae = ASIOGetLatencies( &iInputLatencyDeviceA, &iOutputLatencyDeviceA ); + + ASIOCallbacks oAsioCallback; + oAsioCallback.asioMessage = &AsioMessages; + oAsioCallback.bufferSwitch = &AsioBufferSwitch; + oAsioCallback.bufferSwitchTimeInfo = &AsioBufferSwitchTimeInfo; + oAsioCallback.sampleRateDidChange = &AsioSampleRateChanged; + + vector< ASIOBufferInfo > voBufferInfos( 4 ); + voBufferInfos[ 0 ].buffers; + voBufferInfos[ 0 ].channelNum = 0; + voBufferInfos[ 0 ].isInput = ASIOTrue; + voBufferInfos[ 1 ].buffers; + voBufferInfos[ 1 ].channelNum = 1; + voBufferInfos[ 1 ].isInput = ASIOTrue; + voBufferInfos[ 2 ].buffers; + voBufferInfos[ 2 ].channelNum = 0; + voBufferInfos[ 2 ].isInput = ASIOFalse; + voBufferInfos[ 3 ].buffers; + voBufferInfos[ 3 ].channelNum = 1; + voBufferInfos[ 3 ].isInput = ASIOFalse; + + ASIOSampleRate fs; + if( ASIOGetSampleRate( &fs ) == ASE_NotPresent ) + continue; + + long minSize, maxSize, preferredSize, granularity; + ae = ASIOGetBufferSize( &minSize, &maxSize, &preferredSize, &granularity ); + preferredSize = ( preferredSize == 0 ? min( 1024, maxSize ) : preferredSize ); + + + ae = ASIOCreateBuffers( &voBufferInfos.front(), 4, preferredSize, &oAsioCallback ); + assert( ae == ASE_OK ); + + ae = ASIOStart(); + assert( ae == ASE_OK ); + + VistaTimeUtils::Sleep( int( 2e3 ) ); + + ae = ASIOStop(); + assert( ae == ASE_OK ); + + } + + pDriver->removeCurrentDriver(); + delete pDriver; + } + + return 0; +} diff --git a/tests/AsioTests/NativeAsioThreadedMultiInstanceTest.cpp b/tests/AsioTests/NativeAsioThreadedMultiInstanceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79c365de6e2df80a77662d916f906c80dde5d8d5 --- /dev/null +++ b/tests/AsioTests/NativeAsioThreadedMultiInstanceTest.cpp @@ -0,0 +1,142 @@ +#include <cassert> +#include <conio.h> +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> +#include <map> + +#include <host/asiodrivers.h> +#include <common/asio.h> + +#include <VistaBase/VistaTimeUtils.h> +#include <VistaInterProcComm/Concurrency/VistaThread.h> + +// Errors are validated ussing assertions. Run this in debug, only. + +using namespace std; + +AsioDriverList g_oAsioDriverList; + +class CThreadedASIO; +typedef map< long, CThreadedASIO* > CThreadedASIORegistry; +CThreadedASIORegistry g_oRegistry; + +class CThreadedASIO : public VistaThread +{ +public: + inline CThreadedASIO( const int iDriverIndex ) + : m_iDriverIndex( iDriverIndex ) + { + ASIOError ae; + + assert( m_iDriverIndex < g_oAsioDriverList.asioGetNumDev() && m_iDriverIndex >= 0 ); + m_sDriverName.resize( 256 ); + m_oDriver.asioGetDriverName( m_iDriverIndex, &m_sDriverName[ 0 ], int( m_sDriverName.size() ) ); + m_sDriverName = std::string( m_sDriverName.c_str() ); // Strip + + cout << "[" << m_sDriverName << "] Initializing ASIO from thread " << VistaThread::GetThreadIdentity() << endl; + + VistaTimeUtils::Sleep( 1000 ); + + bool bLoadSuccess = m_oDriver.loadDriver( &m_sDriverName[ 0 ] ); + assert( bLoadSuccess ); + + VistaTimeUtils::Sleep( 1000 ); + + ASIODriverInfo oDriverInfo; + oDriverInfo.asioVersion = 2; + assert( ( ae = ASIOInit( &oDriverInfo ) ) == ASE_OK ); + + ASIOCallbacks oAsioCallback; + oAsioCallback.asioMessage = &( CThreadedASIO::AsioMessages ); + oAsioCallback.bufferSwitch = &( CThreadedASIO::AsioBufferSwitch ); + oAsioCallback.bufferSwitchTimeInfo = &( CThreadedASIO::AsioBufferSwitchTimeInfo ); + oAsioCallback.sampleRateDidChange = &( CThreadedASIO::AsioSampleRateChanged ); + + vector< ASIOBufferInfo > voBufferInfos( 4 ); + voBufferInfos[ 0 ].buffers; + voBufferInfos[ 0 ].channelNum = 0; + voBufferInfos[ 0 ].isInput = ASIOTrue; + voBufferInfos[ 1 ].buffers; + voBufferInfos[ 1 ].channelNum = 1; + voBufferInfos[ 1 ].isInput = ASIOTrue; + voBufferInfos[ 2 ].buffers; + voBufferInfos[ 2 ].channelNum = 0; + voBufferInfos[ 2 ].isInput = ASIOFalse; + voBufferInfos[ 3 ].buffers; + voBufferInfos[ 3 ].channelNum = 1; + voBufferInfos[ 3 ].isInput = ASIOFalse; + + ASIOSampleRate fs; + assert( ASIOGetSampleRate( &fs ) == ASE_OK ); + + long minSize, maxSize, preferredSize, granularity; + ASIOError aeResult = ASIOGetBufferSize( &minSize, &maxSize, &preferredSize, &granularity ); + preferredSize = ( preferredSize == 0 ? min( 1024, maxSize ) : preferredSize ); + + assert( ASE_OK == ASIOCreateBuffers( &voBufferInfos.front(), 4, preferredSize, &oAsioCallback ) ); + + g_oRegistry[ VistaThread::GetThreadIdentity() ] = this; + + assert( ASE_OK == ASIOStart() ); + cout << "[" << m_sDriverName << "] Started ASIO from thread " << VistaThread::GetThreadIdentity() << endl; + VistaTimeUtils::Sleep( 10000 ); + assert( ASE_OK == ASIOStop() ); + }; + + inline void ThreadBody() + { + }; + + inline static ASIOTime* AsioBufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool processNow ) + { + return timeInfo; + }; + + inline static void AsioBufferSwitch( long index, ASIOBool processNow ) + { + ASIOTime timeInfo; + memset( &timeInfo, 0, sizeof( timeInfo ) ); + + if( ASIOGetSamplePosition( &timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime ) == ASE_OK ) + timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; + + AsioBufferSwitchTimeInfo( &timeInfo, index, processNow ); + + long iThreadID = VistaThread::GetCallingThreadIdentity(); + cout << "Buffer switch called from thread " << iThreadID << endl; + //g_oRegistry[ iThreadID ]; + }; + + inline static void AsioSampleRateChanged( ASIOSampleRate fs ) + { + cout << "Sample rate changed to " << fs << endl; + return; + }; + + inline static long AsioMessages( long selector, long value, void*, double* ) + { + return 0; + }; + +private: + int m_iDriverIndex; + std::string m_sDriverName; + AsioDrivers m_oDriver; +}; + + +int main( int, char[] ) +{ + cout << "Main thread is called by " << VistaThread::GetCallingThreadIdentity() << endl; + CThreadedASIO oAsio1( 1 ); + //CThreadedASIO oAsio2( 1 ); + + oAsio1.Run(); + //oAsio2.Run(); + + VistaTimeUtils::Sleep( 10000 ); + + return 0; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8450837cb85f7fcdf16a291af874f62945e5ffe6..a3c3b5d19461463e56d81506c70e5421324be945 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -117,6 +117,7 @@ set_property( TARGET StreamProbeTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataS # tests if( ITA_DATA_SOURCES_WITH_INTEGRATED_ASIO ) add_subdirectory( ITAAsioTests ) + add_subdirectory( AsioTests ) endif( ITA_DATA_SOURCES_WITH_INTEGRATED_ASIO ) if( ITA_DATA_SOURCES_WITH_INTEGRATED_PORTAUDIO ) diff --git a/tests/ITAAsioTests/ThreadInit.cpp b/tests/ITAAsioTests/ThreadInit.cpp index 6c6fb63c4a6f5965c069e2a1a685914fdc0a7fb1..96a8dc3907cbf5f76411be327098c6ed863ffdab 100644 --- a/tests/ITAAsioTests/ThreadInit.cpp +++ b/tests/ITAAsioTests/ThreadInit.cpp @@ -1,56 +1,48 @@ -/* - +------------------------------------------------------------+ - | | - | ThreadInit.cpp | - | | - | Testprogramm aus der Testsuite des ITAsioInterface | - | | - | Beschreibung: Test zur ASIO-Initialisierung | - | in Threads | - | | - | Author: Frank Wefers | - | Letzte �nderung: 13.04.2011 [stienen] | - | | - | (c) Copyright Institut f�r technische Akustik (ITA) | - | Aachen university of technology (RWTH), 2011 | - | | - +------------------------------------------------------------+ -*/ - -// $Id: ThreadInit.cpp 1801 2011-04-13 14:07:25Z stienen $ - #include <ITAAsioInterface.h> + #include <process.h> #include <stdio.h> #include <string> -#define _WIN32_WINNT 0x0500 +#ifndef _WIN32_WINNT // @todo: remove +#define _WIN32_WINNT 0x0501 +#endif + #include <windows.h> -int test(const char* pszDriverName) { + +int test( const char* pszDriverName ) +{ ITAsioInitializeLibrary(); // Treiber anzeigen long lDrivers = ITAsioGetNumDrivers(); - if (lDrivers > 0) { - printf("Folgende ASIO-Treiber wurden gefunden:\n\n"); - for (long i=0; i<lDrivers; i++) { - printf("\t[%d]\t%s\n", i+1, ITAsioGetDriverName(i)); + if( lDrivers > 0 ) + { + printf( "Folgende ASIO-Treiber wurden gefunden:\n\n" ); + for( long i = 0; i < lDrivers; i++ ) + { + printf( "\t[%d]\t%s\n", i + 1, ITAsioGetDriverName( i ) ); } - } else { - printf("Keine ASIO-Treiber gefunden!\n"); + } + else + { + printf( "Keine ASIO-Treiber gefunden!\n" ); return 0; - }; + } // Treiber initialisieren - printf("Initialisiere Treiber \"%s\"\n", pszDriverName); + printf( "Initialisiere Treiber \"%s\"\n", pszDriverName ); ASIOError ae = ITAsioInitializeDriver( pszDriverName ); - if (ae == ASE_OK) { - printf("Initialisierung erfolgreich!"); + if( ae == ASE_OK ) + { + printf( "Initialisierung erfolgreich!" ); ITAsioFinalizeDriver(); - } else { - printf("Initialisierung fehlgeschlagen (errorcode %d: %s)\n", - ae, ITAsioGetErrorStr(ae)); + } + else + { + printf( "Initialisierung fehlgeschlagen (errorcode %d: %s)\n", ae, ITAsioGetErrorStr( ae ) ); + return -1; } @@ -59,36 +51,44 @@ int test(const char* pszDriverName) { return 0; } -void ThreadProc(void* pParam) { - printf("Thread ist gestartet!\n"); +void ThreadProc( void* pParam ) +{ + printf( "Thread ist gestartet!\n" ); // COM initialisieren (Appartment) //CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - if (test((const char*) pParam) != 0) { + if( test( ( const char* ) pParam ) != 0 ) + { //CoUninitialize(); } _endthread(); } -int main(int argc, char* argv[]) { +int main( int argc, char* argv[] ) +{ // COM initialisieren (Appartment) //CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - if (argc != 2) { - fprintf(stderr, "Syntax: ThreadInit TREIBERNUMMER\n"); + if( argc != 2 ) + { + fprintf( stderr, "Syntax: ThreadInit TREIBERNUMMER\n" ); return 255; } bool bThreaded = true; - if (bThreaded) { - HANDLE hThread = (HANDLE) _beginthread( ThreadProc, 0, argv[1] ); - WaitForSingleObject(hThread, INFINITE); - } else - test(argv[1]); + if( bThreaded ) + { + HANDLE hThread = ( HANDLE ) _beginthread( ThreadProc, 0, argv[ 1 ] ); + WaitForSingleObject( hThread, INFINITE ); + } + else + { + test( argv[ 1 ] ); + } //CoUninitialize(); diff --git a/tests/ITAPortaudioTests/CMakeLists.txt b/tests/ITAPortaudioTests/CMakeLists.txt index 0033635819c77563c322fdc945a0ab805595e7e3..a1819c4948c2dde0d8ba06336a106ad1f55a1e16 100644 --- a/tests/ITAPortaudioTests/CMakeLists.txt +++ b/tests/ITAPortaudioTests/CMakeLists.txt @@ -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" ) diff --git a/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.cpp b/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa364eccf16fe8e51b1389bbb5c176a2a0efdb8d --- /dev/null +++ b/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.cpp @@ -0,0 +1,151 @@ +// ITADataSources +#include <ITADataSourceUtils.h> +#include <ITAPortaudioInterface.h> +#include <ITAStreamProbe.h> +#include <ITAFileDataSource.h> +#include <ITAStreamMultiplier1N.h> + +// ITABase +#include <ITAException.h> +#include <ITAStringUtils.h> + +// STL +#include <iostream> +#include <string> + +using namespace std; +void list_portaudio_devices(); + +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 + const int iDeviceA = StringToInt( string( argv[ 1 ] ) ) - 1; + const int iDeviceB = StringToInt( string( argv[ 2 ] ) ) - 1; + string sExcitationSignalPath = string( argv[ 3 ] ); + string sRecordingSignalPathA = string( argv[ 4 ] ); + string sRecordingSignalPathB = string( argv[ 5 ] ); + const double dSampleRate = StringToDouble( string( argv[ 6 ] ) ); + const int iBlockLength = StringToInt( string( argv[ 7 ] ) ); + + + // --- Device A --- + + ITAPortaudioInterface oPADeviceA( dSampleRate, iBlockLength ); + ITAPortaudioInterface::ITA_PA_ERRORCODE err; + if( ( err = oPADeviceA.Initialize( iDeviceA ) ) != ITAPortaudioInterface::ITA_PA_NO_ERROR ) + ITA_EXCEPT1( INVALID_PARAMETER, "Could not initialize device A: " + ITAPortaudioInterface::GetErrorCodeString( err ) ); + + string sDeviceA = oPADeviceA.GetDeviceName( iDeviceA ); + cout << "Device A device identifier: " << sDeviceA << endl; + int iNumInputChannelsA, iNumOutputChannelsA; + oPADeviceA.GetNumChannels( iDeviceA, iNumInputChannelsA, iNumOutputChannelsA ); + + if( iNumInputChannelsA == 0 || iNumOutputChannelsA == 0 ) + ITA_EXCEPT1( INVALID_PARAMETER, "Not enough I/O channels for device A: " + sDeviceA ); + + cout << "Using " << iNumOutputChannelsA << " outputs and " << iNumInputChannelsA << " inputs for device A" << endl; + + + ITAFileDatasource oPlaybackA( sExcitationSignalPath, iBlockLength ); + if( oPlaybackA.GetNumberOfChannels() != 1 ) + ITA_EXCEPT_INVALID_PARAMETER( "Excitation signal must be single channel" ); + + + ITAStreamMultiplier1N oMultiplierA( &oPlaybackA, iNumOutputChannelsA ); + + oPADeviceA.SetPlaybackEnabled( true ); + oPADeviceA.SetPlaybackDatasource( &oMultiplierA ); + + oPADeviceA.SetRecordEnabled( true ); + ITAStreamProbe oRecordStreamProbeA( oPADeviceA.GetRecordDatasource(), sRecordingSignalPathA ); + + + // --- Device B --- + + ITAPortaudioInterface oPADeviceB( dSampleRate, iBlockLength ); + oPADeviceB.Initialize( iDeviceB ); + string sDeviceB = oPADeviceB.GetDeviceName( iDeviceB ); + cout << "Device B device identifier: " << sDeviceB << endl; + int iNumInputChannelsB, iNumOutputChannelsB; + oPADeviceB.GetNumChannels( iDeviceB, iNumInputChannelsB, iNumOutputChannelsB ); + + if( iNumInputChannelsB == 0 || iNumOutputChannelsB == 0 ) + ITA_EXCEPT1( INVALID_PARAMETER, "Not enough I/O channels for device B: " + sDeviceB ); + + cout << "Using " << iNumOutputChannelsB << " outputs and " << iNumInputChannelsB << " inputs for device B" << endl; + + ITAFileDatasource oPlaybackB( sExcitationSignalPath, iBlockLength ); + if( oPlaybackB.GetNumberOfChannels() != 1 ) + ITA_EXCEPT_INVALID_PARAMETER( "Excitation signal must be single channel" ); + + ITAStreamMultiplier1N oMultiplierB( &oPlaybackB, iNumOutputChannelsB ); + + oPADeviceB.SetPlaybackEnabled( true ); + oPADeviceB.SetPlaybackDatasource( &oMultiplierB ); + + oPADeviceB.SetRecordEnabled( true ); + ITAStreamProbe oRecordStreamProbeB( oPADeviceB.GetRecordDatasource(), sRecordingSignalPathB ); + + + // --- Run latency measurement --- + + // Open + oPADeviceA.Open(); + oPADeviceB.Open(); + + // Start streaming + oPADeviceA.Start(); + oPADeviceB.Start(); + + // Measurement + std::vector< float* > vpfSamples; + std::vector< std::vector< float >* > vpfSamplesVector; + for( unsigned int i = 0; i < oRecordStreamProbeB.GetNumberOfChannels(); i++ ) + { + std::vector< float >* pvfData = new std::vector< float >( oPlaybackA.GetFileCapacity() ); + vpfSamplesVector.push_back( pvfData ); + vpfSamples.push_back( &( *pvfData )[ 0 ] ); + } + //WriteFromDatasourceToBuffer( &oRecordStreamProbeA, &vpfSamples[ 0 ], oPlaybackA.GetFileCapacity(), 1.0, true, true ); + WriteFromDatasourceToBuffer( &oRecordStreamProbeB, &vpfSamples[ 0 ], oPlaybackB.GetFileCapacity(), 1.0, true, true ); + + for( size_t i = 0; i < vpfSamplesVector.size(); i++ ) + delete vpfSamplesVector[ i ]; + + // Stop streaming + oPADeviceA.Stop(); + oPADeviceB.Stop(); + + // Close + oPADeviceA.Close(); + oPADeviceB.Close(); + + // Finalize + oPADeviceA.Finalize(); + oPADeviceB.Finalize(); + } + catch( const ITAException& e ) + { + cerr << e << endl; + cout << "Listing all available Portaudio devices: " << endl; + list_portaudio_devices(); + } + + return 0; +} + +void list_portaudio_devices() +{ + ITAPortaudioInterface oITAPA( 44.1e3, 1024 ); + oITAPA.Initialize(); + int iPANumDevices = oITAPA.GetNumDevices(); + for( int i = 0; i < iPANumDevices; i++ ) + cout << "[" << i + 1 << "] \"" << oITAPA.GetDeviceName( i ) << "\"" << endl; + cout << endl; + oITAPA.Finalize(); +} diff --git a/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.m b/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.m new file mode 100644 index 0000000000000000000000000000000000000000..8f79cc5f252fa90286ced8222325e016e908cce5 --- /dev/null +++ b/tests/ITAPortaudioTests/ReciprocalDAADLatencyMeasurement.m @@ -0,0 +1,10 @@ +%% Generate excitation signal +sweep_raw = ita_generate_sweep; +ita_write_wav( sweep_raw, 'sweep.wav', 'nBits', 32, 'overwrite' ); + +%% Evaluate recording +recordA = ita_read( 'recordA.wav' ); +recordB = ita_read( 'recordB.wav' ); + +recordA.pt +recordB.pt diff --git a/tests/NetAudio/CMakeLists.txt b/tests/NetAudio/CMakeLists.txt index a45e28828b665672c5da44de07e13f8b2dfb02e2..0216f8f5988b0f3ad25b7a4907d859c4b99a4c11 100644 --- a/tests/NetAudio/CMakeLists.txt +++ b/tests/NetAudio/CMakeLists.txt @@ -68,11 +68,12 @@ if( ITA_DATA_SOURCES_WITH_INTEGRATED_ASIO ) vista_install( ITANetAudioTest ) vista_create_default_info_file( ITANetAudioTest ) + set_property( TARGET ITANetAudioTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/NetAudio" ) + endif( ) vista_install_all_dlls( bin ) -set_property( TARGET ITANetAudioTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/NetAudio" ) if( NOT DEFINED ITA_NETAUDIO_SERVER_WITH_TESTS ) set( ITA_NETAUDIO_SERVER_WITH_TESTS "localhost 12480 44100 32 2" CACHE STRING "Arguments for calling NetAudio server") diff --git a/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp b/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp index 18c16dee40faa919fde14a3221955a56ecb2f7a0..65eca7b285e9745f02e11ca58b5711a0cf0cec1a 100644 --- a/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp +++ b/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp @@ -6,7 +6,7 @@ #include <ITAException.h> #include <ITAFileDataSource.h> #include <ITAStreamProbe.h> -#include <ITAStreamPatchbay.h> +#include <ITAStreamPatchBay.h> using namespace std; int main(int argc, char* argv[])