diff --git a/include/ITASIMOVariableDelayLine.h b/include/ITASIMOVariableDelayLine.h index e28110e0181543665cbcc1f6ef44fd6f04ee4a69..a11f27d18661f1e3f9c3f64a0b185cd53c02eed5 100644 --- a/include/ITASIMOVariableDelayLine.h +++ b/include/ITASIMOVariableDelayLine.h @@ -268,11 +268,32 @@ public: void Clear(); //! Pushes a block of samples at front of delay line + /** + * Writes a block of samples to the input of the VDL. + * Does not increment block, has to be done manually (i.e. after read) + * + * @note block-oriented VDL usage is usually a three-step process: write-read-increment. + * + * @param[in] psbInput Buffer source for incoming samples + */ void WriteBlock( const ITASampleBuffer* psbInput ); //! Reads a block of samples for a read cursor and switches to new delay + /** + * @note Incremet block processing after all cursors have benn processed / read. + * + * @param[in] iID Cursor identifier + * @param[out] psbOutput Buffer target for processed samples (must be initialized) + */ void ReadBlock( const int iID, ITASampleBuffer* psbOutput ); + //! Increments processing to next block + /** + * @note Make sure that all cursors have been processed, i.e. have read a block from + * the delay line. Otherwise, dropouts occur. + */ + void Increment(); + //! Reads a block of samples at all cursors (switches to new delay) /** * The order of the channels in the sample frame will be linear over the @@ -281,13 +302,13 @@ public: * @param[in] psfOutput Initialized sample frame * */ - void ReadBlock( ITASampleFrame* psfOutput ); + void ReadBlockAndIncrement( ITASampleFrame* psfOutput ); private: double m_dSampleRate; //!< Audio-Abtastrate int m_iBlockLength; //!< Audio-Blockgr��e int m_iVDLBufferSize; //!< Gr��e des Puffers zum Speichern verz�gerter Samples - ITASampleBuffer* m_psbVDLBuffer; //!< Puffer zum Speichern verz�gerter Samples (variable Gr��e, mindestens 2xBlockl�nge) + ITASampleBuffer* m_psbVDLBuffer; //!< Buffer for samples (variable size at multiples of block leng, but minimum is 2 blocks) ITASampleBuffer* m_psbTemp; //!< Tempor�rer Puffer zum Arbeiten mit Samples (Gr��e: 2xBlockl�nge) (das k�nnte evtl. knapp sein) ITACriticalSection m_csBuffer; //!< Zugriff auf Puffer sch�tzen @@ -302,6 +323,7 @@ private: bool m_bStarted; //!< Statusvariable zur Initialisierung + bool m_bBenchmark; ITAStopWatch m_swProcess; //!< StopWatch zur �berwachung der Berechnungsschleife IITASampleInterpolationRoutine* m_pInterpolationRoutine; //!< Zeiger auf Interpolationsroutine diff --git a/src/ITASIMOVariableDelayLine.cpp b/src/ITASIMOVariableDelayLine.cpp index acf3b4aff9875ab39a787c89259cda93333b1dca..7ff05283f93116a08e9e4b33120e6914a7fbba02 100644 --- a/src/ITASIMOVariableDelayLine.cpp +++ b/src/ITASIMOVariableDelayLine.cpp @@ -22,7 +22,8 @@ CITASIMOVariableDelayLine::CITASIMOVariableDelayLine( const double dSamplerate, m_iSwitchingAlgorithm( iAlgorithm ), m_psbVDLBuffer( nullptr ), m_psbTemp( nullptr ), - m_pInterpolationRoutine( nullptr ) + m_pInterpolationRoutine( nullptr ), + m_bBenchmark( false ) { assert( dSamplerate > 0 ); assert( iBlocklength > 0 ); @@ -49,7 +50,7 @@ CITASIMOVariableDelayLine::CITASIMOVariableDelayLine( const double dSamplerate, void CITASIMOVariableDelayLine::Clear() { - m_psbVDLBuffer->Zero(); + m_psbVDLBuffer->Zero(); // Very important, because on small delays the potentially unititialized end of VDL is also read m_psbTemp->Zero(); m_iWriteCursor = 0; @@ -59,16 +60,6 @@ void CITASIMOVariableDelayLine::Clear() m_swProcess.reset(); } -void CITASIMOVariableDelayLine::WriteBlock( const ITASampleBuffer* psbInput ) -{ - if( !m_bStarted ) - m_bStarted = true; - - assert( m_iWriteCursor % m_iBlockLength == 0 ); - m_psbVDLBuffer->write( psbInput, m_iBlockLength, 0, m_iWriteCursor ); - m_iWriteCursor = ( m_iWriteCursor + m_iBlockLength ) % m_iVDLBufferSize; -} - CITASIMOVariableDelayLine::~CITASIMOVariableDelayLine() { delete m_psbVDLBuffer; @@ -132,7 +123,7 @@ void CITASIMOVariableDelayLine::ReserveMaximumDelaySamples( float fMaxDelaySampl * nur durch den Konstruktor aufgerufen wird */ - m_psbVDLBuffer = new ITASampleBuffer( iNewBufferSize, true ); + m_psbVDLBuffer = new ITASampleBuffer( iNewBufferSize, true ); // Important! set all samples to zero. m_iVDLBufferSize = iNewBufferSize; m_iWriteCursor = 0; @@ -152,7 +143,7 @@ void CITASIMOVariableDelayLine::ReserveMaximumDelaySamples( float fMaxDelaySampl int iOldBufferSize = m_psbVDLBuffer->length(); // Vorhandene Daten zyklisch Kopieren (aktuelle Schreibposition => Anfang abrollen) - ITASampleBuffer* psbNewBuffer = new ITASampleBuffer( iNewBufferSize, true ); + ITASampleBuffer* psbNewBuffer = new ITASampleBuffer( iNewBufferSize, true ); // Important! set all samples to zero. psbNewBuffer->cyclic_write( m_psbVDLBuffer, iNewBufferSize, m_iWriteCursor, 0 ); // Alten Puffer freigeben, neuen zuweisen @@ -241,7 +232,7 @@ void CITASIMOVariableDelayLine::SetDelaySamples( const int iID, const float fDel CITAVDLReadCursor& oReadCursor( m_lUserCursors[ iID ] ); oReadCursor.fNewReadCursorSamples = fDelaySamples; - // If not started, set both + // If not started, set both to avoid artifact on first block if( !m_bStarted ) oReadCursor.fOldReadCursorSamples = fDelaySamples; } @@ -251,7 +242,16 @@ void CITASIMOVariableDelayLine::SetDelayTime( const int iCursorID, const float f SetDelaySamples( iCursorID, fDelaySeconds * ( float ) m_dSampleRate ); } -void CITASIMOVariableDelayLine::ReadBlock( ITASampleFrame* psfOutput ) +void CITASIMOVariableDelayLine::WriteBlock( const ITASampleBuffer* psbInput ) +{ + if( !m_bStarted ) + m_bStarted = true; + + assert( m_iWriteCursor % m_iBlockLength == 0 ); + m_psbVDLBuffer->write( psbInput, m_iBlockLength, 0, m_iWriteCursor ); +} + +void CITASIMOVariableDelayLine::ReadBlockAndIncrement( ITASampleFrame* psfOutput ) { assert( psfOutput ); const std::vector< int > viIDs = GetCursorIDs(); @@ -261,6 +261,8 @@ void CITASIMOVariableDelayLine::ReadBlock( ITASampleFrame* psfOutput ) for( int i = 0; i < GetNumCursors(); i++ ) ReadBlock( viIDs[ i ], &( *psfOutput )[ i ] ); + + Increment(); } void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* psbOutput ) @@ -270,23 +272,18 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* m_swProcess.start(); - // Lokale Kopie des gew�nschten Algorithmus (Atomare Membervariable) - int iAlgorithm = m_iSwitchingAlgorithm; - - // Lokale Kopie der neuen Verz�gerung - float fCurrentDelay = m_lUserCursors[ iCursorID ].fOldReadCursorSamples; - float fNewDelay = m_lUserCursors[ iCursorID ].fNewReadCursorSamples; + int iAlgorithmLocalCopy = m_iSwitchingAlgorithm; - // --= Keine �nderung der Verz�gerung (f�r rasant schnelle statische Szenen) =-- - - if( fNewDelay == fCurrentDelay ) { - // Keine �nderung der Verz�gerung. Einfach Anfang der VDL in den Ausgang kopieren. - int iReadCursor = ( m_iWriteCursor + m_iVDLBufferSize - ( int ) ceil( fCurrentDelay ) ) % m_iVDLBufferSize; + float fCurrentDelayLocalCopy = m_lUserCursors[ iCursorID ].fOldReadCursorSamples; + float fNewDelayLocalCopy = m_lUserCursors[ iCursorID ].fNewReadCursorSamples; + + // Use a fast-forward copy in case of no new delay (static situation) + if( fNewDelayLocalCopy == fCurrentDelayLocalCopy ) + { + // No change of delay, simply copy samples from read cursor + int iReadCursor = ( m_iWriteCursor - ( int ) ceil( fCurrentDelayLocalCopy ) + m_iVDLBufferSize ) % m_iVDLBufferSize; psbOutput->cyclic_write( m_psbVDLBuffer, m_iBlockLength, iReadCursor, 0 ); - // Schreibzeiger um Blockl�nge vergr��ern (BlockPointerIncrement) - m_iWriteCursor = ( m_iWriteCursor + m_iBlockLength ) % m_iVDLBufferSize; - return; } @@ -294,18 +291,18 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* // --= �nderung der Verz�gerung =-- // Zerlegen in Ganzzahl und Kommazahl - int iCurrentIntDelay = ( int ) ceil( fCurrentDelay ); - float fCurrentFracDelay = ( float ) iCurrentIntDelay - fCurrentDelay; + int iCurrentIntDelay = ( int ) ceil( fCurrentDelayLocalCopy ); + float fCurrentFracDelay = ( float ) iCurrentIntDelay - fCurrentDelayLocalCopy; assert( fCurrentFracDelay >= 0.0f ); // Subsample darf nicht negativ sein - int iNewIntDelay = ( int ) ceil( fNewDelay ); - float fNewFracDelay = ( float ) iNewIntDelay - fNewDelay; + int iNewIntDelay = ( int ) ceil( fNewDelayLocalCopy ); + float fNewFracDelay = ( float ) iNewIntDelay - fNewDelayLocalCopy; assert( fNewFracDelay >= 0.0f ); // Subsample darf nicht negativ sein int iDeltaDelay = iNewIntDelay - iCurrentIntDelay; // Falls Interpolation gew�nscht ist, Grenzen pr�fen - if( ( iAlgorithm == LINEAR_INTERPOLATION ) || - ( iAlgorithm == WINDOWED_SINC_INTERPOLATION ) || - ( iAlgorithm == CUBIC_SPLINE_INTERPOLATION ) ) + if( ( iAlgorithmLocalCopy == LINEAR_INTERPOLATION ) || + ( iAlgorithmLocalCopy == WINDOWED_SINC_INTERPOLATION ) || + ( iAlgorithmLocalCopy == CUBIC_SPLINE_INTERPOLATION ) ) { /* @@ -335,7 +332,7 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* // Wenn Voraussetzungen verletzt werden, f�r diesen Bearbeitungsschritt auf weiches Umschalten wechseln if( ( fResamplingFactor <= MIN_RESAMPLING_FACTOR ) || ( fResamplingFactor > MAX_RESAMPLING_FACTOR ) ) { - iAlgorithm = CROSSFADE; + iAlgorithmLocalCopy = CROSSFADE; } } @@ -350,24 +347,24 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* // --= Umschaltverfahren =-- - - // TODO: - vermutlich sehen die R�mpfe f�r jede andere Interpolation �hnlich aus, sodass man mit getOverlap() vereinheitlichen kann. - // (LinInterp schon fertig, aber erst Erfahrungen mit den anderen Verfahren sammeln...) - + int iSize; int iLeft, iRight; // �berlappung an den Grenzen - switch( iAlgorithm ) + switch( iAlgorithmLocalCopy ) { // o Hartes Umschalten case SWITCH: + { // Direkt neue Verz�gerung nehmen. Einfach kopieren. Keine R�cksicht nehmen. psbOutput->cyclic_write( m_psbVDLBuffer, m_iBlockLength, iReadCursorNew, 0 ); break; + } // o Umschalten mittels Kreuzblende case CROSSFADE: + { // Kreuzblende mittels tempor�rem Puffer assert( m_iFadeLength <= m_psbTemp->length() ); // Zu gro�e Blende f�r diesen Puffer m_psbTemp->cyclic_write( m_psbVDLBuffer, m_iFadeLength, iReadCursorCurrent, 0 ); @@ -376,11 +373,11 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* psbOutput->Crossfade( m_psbTemp, 0, m_iFadeLength, ITASampleBuffer::CROSSFADE_FROM_SOURCE, ITASampleBuffer::COSINE_SQUARE ); break; - + } // o Umschalten durch Stauchen oder Strecken: Lineare Interpolation, Kubische Spline-Interpolation oder gefensterte Sinc-Interpolation default: - + { /* Zur Erkl�rung: Verringerung der Verz�gerung => Samples stauchen @@ -423,18 +420,24 @@ void CITASIMOVariableDelayLine::ReadBlock( const int iCursorID, ITASampleBuffer* m_pInterpolationRoutine->Interpolate( m_psbTemp, iInputLength, iInputStartOffset, psbOutput, m_iBlockLength ); break; - + } } // end case switch // Neue Verz�gerung speichern - m_lUserCursors[ iCursorID ].fOldReadCursorSamples = fNewDelay; - - // Schreibzeiger inkrementieren - // (Hinweis: Der Schreibzeiger ist immer Vielfaches der Blockl�nge) - m_iWriteCursor = ( m_iWriteCursor + m_iBlockLength ) % m_iVDLBufferSize; - + m_lUserCursors[ iCursorID ].fOldReadCursorSamples = fNewDelayLocalCopy; + // Zeitnahme double t = m_swProcess.stop(); + + if( m_bBenchmark && t > double( m_iBlockLength ) / m_dSampleRate ) + std::cerr << "[ SIMOVDL ] Stream processing panic, reading block for cursor " << iCursorID << " took too long: " << t << std::endl; + return; } + +void CITASIMOVariableDelayLine::Increment() +{ + // Increment write cursor by one block (BlockPointerIncrement) + m_iWriteCursor = ( m_iWriteCursor + m_iBlockLength ) % m_iVDLBufferSize; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 052b0a3c2ddfde89ae4a3628a9c79ca688a66eb5..4acfdd62a077897f3d43fd571c52767255c61e92 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -59,6 +59,16 @@ vista_create_default_info_file( ITADSPThirdOctaveFilterGeneratorTest ) set_property( TARGET ITADSPThirdOctaveFilterGeneratorTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADSP" ) +add_executable( ITADSPSIMOVDLSourceInShoebox ITADSPSIMOVDLSourceInShoebox.cpp ) +target_link_libraries( ITADSPSIMOVDLSourceInShoebox ${VISTA_USE_PACKAGE_LIBRARIES} ) + +vista_configure_app( ITADSPSIMOVDLSourceInShoebox ) +vista_install( ITADSPSIMOVDLSourceInShoebox ) +vista_create_default_info_file( ITADSPSIMOVDLSourceInShoebox ) + +set_property( TARGET ITADSPSIMOVDLSourceInShoebox PROPERTY FOLDER "ITACoreLibs/Tests/ITADSP" ) + + add_executable( ITADSPThirdOctaveFilterbankTest ITADSPThirdOctaveFilterbankTest.cpp ) target_link_libraries( ITADSPThirdOctaveFilterbankTest ${VISTA_USE_PACKAGE_LIBRARIES} ) diff --git a/tests/ITADSPBiquadTest.cpp b/tests/ITADSPBiquadTest.cpp index 1be610933a949094fa14166bd28680b226e42565..87cc3dc107d1f0d0a7073ce2b462a7a53246edf3 100644 --- a/tests/ITADSPBiquadTest.cpp +++ b/tests/ITADSPBiquadTest.cpp @@ -1,4 +1,22 @@ -#include <ITAThirdOctaveFIRFilterGenerator.h> +/* + * ---------------------------------------------------------------- + * + * ITA core libs + * (c) Copyright Institute of Technical Acoustics (ITA) + * RWTH Aachen University, Germany, 2015-2017 + * + * ---------------------------------------------------------------- + * ____ __________ _______ + * // / //__ ___/ // _ | + * // / // / // /_| | + * // / // / // ___ | + * //__/ //__/ //__/ |__| + * + * ---------------------------------------------------------------- + * + */ + +#include <ITABiquad.h> #include <ITAThirdOctaveFilterbank.h> #include <ITAAudiofileWriter.h> diff --git a/tests/ITADSPSIMOVDLSourceInShoebox.cpp b/tests/ITADSPSIMOVDLSourceInShoebox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..707e8fd6608b4e49be344a6bbc72eeabea8da87b --- /dev/null +++ b/tests/ITADSPSIMOVDLSourceInShoebox.cpp @@ -0,0 +1,170 @@ +/* + * ---------------------------------------------------------------- + * + * ITA core libs + * (c) Copyright Institute of Technical Acoustics (ITA) + * RWTH Aachen University, Germany, 2015-2017 + * + * ---------------------------------------------------------------- + * ____ __________ _______ + * // / //__ ___/ // _ | + * // / // / // /_| | + * // / // / // ___ | + * //__/ //__/ //__/ |__| + * + * ---------------------------------------------------------------- + * + * Circulates a sound source in a shoebox room including specular + * reflections off walls (perfectly hard). + * + */ + +#include <ITASIMOVariableDelayLine.h> + +#include <ITAStringUtils.h> +#include <ITAAudiofileWriter.h> +#include <ITASampleBuffer.h> +#include <ITASampleFrame.h> + +#include <ITAStreamFunctionGenerator.h> +#include <ITAFileDataSource.h> +#include <ITAStreamInfo.h> + +#include <iostream> +#include <cmath> +#include <vector> + +using namespace std; + +const float fSimulateSeconds = 20; // s +const float fShoeboxLength = 10.0f; // m +const float fShoeboxWidth = 7.0f; // m +const float fShoeboxHeight = 3.0f; // m + +const float fCircleRadiusHorizontal = 3.0f; // m +const float fCircleDuration = 3.0f; // s + +const float fSpeedOfSound = 343.0f; // m/s + +const string sInFilePath = "CirculatingSource_Signal.wav"; +const string sOutFilePath = "CirculatingSource_ShoeboxRoom.wav"; + +const unsigned int iBlockLength = 128; +const double dSampleRate = 44.1e3; + +float DistanceToPropagationTime( const float fDistanceMeter ) +{ + return fDistanceMeter / fSpeedOfSound; +} + +int main( int, char** ) +{ + assert( fCircleRadiusHorizontal * 2 < fShoeboxLength ); + assert( fCircleRadiusHorizontal * 2 < fShoeboxWidth ); + assert( 1.7f < fShoeboxHeight ); + + ITAStreamFunctionGenerator sinesignal( 1, dSampleRate, iBlockLength, ITAStreamFunctionGenerator::SINE, 500.0f, 0.5f, true ); + ITAFileDatasource filesignal( "cl-mod-bb-piece-32.wav", iBlockLength, true ); + ITADatasource* pIntputStream = &filesignal; + + assert( fShoeboxLength > fShoeboxWidth ); + const float fMaxReservedDelaySamples = float( fShoeboxLength * pow( 2, 1 ) / double( fSpeedOfSound ) * dSampleRate ); + CITASIMOVariableDelayLine* pSIMOVDL = new CITASIMOVariableDelayLine( dSampleRate, iBlockLength, fMaxReservedDelaySamples, CITASIMOVariableDelayLine::CUBIC_SPLINE_INTERPOLATION ); + + unsigned int uiNumberOfFrames = ( unsigned int ) ceil( dSampleRate * fSimulateSeconds / ( float ) iBlockLength ); + + // OpenGL coordinates + const int iCursorDirect = pSIMOVDL->AddCursor(); + const int iCursorPositiveX = pSIMOVDL->AddCursor(); + const int iCursorNegativeX = pSIMOVDL->AddCursor(); + const int iCursorPositiveY = pSIMOVDL->AddCursor(); + const int iCursorNegativeY = pSIMOVDL->AddCursor(); + const int iCursorPositiveZ = pSIMOVDL->AddCursor(); + const int iCursorNegativeZ = pSIMOVDL->AddCursor(); + + ITAAudiofileProperties props_in; + props_in.iChannels = 1; + props_in.dSampleRate = dSampleRate; + props_in.eQuantization = ITAQuantization::ITA_FLOAT; + props_in.eDomain = ITADomain::ITA_TIME_DOMAIN; + props_in.iLength = ( unsigned int ) uiNumberOfFrames * iBlockLength; + ITAAudiofileWriter* writer_in = ITAAudiofileWriter::create( sInFilePath, props_in ); + ITAAudiofileProperties props_out( props_in ); + props_out.iChannels = pSIMOVDL->GetNumCursors(); + ITAAudiofileWriter* writer_out = ITAAudiofileWriter::create( sOutFilePath, props_out ); + + ITAStreamInfo oState; + + ITASampleBuffer* psbInput = new ITASampleBuffer( iBlockLength, true ); + ITASampleFrame* psfOutput = new ITASampleFrame( pSIMOVDL->GetNumCursors(), iBlockLength, true ); + + cout << "Input file: " << sInFilePath << endl; + cout << "Processing "; + + unsigned int n = 0; + while( n < uiNumberOfFrames ) + { + // Set new delays + const double dT = double( n ) * double( iBlockLength ) / dSampleRate; + + const float fX = fCircleRadiusHorizontal * float( sin( dT / fCircleDuration ) ); + const float fY = 1.7f; + const float fZ = -fCircleRadiusHorizontal * float( cos( dT / fCircleDuration ) ); + + // Direct + const float fDelay = DistanceToPropagationTime( sqrt( fX * fX + fZ * fZ ) ); + pSIMOVDL->SetDelayTime( iCursorDirect, fDelay ); + + // Reflection positive X (right wall) + const float fX_ReflectionPositiveX = fShoeboxWidth - fX; + pSIMOVDL->SetDelayTime( iCursorPositiveX, DistanceToPropagationTime( sqrt( fX_ReflectionPositiveX * fX_ReflectionPositiveX + fZ * fZ ) ) ); + + // Reflection negative X (left wall) + const float fX_ReflectionNegativeX = -fShoeboxWidth + fX; + pSIMOVDL->SetDelayTime( iCursorNegativeX, DistanceToPropagationTime( sqrt( fX_ReflectionNegativeX * fX_ReflectionNegativeX + fZ * fZ ) ) ); + + // Reflection positive Y (ceiling) + const float fY_ReflectionPositiveY = fShoeboxHeight - fY; + pSIMOVDL->SetDelayTime( iCursorPositiveY, DistanceToPropagationTime( sqrt( fX * fX + fY_ReflectionPositiveY * fY_ReflectionPositiveY + fZ * fZ ) ) ); + + // Reflection negative Y (floor) + const float fY_ReflectionNegativeY = -fShoeboxHeight + fY; + pSIMOVDL->SetDelayTime( iCursorNegativeY, DistanceToPropagationTime( sqrt( fX * fX + fY_ReflectionNegativeY * fY_ReflectionNegativeY + fZ * fZ ) ) ); + + // Reflection positive Z (rear wall) + const float fZ_ReflectionPositiveZ = fShoeboxLength - fZ; + pSIMOVDL->SetDelayTime( iCursorPositiveZ, DistanceToPropagationTime( sqrt( fX * fX + fZ_ReflectionPositiveZ * fZ_ReflectionPositiveZ ) ) ); + + // Reflection negative Z (front wall) + const float fZ_ReflectionNegativeZ = -fShoeboxLength + fZ; + pSIMOVDL->SetDelayTime( iCursorNegativeZ, DistanceToPropagationTime( sqrt( fX * fX + fZ_ReflectionNegativeZ * fZ_ReflectionNegativeZ ) ) ); + + + // Process + psbInput->write( pIntputStream->GetBlockPointer( 0, &oState ), iBlockLength ); + pSIMOVDL->WriteBlock( psbInput ); + pSIMOVDL->ReadBlockAndIncrement( psfOutput ); + + std::vector< float* > pIn; + pIn.push_back( psbInput->data() ); + writer_in->write( iBlockLength, pIn ); + writer_out->write( psfOutput, iBlockLength ); + n++; + + pIntputStream->IncrementBlockPointer(); + + if( n % ( uiNumberOfFrames / 40 ) == 0 ) + cout << "."; + } + + cout << " done." << endl; + cout << "Output file: " << sOutFilePath << endl; + + delete writer_in; + delete writer_out; + + delete psbInput; + delete psfOutput; + + return 255; +} diff --git a/tests/ITADSPSIMOVDLSourceInShoebox.m b/tests/ITADSPSIMOVDLSourceInShoebox.m new file mode 100644 index 0000000000000000000000000000000000000000..c95b3a569b24a6d50fb05bd2253268abd4bb191f --- /dev/null +++ b/tests/ITADSPSIMOVDLSourceInShoebox.m @@ -0,0 +1,24 @@ +%% load +simo_i = ita_read( 'CirculatingSource_Signal.wav' ); +simo_o = ita_read( 'CirculatingSource_ShoeboxRoom.wav' ); +simo_io = ita_merge( simo_i, simo_o ); + +%% prepare +simo_io_snipped = ita_time_crop( simo_io, [ 2 2.1 ], 'time' ); +simo_io_snipped.comment = 'Circulating source in a shoebox room (10x7x3)'; +simo_io_snipped.channelNames = { 'Input signal', ... + 'Direct sound', ... + 'Reflection right wall', ... + 'Reflection left wall', ... + 'Reflection ceiling', ... + 'Reflection floor', ... + 'Reflection rear wall', ... + 'Reflection front wall', ... + }; + +%% plot +simo_io_snipped.pt + +%% merge +source_shoebox_auralization_mono = ita_sum( simo_o ); +ita_write( ita_normalize_dat( source_shoebox_auralization_mono ), 'CirculatingSource_ShoeboxRoom_Mono.wav', 'overwrite' ); diff --git a/tests/ITADSPSIMOVDLTest.cpp b/tests/ITADSPSIMOVDLTest.cpp index f482665a494c9fddeaa96e79f86102c663414ef7..cca062de41de94352ac0294a9b79e1876e1054ce 100644 --- a/tests/ITADSPSIMOVDLTest.cpp +++ b/tests/ITADSPSIMOVDLTest.cpp @@ -1,3 +1,25 @@ +/* + * ---------------------------------------------------------------- + * + * ITA core libs + * (c) Copyright Institute of Technical Acoustics (ITA) + * RWTH Aachen University, Germany, 2015-2017 + * + * ---------------------------------------------------------------- + * ____ __________ _______ + * // / //__ ___/ // _ | + * // / // / // /_| | + * // / // / // ___ | + * //__/ //__/ //__/ |__| + * + * ---------------------------------------------------------------- + * + * Processes a sine signal through single-input multiple-output + * variable delay line with two cursors at different delays and + * exports the i/o streams to hard drive. + * + */ + #include <ITASIMOVariableDelayLine.h> #include <ITAStringUtils.h> @@ -6,6 +28,7 @@ #include <ITASampleFrame.h> #include <ITAStreamFunctionGenerator.h> +#include <ITAFileDataSource.h> #include <ITAStreamInfo.h> #include <iostream> @@ -20,23 +43,35 @@ const float fMaxReservedDelaySamples = 5 * iBlockLength; const float fSimulateSeconds = 10; const float fInitialDelaySamples = 10 * 2 * iBlockLength - 1; +const string sInFilePath = "SIMOVDL_in.wav"; +const string sOutFilePath = "SIMOVDL_out.wav"; + int main( int, char** ) { ITAStreamFunctionGenerator sinesignal( 1, dSampleRate, iBlockLength, ITAStreamFunctionGenerator::SINE, 500.0f, 0.9f, true ); + //ITAFileDatasource filesignal( "cl-mod-bb-piece-32.wav", iBlockLength, true ); - CITASIMOVariableDelayLine* pSIMOVDL = new CITASIMOVariableDelayLine( dSampleRate, iBlockLength, fMaxReservedDelaySamples, CITASIMOVariableDelayLine::SWITCH ); + ITADatasource* pIntputStream = &sinesignal; + + CITASIMOVariableDelayLine* pSIMOVDL = new CITASIMOVariableDelayLine( dSampleRate, iBlockLength, fMaxReservedDelaySamples, CITASIMOVariableDelayLine::CUBIC_SPLINE_INTERPOLATION ); double dSamplerate = dSampleRate; unsigned int uiBlocklength = iBlockLength; unsigned int uiNumberOfFrames = ( unsigned int ) std::ceil( dSamplerate * fSimulateSeconds / ( float ) uiBlocklength ); + int iCursor0 = pSIMOVDL->AddCursor(); + pSIMOVDL->SetDelaySamples( iCursor0, .0f ); + int iCursor1 = pSIMOVDL->AddCursor(); - pSIMOVDL->SetDelaySamples( iCursor1, float( uiBlocklength * 2 ) ); + pSIMOVDL->SetDelaySamples( iCursor1, 11.0f ); int iCursor2 = pSIMOVDL->AddCursor(); - pSIMOVDL->SetDelaySamples( iCursor2, float( uiBlocklength * 3 ) ); + pSIMOVDL->SetDelaySamples( iCursor2, float( uiBlocklength * 2 ) ); + + int iCursor3 = pSIMOVDL->AddCursor(); + pSIMOVDL->SetDelaySamples( iCursor3, float( uiBlocklength * 3 ) ); ITAAudiofileProperties props_in; props_in.iChannels = 1; @@ -44,34 +79,43 @@ int main( int, char** ) props_in.eQuantization = ITAQuantization::ITA_FLOAT; props_in.eDomain = ITADomain::ITA_TIME_DOMAIN; props_in.iLength = uiNumberOfFrames * uiBlocklength; - ITAAudiofileWriter* writer_in = ITAAudiofileWriter::create( "SIMOVDL_in.wav", props_in ); + ITAAudiofileWriter* writer_in = ITAAudiofileWriter::create( sInFilePath, props_in ); ITAAudiofileProperties props_out( props_in ); props_out.iChannels = pSIMOVDL->GetNumCursors(); - ITAAudiofileWriter* writer_out = ITAAudiofileWriter::create( "SIMOVDL_out.wav", props_out ); + ITAAudiofileWriter* writer_out = ITAAudiofileWriter::create( sOutFilePath, props_out ); ITAStreamInfo oState; ITASampleBuffer* psbInput = new ITASampleBuffer( uiBlocklength, true ); ITASampleFrame* psfOutput = new ITASampleFrame( pSIMOVDL->GetNumCursors(), uiBlocklength, true ); + cout << "Input file: " << sInFilePath << endl; + cout << "Processing "; + unsigned int n = 0; while( n < uiNumberOfFrames ) { // Add new samples - psbInput->write( sinesignal.GetBlockPointer( 0, &oState ), uiBlocklength ); + psbInput->write( pIntputStream->GetBlockPointer( 0, &oState ), uiBlocklength ); pSIMOVDL->WriteBlock( psbInput ); - pSIMOVDL->ReadBlock( psfOutput ); + pSIMOVDL->ReadBlockAndIncrement( psfOutput ); - std::vector<float*> pIn; + std::vector< float* > pIn; pIn.push_back( psbInput->data() ); writer_in->write( uiBlocklength, pIn ); writer_out->write( psfOutput, uiBlocklength ); n++; - sinesignal.IncrementBlockPointer(); + pIntputStream->IncrementBlockPointer(); + + if( n % ( uiNumberOfFrames / 40 ) == 0 ) + cout << "."; } + cout << " done." << endl; + cout << "Output file: " << sOutFilePath << endl; + delete writer_in; delete writer_out; diff --git a/tests/ITADSPSIMOVDLTest.m b/tests/ITADSPSIMOVDLTest.m new file mode 100644 index 0000000000000000000000000000000000000000..90716d9a51636601cd3e632a57f106973e48d105 --- /dev/null +++ b/tests/ITADSPSIMOVDLTest.m @@ -0,0 +1,14 @@ +%% load +simo_io = ita_merge( ita_read( 'SIMOVDL_in.wav' ), ita_read( 'SIMOVDL_out.wav' ) ); + +%% prepare +simo_io_snipped = ita_time_crop( simo_io, [ 1 512 ], 'samples' ); +simo_io_snipped.comment = 'Single-Input Multiple-Output Variable Delay Line'; +simo_io_snipped.channelNames = { 'Sine signal in', ... + 'Read cursor 1 out (no delay)', ... + 'Read cursor 2 out (11 samples delay)', ... + 'Read cursor 3 out (2 blocks delay)', ... + 'Read cursor 4 out (3 blocks delay)' }; + +%% plot +simo_io_snipped.pt \ No newline at end of file diff --git a/tests/ITADSPThirdOctaveFilterbankTest.cpp b/tests/ITADSPThirdOctaveFilterbankTest.cpp index a5c334371ed62a74ce81d4d9c275df543955501c..69046bc4df3b3e9f745725dce548b871674d2700 100644 --- a/tests/ITADSPThirdOctaveFilterbankTest.cpp +++ b/tests/ITADSPThirdOctaveFilterbankTest.cpp @@ -26,7 +26,7 @@ void TestThirdOctaveFilterbankIIR() const int iSampleLength = ( 1 << 17 ); CITAThirdOctaveFilterbank* pIIRFilterbank = CITAThirdOctaveFilterbank::Create( g_dSampleRate, iSampleLength, CITAThirdOctaveFilterbank::IIR_BIQUADS_ORDER10 ); - ITASampleBuffer x( iSampleLength ); + ITASampleBuffer x( iSampleLength, true ); x[ 0 ] = 1.0f; CITAThirdOctaveGainMagnitudeSpectrum oMags;