Aufgrund einer Wartung wird GitLab am 18.01. zwischen 8:00 und 9:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 18.01. between 8:00 and 9:00 am.

ITAUPConvolution.h 7.88 KB
Newer Older
1
2
3
4
5
/*
 * ----------------------------------------------------------------
 *
 *		ITA core libs
 *		(c) Copyright Institute of Technical Acoustics (ITA)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
6
 *		RWTH Aachen University, Germany, 2015-2020
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