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

#ifndef IW_ITA_SIMO_VARIABLE_DELAY_LINE
#define IW_ITA_SIMO_VARIABLE_DELAY_LINE

22
23
#include <ITADSPDefinitions.h>

24
25
26
27
28
29
30
31
32
#include <ITACriticalSection.h>
#include <ITADataLog.h>
#include <ITAStopWatch.h>

#include <atomic>
#include <map>

//! Vorwrtsdeklarationen
class ITASampleBuffer;
33
class ITASampleFrame;
34
class IITASampleInterpolationRoutine;
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

//! Single-input multiple-output block-based variable delay line
/**
 * Diese Klasse realisiert Verzgerungsglieder (variable delay-lines, VDLs)
 * mit frei einstellbarer und zur Laufzeit vernderbarer Verzgerung.
 * Hierbei wird nur ein Kanal betrachtet.
 *
 * Die maximale Verzgerung wird durch den internen Pufferspeicher voralloziert.
 * Da das Reservieren von Speicherplatz zur Laufzeit teuer sein kann, ist es ratsam,
 * eine grobe Schtzung vor Ausfhrung einer Szene zu vollziehen und dem entsprechend
 * eine Verzgerung zu setzen.
 *
 * Berechnungsvorschrift: Samples = ( Distance / SpeedOfSound ) * SampleRate
 *
 * Beispiel:
 * - Raumakustik, Ausbreitungspfade maximal rund 100 m: 13000 = 13e3 Samples
 * - Fluglrm, Ausbreitungspfade bis zu 10 km: 1300000 = 13e5 Samples
 *
 * Mittels der Methode ReserveMaximumDelaySamples() oder
 * ReserveMaximumDelayTime() kann dieser Speicher den
 * bentigten Verzgerungen zur Laufzeit angepasst werden.
 *
 * Dieses Modul erzeugt nur dann Latenz, wenn fr den aktuellen Switching-Algorithmus
 * nicht gengend Sttzstellen zur Verfgung stehen. Diese Latenz tritt nur dann auf,
 * wenn die Gesamtverzgerung der VDL unter die Latenz der Interpolationsroutine
 * fllt. Die VDL Implementierung erzwingt dann diese Latenz, um auf weitere Sttzwerte
 * zu warten. Anders interpretiert funktioniert die Verzgerung 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 Verzgerung 0 = t < 1 Sample => 1 - t = 1 Sample Latenz
 * - sinc-Interpolation: z.B. 12 Sample Latenz, d.h. VDL Verzgerung t < 12 Sample => 12 - t Samples Latenz
68
 * *
69
70
71
72
 * TODO: Doku, Synchronitt
 * - Wchst automatisch mit Setzen der Verzgerung
 */

