ITAUPConvolution.h 7.88 KB
Newer Older
1 2 3 4 5
/*
 * ----------------------------------------------------------------
 *
 *		ITA core libs
 *		(c) Copyright Institute of Technical Acoustics (ITA)
6
 *		RWTH Aachen University, Germany, 2015-2019
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * ----------------------------------------------------------------
 *				    ____  __________  _______
 *				   //  / //__   ___/ //  _   |
 *				  //  /    //  /    //  /_|  |
 *				 //  /    //  /    //  ___   |
 *				//__/    //__/    //__/   |__|
 *
 * ----------------------------------------------------------------
 *
 */

19 20
#ifndef INCLUDE_WATCHER_ITA_UP_CONVOLVER
#define INCLUDE_WATCHER_ITA_UP_CONVOLVER
21 22 23

#include <ITAConvolutionDefinitions.h>

24
#include <ITABaseDefinitions.h>
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
#include <ITACriticalSection.h>
#include <ITAUncopyable.h>
#include <vector>
#include <ITAUPTrigger.h>

#include <tbb/concurrent_queue.h>

#include <atomic>

// Vorwürtsdeklarationen
class ITAUPFilter;
class ITAUPFilterPool;
class ITAFFT;

/**
 * Diese Klasse realisiert einen schnellen (einkanaligen) Falter (dynamic single-channel multi-block convolver),
 * welcher die effiziente Overlap-Save Blockfaltung zusammen mit einer frequency-domain delay-line (FDL)
 * benutzt um eine Impulsantwortet zu falten, welche in mehrere gleichlange Teile zerlegt wird.
 * Dieser Ansatz ermüglicht eine wesentlich grüüere Leistung als ein einfacher Blockfaltungsansatz,
 * bei welchem die komplette Impulsantwort mit einem Block gefaltet werden. Der Falter ist dynamisch,
 * d.h. er erlaubt den Austausch der Filter zur Laufzeit bzw. Streamingzeit. Der Austausch der Filter
 * geschieht entweder durch hartes Umschalten oder überblendung im Zeitbereich.
 *
 * Nebenlüufigkeit & Synchronisation:
 *
 * Folgende Methoden sind synchronisiert:
 *
 * - getFilterPool, setFilterPool, requestFilter, releaseFilter => Blocking aber leichtgewichtig, reentrant
 * - getFilterExchangeMode, setFilterExchangeMode, getFilterCrossfadeLength, setFilterCrossfadeLength,
 *   getActiveFilter, exchangeFilter => Non-blocking und wait-free, reentrant
 * - process => Non-blocking, wait-free aber NICHT REENTRANT (!!)
 *
 * Alle anderen Methoden sind nicht synchronisiert.
 *
 * Müchtest Du mehr zu den Details wissen? Frag mich! -> Frank.Wefers@akustik.rwth-aachen.de
 */

class ITA_CONVOLUTION_API ITAUPConvolution : public ITAUncopyable
{
public:

	//! Standard-Konstruktor
	/**
	 * Erzeugt einen Falter der seinen eigenen Filterpool betreibt
	 */
	ITAUPConvolution();

	//! Initialierungs-Konstruktor
	/**
	 * Erzeugt einen Falter.
	 *
	 * \param iBlocklength		Blocklänge [in Samples]
	 * \param iMaxFilterlength  Maximale Filterlänge [Anzahl Filterkoeffizienten]
	 */
	ITAUPConvolution( const int iBlocklength, const int iMaxFilterlength, ITAUPFilterPool* pFilterPool = NULL );

	//! Destruktor
	virtual ~ITAUPConvolution();

	//! Initialisieren
	/**
	 * Initialisiert einen Falter.
	 *
	 * \param iBlocklength		Blocklänge [in Samples]
	 * \param iMaxFilterlength  Maximale Filterlänge [Anzahl Filterkoeffizienten]
	 */
91
	void Init( const int iBlocklength, const int iFilterLength );
92 93

	//! Blocklänge zurückgeben
94
	int GetBlocklength() const;
95 96

	//! Maximale Filterlänge [Anzahl Filterkoeffizienten] zurückgeben
97
	int GetMaxFilterlength() const;
98 99

	//! Trigger für den Filteraustausch zurückgeben (NULL falls keiner zugeordnet)
100
	const ITAUPTrigger* GetFilterExchangeTrigger() const;
101 102

	//! Trigger für den Filteraustausch setzen
103
	void SetFilterExchangeTrigger( const ITAUPTrigger* pTrigger );
104 105

	//! Filteraustausch-Modus zurückgeben
106
	int GetFilterExchangeFadingFunction();
107 108

	//! Filteraustausch-Modus setzen
109
	void SetFilterExchangeFadingFunction( const int iMode );
110 111

	//! überblendlänge [Samples] des Filteraustauschs zurückgeben
112
	int GetFilterCrossfadeLength();
113 114

	//! überblendlänge [Samples] für den Filteraustausch setzen
115
	void SetFilterCrossfadeLength( const int iLength );
116 117

	//! Verstärkung zurückgeben
118
	float GetGain() const;
119 120 121 122

	//! Verstärkung setzen
	// Hinweis: Falls bSetImmediately==true gesetzt, wird die Verstärkung nicht
	// dynamisch angepasst, sondern hart auf den angegebenen Wert gesetzt.
123
	void SetGain( const float fGain, const bool bSetImmediately = false );
124 125

