Select Git revision
ITAUPConvolution.h

Pascal Palenda authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ITAUPConvolution.h 8.03 KiB
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2024
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
#ifndef INCLUDE_WATCHER_ITA_UP_CONVOLVER
#define INCLUDE_WATCHER_ITA_UP_CONVOLVER
#include <ITABaseDefinitions.h>
#include <ITAConvolutionDefinitions.h>
#include <ITACriticalSection.h>
#include <ITAUPTrigger.h>
#include <ITAUncopyable.h>
#include <atomic>
#include <tbb/concurrent_queue.h>
#include <vector>
// 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]
*/
void Init( const int iBlocklength, const int iFilterLength );
//! Blocklänge zurückgeben
int GetBlocklength( ) const;
//! Maximale Filterlänge [Anzahl Filterkoeffizienten] zurückgeben
int GetMaxFilterlength( ) const;
//! Trigger für den Filteraustausch zurückgeben (NULL falls keiner zugeordnet)
const ITAUPTrigger* GetFilterExchangeTrigger( ) const;
//! Trigger für den Filteraustausch setzen
void SetFilterExchangeTrigger( const ITAUPTrigger* pTrigger );
//! Filteraustausch-Modus zurückgeben
int GetFilterExchangeFadingFunction( );
//! Filteraustausch-Modus setzen
void SetFilterExchangeFadingFunction( const int iMode );
//! überblendlänge [Samples] des Filteraustauschs zurückgeben
int GetFilterCrossfadeLength( );
//! überblendlänge [Samples] für den Filteraustausch setzen
void SetFilterCrossfadeLength( const int iLength );
//! Verstärkung zurückgeben
float GetGain( ) const;
//! Verstärkung setzen
// Hinweis: Falls bSetImmediately==true gesetzt, wird die Verstärkung nicht
// dynamisch angepasst, sondern hart auf den angegebenen Wert gesetzt.
void SetGain( const float fGain, const bool bSetImmediately = false );
//! Filterpool zurückgeben
ITAUPFilterPool* GetFilterPool( ) const;
//! Filterpool setzen
/**
* NULL => Falter-eigenen Pool benutzen
*/
void SetFilterPool( ITAUPFilterPool* pFilterPool );
//! Freies Filter anfordern
ITAUPFilter* RequestFilter( );
//! Filter wieder zur anderweitigen Benutzung freigeben
void ReleaseFilter( ITAUPFilter* pFilter );
//! Aktives Filter zurückgeben
/**
* Das aktive Filter ist jenes, welches der Falter momentan benutzt.
*/
ITAUPFilter* GetActiveFilter( );
//! Filter austauschen
/**
* Hinweis: Nullzeiger => Aktives Filter entfernen
*/
void ExchangeFilter( ITAUPFilter* pNewFilter, const int iExchangeMode = ITABase::FadingFunction::COSINE_SQUARE, const int iCrossfadeLength = -1 );
//! 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!
void Process( const float* pfInputData, float* pfOutputData, const int iOutputMode = ITABase::MixingMethod::OVERWRITE );
//! 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)
*/
void Process( const float* pfInputData, const int iInputLength, float* pfOutputData, const int iOutputLength,
const int iOutputMode = ITABase::MixingMethod::OVERWRITE );
private:
typedef struct
{
ITAUPFilter* pFilter;
int iExchangeMode;
int iCrossfadeLength;
} FilterUpdate;
int m_iBlocklength;
int m_iMaxFilterlength;
std::atomic<int> m_iExchangeFadingFunction; // Austauschmodus
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::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
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 );
};
#endif // INCLUDE_WATCHER_ITA_UP_CONVOLVER