73
class ITA_DSP_API CITASIMOVariableDelayLine
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{
public:
	//! Umsetzung der Verzgerungsnderung
	/**
	  * Auflistung der Algorithmen, die zur Umsetzung einer Verzgerungsnderung
	  * zur Verfgung 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
	};

	struct CITAVDLReadCursor
	{
		std::atomic< float > fNewReadCursorSamples; //!< Read cursor that will be forwarded to on next processing block
		std::atomic< float > fOldReadCursorSamples; //!< Read cursor from last calculation
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

		//! Default constructor for read cursor with zero delay
		inline CITAVDLReadCursor()
		{
			fNewReadCursorSamples = 0.0f;
			fOldReadCursorSamples = 0.0f;
		};

		inline CITAVDLReadCursor( CITAVDLReadCursor& rhs )
		{
			fNewReadCursorSamples.store( rhs.fNewReadCursorSamples );
			fOldReadCursorSamples.store( rhs.fOldReadCursorSamples );
		};

		inline CITAVDLReadCursor& operator =( const CITAVDLReadCursor& rhs )
		{
			fNewReadCursorSamples.store( rhs.fNewReadCursorSamples );
			fOldReadCursorSamples.store( rhs.fOldReadCursorSamples );

			return *this;
		}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
	};

	//! Konstruktor der variablen Verzgerungsleitung
	/**
	 * \param dSamplerate				Abtastrate [Hz]
	 * \param iBlocklength				Streaming-Blocklnge [Anzahl Samples]
	 * \param fReservedMaxDelaySamples	Initiale maximale Verzgerung [Anzahl Samples]
	 * \param iAlgorithm				Algorithmus (siehe #SwitchingAlgorithm)
	 */
	CITASIMOVariableDelayLine( const double dSamplerate, const int iBlocklength, const float fReservedMaxDelaySamples, const int iAlgorithm );

	//! Destruktor der variablen Verzgerungsleitung
	~CITASIMOVariableDelayLine();

	//! Verfahren zur nderung der Verzgerung zurckgeben
	/**
	  * Gibt das momentan benutzte Verfahren zur Umsetzung der Verzgerungsnderung zurck
	  *
	  * \return Eine Nummer aus der Auflistung #SwitchingAlgorithm
	  *
	  */
	int GetAlgorithm() const;

	//! Verfahren zur nderung der Verzgerung setzen
	/**
	  * Setzt das momentan zu benutzende Verfahren zur Umsetzung der Verzgerungsnderung
	  *
	  * \param iAlgorithm Eine Nummer aus der Auflistung #SwitchingAlgorithm
	  *
	  */
	void SetAlgorithm( const int iAlgorithm );

	//! Minimal mgliche Verzgerung in Samples zurckgeben
	int GetMinimumDelaySamples() const;

	//! Minimal mgliche Verzgerung in Sekunden zurckgeben
	float GetMinimumDelayTime() const;

	//! Maximal Verzgerung zurckgeben [Samples]
	/**
	  * Maximale mgliche Verzgerung auf dem momentan
	  *	reservierten Pufferspeicher in Samples zurckgeben
	  */
	float GetReservedMaximumDelaySamples() const;

	//! Maximal Verzgerung zurckgeben [Sekunden] 
	/**
	  * Maximale mgliche Verzgerung auf dem momentan
	  * reservierten Pufferspeicher in Sekunden zurckgeben
	  *
165
	  * Siehe auch: CITAVariableDelayLine::ReserveMaximumDelaySamples(), CITAVariableDelayLine::SetDelaySamples()
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
	  */
	float GetReservedMaximumDelayTime() const;

	//! Pufferspeicher reservieren fr die angegebene maximale Verzgerung [Samples]
	/**
	  * \note Die vorhandenen Daten bleiben erhalten
	  * \note Nicht vor parallelem Einstieg sicher
	  */
	void ReserveMaximumDelaySamples( const float fMaxDelaySamples );

	//! Pufferspeicher reservieren fr die angegebene maximale Verzgerung [Sekunden]
	/**
	  * Wie ReserveMaximumDelaySamples(), nur fr Zeit in Sekunden
	  */
	void ReserveMaximumDelayTime( const float fMaxDelaySecs );

	//! Adds a new reading cursor 
183
	/**
184
185
186
187
188
	  * @return Cursor ID
	  */
	int AddCursor();

	//! Remove cursor
189
	/**
190
191
192
193
194
195
196
	  * Removes cursor of given ID
	  * @param[in] iCursorID Cursor ID
	  * @return False, if cursor not valid
	  */
	bool RemoveCursor( const int iCursorID );

	//! Checks existance of a cursor
197
198
199
200
	/**
	  * @param[in] iCursorID Cursor identifier
	  * @return True, if cursor exists, false otherwise
	  */
201
202
	bool CursorExists( const int iCursorID ) const;

203
204
205
206
	//! Returns the IDs of the current cursors
	/**
	  * @return Cursor identifier
	  */
207
208
	std::vector< int > GetCursorIDs() const;

209
210
211
212
213
214
	//! Returns number of current cursors
	/**
	  * @return Number of user cursors
	  */
	int GetNumCursors() const;

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
	//! Overall current latency of a cursor in samples
	/**
	  * \return Delay and fractional delay in samples (which is rounded during VDL processing)
	  *
	  * \note Raises ITAException if cursor not valid
	  */
	float GetCurrentDelaySamples( const int iCursorID ) const;

	//! Overall new latency of a cursor in samples (not yet effective)
	/**
	  * \return New delay and fractional delay in samples (which is rounded during VDL processing)
	  *
	  * \note Raises ITAException if cursor not valid
	  */
	float GetNewDelaySamples( const int iCursorID ) const;

	//! Overall current latency of a cursor in seconds
	/**
	  * \return Delay and fractional delay in seconds
	  *
	  * \note Raises ITAException if cursor not valid
	  */
	float GetCurrentDelayTime( const int iCursorID ) const;

	//! Overall new latency of a cursor in seconds
	/**
	  * Gibt die neu eingestellte (und mglicherweise noch nicht bernommene) Gesamtverzgerung der VDL als Zusammensetzung der Ganzzahl und des Sub-Sample zurck
	  *
	  * \note Raises ITAException if cursor not valid
	  */
	float GetNewDelayTime( const int iCursorID ) const;

	//! Verzgerung setzen [Samples]
	/**
	  * Setzt die Verzgerung der VDL. Die Verzgerungsanpassung wird
	  * sofort auf den aktuellen Leseblock angewendet.
	  *
	  * \note	Vergrert gegebenenfalls den internen Puffer auf das Doppelte der aktuellen Gre.
	  *			Dies kann unter Umstnden zu einem Blockausfall fhren, da die Operation teuer ist.
	  *			Es empfiehlt sich bereits bei der Initialisierung fr ausreichend Speicher zu sorgen,
	  *			siehe ReserveMaximumDelaySamples().
	  *
	  * \note	Die Funktion darf nicht parallel betreten werden (non-reentrant)
	  */
	void SetDelaySamples( const int iID, const float fDelaySamples );

	//! Verzgerung setzen [Sekunden]
	/**
	  * Wie SetDelaySamples(), aber fr Zeit in Sekunden.
	  */
	void SetDelayTime( const int iID, const float fDelaySecs );

	//! Lscht alle internen gespeicherten Samples und setzt die Distanz auf 0
	void Clear();

	//! Pushes a block of samples at front of delay line
271
272
273
274
275
276
277
278
	/**
	  * 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
	  */
279
280
281
	void WriteBlock( const ITASampleBuffer* psbInput );

	//! Reads a block of samples for a read cursor and switches to new delay
282
283
284
285
286
287
	/**
	  * @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)
	  */
288
289
	void ReadBlock( const int iID, ITASampleBuffer* psbOutput );

290
291
292
293
294
295
296
	//! 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();

297
	//! Reads a block of samples at all cursors (switches to new delay)
298
	/**
299
300
301
302
303
304
	  * The order of the channels in the sample frame will be linear over the
	  * internal cursor list, see GetCursorIDs()
	  *
	  * @param[in] psfOutput Initialized sample frame
	  *
	  */
305
	void ReadBlockAndIncrement( ITASampleFrame* psfOutput );
306
307
308
309
310

private:
	double m_dSampleRate;				//!< Audio-Abtastrate
	int m_iBlockLength;					//!< Audio-Blockgre
	int m_iVDLBufferSize;				//!< Gre des Puffers zum Speichern verzgerter Samples
311
	ITASampleBuffer* m_psbVDLBuffer;	//!< Buffer for samples (variable size at multiples of block leng, but minimum is 2 blocks)
312
313
314
315
316
317
318
	ITASampleBuffer* m_psbTemp;			//!< Temporrer Puffer zum Arbeiten mit Samples (Gre: 2xBlocklnge) (das knnte evtl. knapp sein)
	ITACriticalSection m_csBuffer;		//!< Zugriff auf Puffer schtzen

	int m_iWriteCursor;					//!< Der Schreibzeiger ist immer Vielfaches der Blocklnge
	int m_iMaxDelay;					//!< Maximal einstellbare Verzgerung (hngt von Puffergre ab)
	int m_iSwitchingAlgorithm;			//!< Eingestellter Algorithmus zum Umschalten der Verzgerung

319
	std::map< int, CITAVDLReadCursor > m_lUserCursors;		//!< List of read cursors (managed by user) @todo maybe enforced thread-safe access required
320
	std::map< int, CITAVDLReadCursor > m_lInternalCursors;		//!< List of read cursors (synced for processing)
321

322
323
324
325
	int m_iFadeLength;					//!< berblendlnge fr das Umschaltverfahren mittels Kreuzblende (Minimum von Blocklnge oder 32 Samples)

	bool m_bStarted;					//!< Statusvariable zur Initialisierung

326
	bool m_bBenchmark;
327
328
	ITAStopWatch m_swProcess;			//!< StopWatch zur berwachung der Berechnungsschleife

329
	IITASampleInterpolationRoutine* m_pInterpolationRoutine; //!< Zeiger auf Interpolationsroutine
330
331
332
333
};


#endif // IW_ITA_SIMO_VARIABLE_DELAY_LINE