	//! Filterpool zurückgeben
126
	ITAUPFilterPool* GetFilterPool() const;
127 128 129 130 131

	//! Filterpool setzen
	/**
	 * NULL => Falter-eigenen Pool benutzen
	 */
132
	void SetFilterPool( ITAUPFilterPool* pFilterPool );
133 134

	//! Freies Filter anfordern
135
	ITAUPFilter* RequestFilter();
136 137

	//! Filter wieder zur anderweitigen Benutzung freigeben
138
	void ReleaseFilter( ITAUPFilter* pFilter );
139 140 141 142 143

	//! Aktives Filter zurückgeben
	/**
	 * Das aktive Filter ist jenes, welches der Falter momentan benutzt.
	 */
144
	ITAUPFilter* GetActiveFilter();
145 146 147 148 149

	//! Filter austauschen
	/**
	 * Hinweis: Nullzeiger => Aktives Filter entfernen
	 */
150
	void ExchangeFilter( ITAUPFilter* pNewFilter, const int iExchangeMode = ITABase::FadingFunction::COSINE_SQUARE, const int iCrossfadeLength = -1 );
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

	//! Löscht alle internen Samplepuffer
	void clear();

	//! Faltungsmethode
	/**
	 * Nimmt einen neuen Block Eingangsdaten entgegen und faltet ihn mit der Impulsantwortet.
	 * Das (partielle) Ausgangssignal wird als Block im Zielarray gespeichert.
	 *
	 * \param pfInputData   Array der Eingangsdaten (Exakt soviele Elemente wie die Blocklänge ist)
	 * \param pfOutputData  Array der Ausgangsdaten (Exakt soviele Elemente wie die Blocklänge ist)
	 * \param iOutputMode   Ausgabemodus (überschreiben oder Einmischen)
	 */

	// TODO: Hier wird Austausch durchgeführt!
166
	void Process( const float* pfInputData, float* pfOutputData, const int iOutputMode = ITABase::MixingMethod::OVERWRITE );
167 168 169 170 171 172 173 174 175 176 177 178 179

	//! Faltungsmethode (Erweitert)
	/**
	 * Nimmt einen neuen Block Eingangsdaten entgegen und faltet ihn mit der Impulsantwortet.
	 * Das (partielle) Ausgangssignal wird als Block im Zielarray gespeichert.
	 *
	 * \param pfInputData   Array der Eingangsdaten
	 * \param iInputLength  Anzahl der Samples in den Eingangsdaten
	 * \param pfOutputData  Array der Ausgangsdaten (Exakt soviele Elemente wie die Blocklänge ist)
	 * \param iOutputLength Anzahl der Samples in den Ausgabedaten
	 * \param iOutputMode   Ausgabemodus (überschreiben oder Einmischen)
	 */

180
	void Process( const float* pfInputData, const int iInputLength, float* pfOutputData, const int iOutputLength, const int iOutputMode = ITABase::MixingMethod::OVERWRITE );
181 182 183 184 185 186 187 188 189 190 191 192

private:
	typedef struct
	{
		ITAUPFilter* pFilter;
		int iExchangeMode;
		int iCrossfadeLength;
	} FilterUpdate;

	int m_iBlocklength;
	int m_iMaxFilterlength;

193
	std::atomic< int > m_iExchangeFadingFunction;				// Austauschmodus
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	std::atomic< int > m_iCrossfadeLength;			// überblendlänge
	std::atomic< float > m_fCurrentGain;				// Aktuelle Verstärkung
	std::atomic< float > m_fNewGain;					// Gewünschte Verstärkung
	std::atomic< ITAUPFilter* > m_pCurrentFilter;	// Aktives Filter
	tbb::strict_ppl::concurrent_queue<FilterUpdate> m_qExchangeFilters;	// Queue: Nächste Filter zum Austausch

	float *m_pfTimeInputBuffer;					// Eingangspuffer (Zeitbereich)
	float *m_pfTimeOutputBuffer1;				// Ausgangspuffer (Zeitbereich)
	float *m_pfTimeOutputBuffer2;				// Ausgangspuffer (Zeitbereich)
	float *m_pfFreqAuxBuffer;					// Hilfspuffer (Frequenz-bereich)
	float *m_pfFreqMixdownBuffer;				// Mischpuffer (Frequenz-bereich)
	int m_iFreqCoeffs;							// Anzahl DFT-Koeffizienten (Symetrien eingerechnet)
	std::vector< float* > m_vpfFreqDelayLine;		// Frequency-domain delay line (FDL)
	ITAFFT *m_pFFT, *m_pIFFT;					// FFT, IFFT der Daten
	ITACriticalSection m_csPool;				// Exklusiver Zugriff auf den Filterpool

	ITAUPFilterPool* m_pCurrentPool;			// Gesetzer Filterpool
	ITAUPFilterPool* m_pOwnPool;				// Falter-eigener Filterpool
	ITAUPTriggerWatch m_oTriggerWatch;			// TriggerWatch für den Filteraustausch


215 216
	void CopyOutputApplyGain1( float* pfDest, const float* pfSrc, const int iNumSamples, const int iOutputMode );
	void CopyOutputApplyGain2( float* pfDest, const float* pfSrc1, const float* pfSrc2, const int iOutputLength, const int iCrossfadeLength, const int iOutputMode );
217 218
};

219
#endif // INCLUDE_WATCHER_ITA_UP_CONVOLVER