Commit 426c11e9 authored by Dipl.-Ing. Jonas Stienen's avatar Dipl.-Ing. Jonas Stienen
Browse files

Adding variable delay line for single-input and single-output

parent 816277f6
......@@ -20,6 +20,7 @@ include_directories( "include" )
set( ITADSPHeader
"include/ITADSPDefinitions.h"
"include/ITASIMOVariableDelayLine.h"
"include/ITAVariableDelayLine.h"
"include/ITABiquad.h"
"include/ITAThirdOctaveFilterbank.h"
"include/ITAThirdOctaveFilterbankFIR.h"
......@@ -33,6 +34,7 @@ set( ITADSPSources
"src/ITAThirdOctaveFilterbankIIR.cpp"
"src/ITAThirdOctaveFIRFilterGenerator.cpp"
"src/ITAThirdOctaveFilterbankCoefficients.h"
"src/ITAVariableDelayLine.cpp"
)
......
......@@ -30,7 +30,7 @@
//! Vorwärtsdeklarationen
class ITASampleBuffer;
class ITASampleFrame;
class IITAVDLInterpolationRoutine;
class IITASampleInterpolationRoutine;
//! Single-input multiple-output block-based variable delay line
/**
......@@ -64,10 +64,7 @@ class IITAVDLInterpolationRoutine;
* Beispiel:
* - lineare Interpolation: 1 Sample Latenz, d.h. VDL Verzögerung 0 = t < 1 Sample => 1 - t = 1 Sample Latenz
* - sinc-Interpolation: z.B. 12 Sample Latenz, d.h. VDL Verzögerung t < 12 Sample => 12 - t Samples Latenz
*
* \see CVAFreefieldAudiostreamProcessor
* \see CVAFreefieldFilterGenerator
*
* *
* TODO: Doku, Synchronität
* - Wächst automatisch mit Setzen der Verzögerung
*/
......@@ -143,7 +140,7 @@ public:
* Maximale mögliche Verzögerung auf dem momentan
* reservierten Pufferspeicher in Sekunden zurückgeben
*
* Siehe auch: CVAVariableDelayLine::ReserveMaximumDelaySamples(), CVAVariableDelayLine::SetDelaySamples()
* Siehe auch: CITAVariableDelayLine::ReserveMaximumDelaySamples(), CITAVariableDelayLine::SetDelaySamples()
*/
float GetReservedMaximumDelayTime() const;
......@@ -272,7 +269,7 @@ private:
ITAStopWatch m_swProcess; //!< StopWatch zur Überwachung der Berechnungsschleife
IITAVDLInterpolationRoutine* m_pInterpolationRoutine; //!< Zeiger auf Interpolationsroutine
IITASampleInterpolationRoutine* m_pInterpolationRoutine; //!< Zeiger auf Interpolationsroutine
};
......
......@@ -29,7 +29,7 @@
* Sie wird durch die Realisierungsmethoden (#FilterbankRealisationMethods) mittels Factory Method
* erstellt und kann dann Eingabesamples im Process()-Schritt filtern.
*
* Die Datensätze der Terzbandspektren werden durch die Klasse \CVAThirdOctaveMagnitues verwaltet.
* Die Datensätze der Terzbandspektren werden durch die Klasse \CITAThirdOctaveMagnitudeSpectrum verwaltet.
*
*/
class CITAThirdOctaveFilterbank
......
......@@ -28,8 +28,8 @@
//! Terzfilterbank mittels Biquads (IIR Filter)
/**
* Diese Klasse realisiert eine Terzfilterbank (#CVAThirdOctaveFilterbank) mit der Methode der kaskadierten
* Biquads (#CVABiquad) für Verstärkungsfaktoren eines Terzbank-Betragsspektrums (#CVAThirdOctaveMagnitudes).
* Diese Klasse realisiert eine Terzfilterbank (#CITAThirdOctaveFilterbank) mit der Methode der kaskadierten
* Biquads (#CITABiquad) für Verstärkungsfaktoren eines Terzbank-Betragsspektrums (#CITAThirdOctaveMagnitudeSpectrum).
*
*/
class ITA_DSP_API CITAThirdOctaveFilterbankIIR : public CITAThirdOctaveFilterbank
......
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2017
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
#ifndef IW_ITA_VARIABLE_DELAY_LINE
#define IW_ITA_VARIABLE_DELAY_LINE
#include <ITAAtomicPrimitives.h>
#include <ITACriticalSection.h>
#include <ITADataLog.h>
#include <ITAStopWatch.h>
//! Vorwärtsdeklarationen
class ITASampleBuffer;
class IITASampleInterpolationRoutine;
//! Daten-Logger der VDL aktivieren
#define VA_VDL_DATA_LOG 0
//! Klasse für variable Verzögerungsglieder (variable delay-lines, VDLs)
/**
* Diese Klasse realisiert Verzögerungsglieder (variable delay-lines, VDLs)
* mit frei einstellbarer und zur Laufzeit veränderbarer Verzögerung.
* Hierbei wird nur ein Kanal betrachtet.
*
* Die maximale Verzögerung wird durch den internen Pufferspeicher voralloziert.
* Da das Reservieren von Speicherplatz zur Laufzeit teuer sein kann, ist es ratsam,
* eine grobe Schätzung vor Ausführung einer Szene zu vollziehen und dem entsprechend
* eine Verzögerung zu setzen.
*
* Berechnungsvorschrift: Samples = ( Distance / SpeedOfSound ) * SampleRate
*
* Beispiel:
* - Raumakustik, Ausbreitungspfade maximal rund 100 m: 13000 = 13e3 Samples
* - Fluglärm, Ausbreitungspfade bis zu 10 km: 1300000 = 13e5 Samples
*
* Mittels der Methode ReserveMaximumDelaySamples() oder
* ReserveMaximumDelayTime() kann dieser Speicher den
* benötigten Verzögerungen zur Laufzeit angepasst werden.
*
* Dieses Modul erzeugt nur dann Latenz, wenn für den aktuellen Switching-Algorithmus
* nicht genügend Stützstellen zur Verfügung stehen. Diese Latenz tritt nur dann auf,
* wenn die Gesamtverzögerung der VDL unter die Latenz der Interpolationsroutine
* fällt. Die VDL Implementierung erzwingt dann diese Latenz, um auf weitere Stützwerte
* zu warten. Anders interpretiert funktioniert die Verzögerung durch die VDL nur bis
* zu einem Minimalabstand, welcher durch die Interpolationsroutine begrenzt wird. Unterhalb
* dieser Grenze kommt es zu keiner zeitlich korrekten Wiedergabe der Samples.
*
* Beispiel:
* - lineare Interpolation: 1 Sample Latenz, d.h. VDL Verzögerung 0 = t < 1 Sample => 1 - t = 1 Sample Latenz
* - sinc-Interpolation: z.B. 12 Sample Latenz, d.h. VDL Verzögerung t < 12 Sample => 12 - t Samples Latenz
*
* \see CVAFreefieldAudiostreamProcessor
* \see CVAFreefieldFilterGenerator
*
* TODO: Doku, Synchronität
* - Wächst automatisch mit Setzen der Verzögerung
*/
class CITAVariableDelayLine
{
public:
//! Umsetzung der Verzögerungsänderung
/**
* Auflistung der Algorithmen, die zur Umsetzung einer Verzögerungsänderung
* zur Verfügung stehen.
*/
enum SwitchingAlgorithm
{
SWITCH = 0, //!< Hartes umschalten
CROSSFADE, //!< Überblenden im Zeitbereich mittels Kreuzblende (Kosinus-Quadrat)
LINEAR_INTERPOLATION, //!< Stauchen und Strecken im Zeitbereich durch lineare Interpolation (Polynominterpolation der Ordnung 1)
WINDOWED_SINC_INTERPOLATION, //!< Stauchen und Strecken im Zeitbereich durch Interpolation mittels gefensterter si-Funktion
CUBIC_SPLINE_INTERPOLATION, //!< Stauchen und Strecken im Zeitbereich durch kubische Spline-Interpolation
};
//! Konstruktor der variablen Verzögerungsleitung
/**
* \param dSamplerate Abtastrate [Hz]
* \param iBlocklength Streaming-Blocklänge [Anzahl Samples]
* \param fReservedMaxDelaySamples Initiale maximale Verzögerung [Anzahl Samples]
* \param iAlgorithm Algorithmus (siehe #SwitchingAlgorithm)
*/
CITAVariableDelayLine( double dSamplerate, int iBlocklength, float fReservedMaxDelaySamples, int iAlgorithm );
//! Destruktor der variablen Verzögerungsleitung
~CITAVariableDelayLine();
//! Verfahren zur Änderung der Verzögerung zurückgeben
/**
* Gibt das momentan benutzte Verfahren zur Umsetzung der Verzögerungsänderung zurück
*
* \return Eine Nummer aus der Auflistung #SwitchingAlgorithm
*
*/
int GetAlgorithm() const;
//! Verfahren zur Änderung der Verzögerung setzen
/**
* Setzt das momentan zu benutzende Verfahren zur Umsetzung der Verzögerungsänderung
*
* \param iAlgorithm Eine Nummer aus der Auflistung #SwitchingAlgorithm
*
*/
void SetAlgorithm( int iAlgorithm );
//! Minimal mögliche Verzögerung in Samples zurückgeben
int GetMinimumDelaySamples() const;
//! Minimal mögliche Verzögerung in Sekunden zurückgeben
float GetMinimumDelayTime() const;
//! Maximal Verzögerung zurückgeben [Samples]
/**
* Maximale mögliche Verzögerung auf dem momentan
* reservierten Pufferspeicher in Samples zurückgeben
*/
float GetReservedMaximumDelaySamples() const;
//! Maximal Verzögerung zurückgeben [Sekunden]
/**
* Maximale mögliche Verzögerung auf dem momentan
* reservierten Pufferspeicher in Sekunden zurückgeben
*
* Siehe auch: CVAVariableDelayLine::ReserveMaximumDelaySamples(), CVAVariableDelayLine::SetDelaySamples()
*/
float GetReservedMaximumDelayTime() const;
//! Pufferspeicher reservieren für die angegebene maximale Verzögerung [Samples]
/**
* \note Die vorhandenen Daten bleiben erhalten
* \note Nicht vor parallelem Einstieg sicher
*/
void ReserveMaximumDelaySamples( float fMaxDelaySamples );
//! Pufferspeicher reservieren für die angegebene maximale Verzögerung [Sekunden]
/**
* Wie ReserveMaximumDelaySamples(), nur für Zeit in Sekunden
*/
void ReserveMaximumDelayTime( float fMaxDelaySecs );
//! Sub-Sample-Verzögerung aktiviert
/**
* \return Gibt zurück, ob Sub-Sample-Verzögerungen aktiviert (true) oder deaktiviert (false) ist
*/
bool GetFractionalDelaysEnabled() const;
//! Sub-Sample-Verzögerung setzen
/**
* \param bEnabled Aktiviert (true) oder deaktiviert (false) Sub-Sample-Verzögerungen
*/
void SetFractionalDelaysEnabled( bool bEnabled );
//! Gesamtverzögerung zurückgeben [Samples]
/**
* Gibt die Gesamtverzögerung der VDL als Zusammensetzung der Ganzzahl und des Sub-Sample zurück
*/
float GetDelaySamples() const;
//! Gesamtverzögerung zurückgeben
/**
* Gibt die Gesamtverzögerung der VDL als Zusammensetzung der Ganzzahl und des Sub-Sample zurück
*/
float GetDelayTime() const;
//! Gesamtverzögerung zurückgeben [Zeit]
/**
* Gibt die neu eingestellte (und möglicherweise noch nicht übernommene) Gesamtverzögerung der VDL als Zusammensetzung der Ganzzahl und des Sub-Sample zurück
*/
float GetNewDelayTime() const;
//! Gesamtverzögerung zurückgeben [Samples]
/**
* Gibt die Gesamtverzögerung der VDL als Ganzzahl und als Sub-Sample zurück
*
* \return iIntegerDelay Ganzzahlwert der Verzögerung (kleiner oder gleich der Gesamtverzögerung)
* \return fFractionalDelay Bruch der Sub-Sample-Verzögerung aus dem Wertebereich [0, 1)
*
*/
float GetDelaySamples( int& iIntegerDelay, float& fFractionalDelay ) const;
//! Verzögerung setzen [Samples]
/**
* Setzt die Verzögerung der VDL. Die Verzögerungsanpassung wird
* sofort auf den aktuellen Leseblock angewendet.
*
* \note Vergrößert gegebenenfalls den internen Puffer auf das Doppelte der aktuellen Größe.
* Dies kann unter Umständen zu einem Blockausfall führen, da die Operation teuer ist.
* Es empfiehlt sich bereits bei der Initialisierung für ausreichend Speicher zu sorgen,
* siehe ReserveMaximumDelaySamples().
*
* \note Die Funktion darf nicht parallel betreten werden (non-reentrant)
*/
void SetDelaySamples( float fDelaySamples );
//! Verzögerung setzen [Sekunden]
/**
* Wie SetDelaySamples(), aber für Zeit in Sekunden.
*/
void SetDelayTime( float fDelaySecs );
//! Löscht alle internen gespeicherten Samples und setzt die Distanz auf 0
void Clear();
//! Daten verarbeiten
/**
* Diese Funktion wird immer dann aufgerufen, wenn ein neuer Block für die Audiohardware
* verarbeitet werden soll (1 Block eingeben, 1 Block entnehmen).
*
* \param psbInput Eingabepuffer (Block) der VDL
* \param psbOutput Ausgabepuffer (Block) der VDL
*
*/
void Process( const ITASampleBuffer* psbInput, ITASampleBuffer* psbOutput );
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_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
int m_iWriteCursor; //!< Der Schreibzeiger ist immer Vielfaches der Blocklänge
int m_iMaxDelay; //!< Maximal einstellbare Verzögerung (hängt von Puffergröße ab)
int m_iSwitchingAlgorithm; //!< Eingestellter Algorithmus zum Umschalten der Verzögerung
ITAAtomicFloat m_fCurrentDelay; //!< Aktuelle Verzögerung in Samples
ITAAtomicFloat m_fNewDelay; //!< Neue Verzögerung in Samples
bool m_bFracDelays; //!< Fractional Delay Filterung an/aus
int m_iFadeLength; //!< Überblendlänge für das Umschaltverfahren mittels Kreuzblende (Minimum von Blocklänge oder 32 Samples)
bool m_bStarted; //!< Statusvariable zur Initialisierung
ITAStopWatch m_swBufferSizeInc; //!< StopWatch zur Überwachung von Speicherallozierungszeiten
ITAStopWatch m_swProcess; //!< StopWatch zur Überwachung der Berechnungsschleife
int m_iNumberOfDropouts; //!< Zählt die Anzahl durch die VDL verursachten Ausfälle
IITASampleInterpolationRoutine* m_pInterpolationRoutine; //!< Zeiger auf Interpolationsroutine
#if (VA_VDL_DATA_LOG == 1)
//! Implementierungsklasse für Logger-Datum
class VDLLogData : ITALogDataBase
{
public:
static std::ostream& outputDesc(std::ostream& os);
std::ostream& outputData(std::ostream& os) const;
float fCurrentDelay;
float fNewDelay;
float fResamplingFactor;
int iTargetBlockSize;
float fProcessingTime; //!< Zeit der Process-Routine in Millisekunden
};
ITABufferedDataLogger< VDLLogData > m_oDataLog; //!< Logger Datum für VDL spezifische Prozess-Information
#endif
};
#endif // IW_ITA_VARIABLE_DELAY_LINE
......@@ -35,13 +35,13 @@ CITASIMOVariableDelayLine::CITASIMOVariableDelayLine( const double dSamplerate,
m_iFadeLength = std::min( m_iBlockLength, 32 );
if( m_iSwitchingAlgorithm == LINEAR_INTERPOLATION )
m_pInterpolationRoutine = new CITAVDLLinearInterpolation();
m_pInterpolationRoutine = new CITASampleLinearInterpolation();
if( m_iSwitchingAlgorithm == CUBIC_SPLINE_INTERPOLATION )
m_pInterpolationRoutine = new CITAVDLCubicSplineInterpolation();
m_pInterpolationRoutine = new CITASampleCubicSplineInterpolation();
if( m_iSwitchingAlgorithm == WINDOWED_SINC_INTERPOLATION )
m_pInterpolationRoutine = new CITAVDLWindowedSincInterpolation();
m_pInterpolationRoutine = new CITASampleWindowedSincInterpolation();
Clear();
}
......
......@@ -139,7 +139,7 @@ void CITAThirdOctaveFIRFilterGenerator::GenerateFilter( const CITAThirdOctaveMag
#if (DUMP_INTERPOLATED_MAGNITUDES==1)
std::ofstream coeffs_file;
coeffs_file.open(m_sDumpFilename);
coeffs_file << "# 1/3 magnitudes: " << FloatArrayToString(pfThirdOctaveMagnitudes, CVAThirdOctaveMagnitudes::nBands, 3) << std::endl;
coeffs_file << "# 1/3 magnitudes: " << FloatArrayToString(pfThirdOctaveMagnitudes, CITAThirdOctaveMagnitudes::nBands, 3) << std::endl;
coeffs_file << "# Num DFT coeffs: " << m_iDFTCoeffs << std::endl;
coeffs_file << "# DFT bin bandwidth: " << m_fDeltaF << " Hz" << std::endl << std::endl;
#endif
......
#include <ITAVariableDelayLine.h>
#include <ITAInterpolation.h>
#include <ITAFastMath.h>
#include <ITANumericUtils.h>
#include <ITASampleBuffer.h>
#include <ITAStringUtils.h>
#include <ITAConstants.h>
#include <ITADebug.h>
#include <spline.h>
#include <cassert>
#include <cmath>
#include <iostream>
// Interpolation resampling factor range (otherwise crossfading is used)
#define MIN_RESAMPLING_FACTOR 0.0f // [0, inf) ... aber sinnvoll z.B. 0, 0.1, 0.5 (< 1)
#define MAX_RESAMPLING_FACTOR 25.0f // [0, inf) ... aber sinnvoll z.B. 1, 1.5, 2, 3 (> 1)
// --= VDL =--
CITAVariableDelayLine::CITAVariableDelayLine( double dSamplerate,
int iBlocklength,
float fReservedMaxDelaySamples,
int iAlgorithm )
: m_dSampleRate( dSamplerate ),
m_iBlockLength( iBlocklength ),
m_iSwitchingAlgorithm( iAlgorithm ),
m_psbVDLBuffer( nullptr ),
m_psbTemp( nullptr ),
m_bFracDelays( false ),
m_pInterpolationRoutine( nullptr )
{
assert( dSamplerate > 0 );
assert( iBlocklength > 0 );
// Define size of temp buffer depending on maximum oversampling factor
int iTempBufferBlockLength = ( ( int ) ceil( MAX_RESAMPLING_FACTOR ) + 1 )*m_iBlockLength;
m_psbTemp = new ITASampleBuffer( iTempBufferBlockLength, true );
ReserveMaximumDelaySamples( fReservedMaxDelaySamples );
m_iFadeLength = std::min( m_iBlockLength, 32 );
if( m_iSwitchingAlgorithm == LINEAR_INTERPOLATION )
m_pInterpolationRoutine = new CITASampleLinearInterpolation();
if( m_iSwitchingAlgorithm == CUBIC_SPLINE_INTERPOLATION )
m_pInterpolationRoutine = new CITASampleCubicSplineInterpolation();
if( m_iSwitchingAlgorithm == WINDOWED_SINC_INTERPOLATION )
m_pInterpolationRoutine = new CITASampleWindowedSincInterpolation();
#if (VA_VDL_DATA_LOG == 1)
m_oDataLog.setOutputFile("VDL.log");
#endif
Clear();
}
void CITAVariableDelayLine::Clear() {
m_psbVDLBuffer->Zero();
m_psbTemp->Zero();
m_iWriteCursor = 0;
m_fCurrentDelay = 0;
m_fNewDelay = 0;
m_bStarted = false;
m_swProcess.reset();
m_swBufferSizeInc.reset();
m_iNumberOfDropouts = 0;
}
CITAVariableDelayLine::~CITAVariableDelayLine()
{
delete m_psbVDLBuffer;
delete m_psbTemp;
std::string sAddition = "";
if( m_iSwitchingAlgorithm == SWITCH )
sAddition = "(Switching)";
else if( m_iSwitchingAlgorithm == CROSSFADE )
sAddition = "(Crossfading)";
else
sAddition = "(" + m_pInterpolationRoutine->GetName() + ")";
delete m_pInterpolationRoutine;
if( m_swProcess.cycles() > 0 )
{
DEBUG_PRINTF( " * [VDL] Process time monitor: avg=%.2f us max=%.2f us stddev=%.2f us, dropouts=%i %s\n", m_swProcess.mean()*1e6, m_swProcess.maximum()*1e6, m_swProcess.std_deviation()*1e6, m_iNumberOfDropouts, sAddition.c_str() );
}
}
int CITAVariableDelayLine::GetAlgorithm() const {
return m_iSwitchingAlgorithm;
}
void CITAVariableDelayLine::SetAlgorithm( int iAlgorithm ) {
m_iSwitchingAlgorithm = iAlgorithm;
}
float CITAVariableDelayLine::GetReservedMaximumDelaySamples() const {
return ( float ) ( m_iVDLBufferSize - m_iBlockLength );
}
float CITAVariableDelayLine::GetReservedMaximumDelayTime() const {
return GetReservedMaximumDelaySamples() / ( float ) m_dSampleRate;
}
int CITAVariableDelayLine::GetMinimumDelaySamples() const
{
if( !m_pInterpolationRoutine )
return 0;
int iLeft, iRight;
m_pInterpolationRoutine->GetOverlapSamples( iLeft, iRight );
return ( iLeft + iRight );
}
float CITAVariableDelayLine::GetMinimumDelayTime() const
{
return GetMinimumDelaySamples() / ( float ) m_dSampleRate;
}
void CITAVariableDelayLine::ReserveMaximumDelaySamples( float fMaxDelaySamples )
{
// Festlegung: Die Methode darf nicht parallel betreten werden (non-reentrant)
assert( fMaxDelaySamples >= 0 ); // Verzgerung immer positiv
// Anzahl Pufferblcke bestimmen
int iNewBufferSize = uprmul( ( int ) ceil( fMaxDelaySamples ), m_iBlockLength );
assert( iNewBufferSize > 0 ); // Puffer muss eine Gre haben
if( !m_psbVDLBuffer )
{
/*
* Erste Initalisierung des Puffers
* Hinweis: Hier ist keine Synchronisierung erforderlich, da dieser Ast
* nur durch den Konstruktor aufgerufen wird
*/
m_psbVDLBuffer = new ITASampleBuffer( iNewBufferSize, true );
m_iVDLBufferSize = iNewBufferSize;
m_iWriteCursor = 0;
}
else
{
// Puffer schon gross genug => Nichts tun...
if( m_psbVDLBuffer->length() >= iNewBufferSize ) return;
m_swBufferSizeInc.start();
assert( m_psbVDLBuffer->length() >= 0 ); // VDL-Pufferlnge muss eine Gre haben
m_csBuffer.enter();
// Alte Puffergre sichern
int iOldBufferSize = m_psbVDLBuffer->length();
// Vorhandene Daten zyklisch Kopieren (aktuelle Schreibposition => Anfang abrollen)
ITASampleBuffer* psbNewBuffer = new ITASampleBuffer( iNewBufferSize, true );
psbNewBuffer->cyclic_write( m_psbVDLBuffer, iNewBufferSize, m_iWriteCursor, 0 );
// Alten Puffer freigeben, neuen zuweisen
delete m_psbVDLBuffer;
m_psbVDLBuffer = psbNewBuffer;
m_iVDLBufferSize = iNewBufferSize;
m_iWriteCursor = iOldBufferSize; // Hinten anhngend weiterschreiben
m_csBuffer.leave();
double t = m_swBufferSizeInc.stop() * 1e6;
std::cout << "VairableDelayLine: Buffer increment from " << iOldBufferSize << " samples to " << iNewBufferSize << " samples requested, took " << timeToString( t );
}
}
void CITAVariableDelayLine::ReserveMaximumDelayTime( float fMaxDelaySecs )
{
ReserveMaximumDelaySamples( fMaxDelaySecs * ( float ) m_dSampleRate );
}
bool CITAVariableDelayLine::GetFractionalDelaysEnabled() const {
return m_bFracDelays;
}
void CITAVariableDelayLine::SetFractionalDelaysEnabled( bool bEnabled )
{
m_bFracDelays = bEnabled;
}
float CITAVariableDelayLine::GetDelaySamples() const
{
// Um Konsistenz zu wahren geben wir immer den
// neuen Verzgerungswert zurck, da es sein kann,
// dass Getter und Setter fr den Delay mehrmals benutzt werden,
// ohne dass im Process() Schritt der neue Wert als Aktueller
// bernommen wurde.
if( m_fCurrentDelay == m_fNewDelay )
return m_fCurrentDelay;
else
return m_fNewDelay;
}
float CITAVariableDelayLine::GetDelaySamples( int& iIntegerDelay, float& fFractionalDelay ) const
{
// Lokale Kopie der Verzgerung
float fDelay = GetDelaySamples();
iIntegerDelay = ( int ) floor( fDelay );
fFractionalDelay = fDelay - ( float ) iIntegerDelay;
return fDelay;
}
void CITAVariableDelayLine::SetDelaySamples( float fDelaySamples )
{
assert( fDelaySamples >= 0 ); // Verzgerung immer positiv
// Internen Puffer vergrern
/* Erfordert die neuen Verzgerung auch eine Puffer-Vergrerung,
* ist es wahrscheinlich, dass bald erneut eine Vergrerung ntig ist.
* Dies ist teuer, deshalb erzwingen wird hier direkt eine deutliche
* Vergrerung.
*/
if( m_iVDLBufferSize - m_iBlockLength < ceil( fDelaySamples ) )
ReserveMaximumDelaySamples( ceil( fDelaySamples ) * 2 );
// Neuen Wert nicht einfach bernehmen, sondern der
// Process()-Routine berlassen
m_fNewDelay = fDelaySamples;
//VA_DEBUG_PRINTF(" * [VDL] Delay set to %.3f samples\n", fDelaySamples);
// Falls das Streaming noch nicht gestartet ist sofort die
// neue Verzgerung bernehmen, sonst wird im ersten Block
// gleich von 0 auf fDelaySamples umgesetzt und bei