From 297ebd0d405aed7c18db85b0aab0a94d3ebe3f98 Mon Sep 17 00:00:00 2001 From: Jonas Stienen Date: Thu, 18 May 2017 16:14:52 +0200 Subject: [PATCH] Renaming files (no DSMBC, now ITAUP -> uniform partitioned convolution) --- CMakeLists.txt | 32 +- apps/ita_convoi/ita_convoi.cpp | 6 +- include/DSMBCConvolver.h | 233 ------------ include/DSMBCFilter.h | 129 ------- include/DSMBCFilterPool.h | 93 ----- include/DSMBCTrigger.h | 75 ---- include/ITAConvolution.h | 78 ---- src/DSMBCConvolver.cpp | 631 --------------------------------- src/DSMBCFilter.cpp | 143 ++++---- src/DSMBCFilterPool.cpp | 206 ----------- src/ITAConvolution.cpp | 34 -- src/ITAConvolutionImpl.cpp | 75 ---- src/ITAConvolutionImpl.h | 36 -- tests/DSMBCTest.cpp | 6 +- tests/ITAConvolutionTest.cpp | 40 ++- 15 files changed, 127 insertions(+), 1690 deletions(-) delete mode 100644 include/DSMBCConvolver.h delete mode 100644 include/DSMBCFilter.h delete mode 100644 include/DSMBCFilterPool.h delete mode 100644 include/DSMBCTrigger.h delete mode 100644 include/ITAConvolution.h delete mode 100644 src/DSMBCConvolver.cpp delete mode 100644 src/DSMBCFilterPool.cpp delete mode 100644 src/ITAConvolution.cpp delete mode 100644 src/ITAConvolutionImpl.cpp delete mode 100644 src/ITAConvolutionImpl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 390feba..7ff44a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ project( ITAConvolution ) list( APPEND CMAKE_MODULE_PATH "$ENV{VISTA_CMAKE_COMMON}" ) include( VistaCommon ) +if( NOT DEFINED ITA_CONVOLUTION_UPCONV_WITH_POWER_SAVER ) + set( ITA_CONVOLUTION_UPCONV_WITH_POWER_SAVER ON CACHE BOOL "Use power saving mode for uniform partitioned convolution (do not convolve blocks with zeros)" ) +endif( ) + # dependencies vista_use_package( ITABase REQUIRED FIND_DEPENDENCIES ) vista_use_package( ITAFFT REQUIRED FIND_DEPENDENCIES ) @@ -16,20 +20,20 @@ include_directories( "include" ) # sources set( ITAConvolutionHeader - include/DSMBCConvolver.h - include/DSMBCFilter.h - include/DSMBCFilterPool.h - include/DSMBCTrigger.h - include/ITAConvolution.h - include/ITAConvolutionDefinitions.h + "include/ITAUPConvolution.h" + "include/ITAUPFilter.h" + "include/ITAUPFilterPool.h" + "include/ITAUPTrigger.h" + "include/ITADirectConvolution.h" + "include/ITAConvolutionDefinitions.h" ) set( ITAConvolutionSources - src/DSMBCConvolver.cpp - src/DSMBCFilter.cpp - src/DSMBCFilterPool.cpp - src/ITAConvolution.cpp - src/ITAConvolutionImpl.cpp - src/ITAConvolutionImpl.h + "src/ITAUPConvolution.cpp" + "src/ITAUPFilter.cpp" + "src/ITAUPFilterPool.cpp" + "src/ITADirectConvolution.cpp" + "src/ITADirectConvolutionImpl.cpp" + "src/ITADirectConvolutionImpl.h" ) @@ -47,6 +51,10 @@ if( NOT WIN32 ) add_definitions( -std=gnu++11) endif( ) +if( ITA_CONVOLUTION_UPCONV_WITH_POWER_SAVER ) + add_definitions( -DITA_CONVOLUTION_UPCONV_WITH_POWER_SAVER ) +endif( ) + # linker add_library( ITAConvolution ${ITAConvolutionHeader} ${ITAConvolutionSources} ) diff --git a/apps/ita_convoi/ita_convoi.cpp b/apps/ita_convoi/ita_convoi.cpp index 6f432c7..eacfdc6 100644 --- a/apps/ita_convoi/ita_convoi.cpp +++ b/apps/ita_convoi/ita_convoi.cpp @@ -15,9 +15,9 @@ * ---------------------------------------------------------------- * */ -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/DSMBCConvolver.h b/include/DSMBCConvolver.h deleted file mode 100644 index fc4ef44..0000000 --- a/include/DSMBCConvolver.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * ---------------------------------------------------------------- - * - * ITA core libs - * (c) Copyright Institute of Technical Acoustics (ITA) - * RWTH Aachen University, Germany, 2015-2017 - * - * ---------------------------------------------------------------- - * ____ __________ _______ - * // / //__ ___/ // _ | - * // / // / // /_| | - * // / // / // ___ | - * //__/ //__/ //__/ |__| - * - * ---------------------------------------------------------------- - * - */ - -#ifndef INCLUDE_WATCHER_DSMBC_CONVOLVER -#define INCLUDE_WATCHER_DSMBC_CONVOLVER - -#include - -#include -#include -#include -#include -#include - -#include - -// Vorwürtsdeklarationen -class DSMBCFilter; -class DSMBCFilterPool; -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 DSMBCConvolver : public ITAUncopyable -{ -public: - //! Austausch-Modi - enum - { - SWITCH = 0, //!< Hartes Umschalten - CROSSFADE_LINEAR, //!< Lineare Kreuzblende - CROSSFADE_COSINE_SQUARE //!< Cosinus-Quadrat Kreuzblende - }; - - //! Ausgabe-Modi - enum - { - OUTPUT_OVERWRITE = 0, //!< Daten im Ausgabepuffer mit neuen Daten überschreiben - OUTPUT_MIX, //!< Neue Daten in den Ausgabepuffer einmischen - }; - - static const int AUTO = -1; - - //! Standard-Konstruktor - /** - * Erzeugt einen Falter der seinen eigenen Filterpool betreibt - */ - DSMBCConvolver(); - - //! Initialierungs-Konstruktor - /** - * Erzeugt einen Falter. - * - * \param iBlocklength Blocklänge [in Samples] - * \param iMaxFilterlength Maximale Filterlänge [Anzahl Filterkoeffizienten] - */ - DSMBCConvolver( const int iBlocklength, const int iMaxFilterlength, DSMBCFilterPool* pFilterPool = NULL ); - - //! Destruktor - virtual ~DSMBCConvolver(); - - //! 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 DSMBCTrigger* getFilterExchangeTrigger() const; - - //! Trigger für den Filteraustausch setzen - void setFilterExchangeTrigger( const DSMBCTrigger* pTrigger ); - - //! Filteraustausch-Modus zurückgeben - int getFilterExchangeMode(); - - //! Filteraustausch-Modus setzen - void setFilterExchangeMode( 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 - DSMBCFilterPool* getFilterPool() const; - - //! Filterpool setzen - /** - * NULL => Falter-eigenen Pool benutzen - */ - void setFilterPool( DSMBCFilterPool* pFilterPool ); - - //! Freies Filter anfordern - DSMBCFilter* requestFilter(); - - //! Filter wieder zur anderweitigen Benutzung freigeben - void releaseFilter( DSMBCFilter* pFilter ); - - //! Aktives Filter zurückgeben - /** - * Das aktive Filter ist jenes, welches der Falter momentan benutzt. - */ - DSMBCFilter* getActiveFilter(); - - //! Filter austauschen - /** - * Hinweis: Nullzeiger => Aktives Filter entfernen - */ - void exchangeFilter( DSMBCFilter* pNewFilter, const int iExchangeMode = AUTO, const int iCrossfadeLength = AUTO ); - - //! 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 = OUTPUT_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 = OUTPUT_OVERWRITE ); - -private: - typedef struct - { - DSMBCFilter* pFilter; - int iExchangeMode; - int iCrossfadeLength; - } FilterUpdate; - - int m_iBlocklength; - int m_iMaxFilterlength; - - std::atomic< int > m_iExchangeMode; // 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< DSMBCFilter* > m_pCurrentFilter; // Aktives Filter - tbb::strict_ppl::concurrent_queue 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 - - DSMBCFilterPool* m_pCurrentPool; // Gesetzer Filterpool - DSMBCFilterPool* m_pOwnPool; // Falter-eigener Filterpool - DSMBCTriggerWatch 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_DSMBC_CONVOLVER diff --git a/include/DSMBCFilter.h b/include/DSMBCFilter.h deleted file mode 100644 index 645d750..0000000 --- a/include/DSMBCFilter.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * ---------------------------------------------------------------- - * - * ITA core libs - * (c) Copyright Institute of Technical Acoustics (ITA) - * RWTH Aachen University, Germany, 2015-2017 - * - * ---------------------------------------------------------------- - * ____ __________ _______ - * // / //__ ___/ // _ | - * // / // / // /_| | - * // / // / // ___ | - * //__/ //__/ //__/ |__| - * - * ---------------------------------------------------------------- - * - */ - -#ifndef INCLUDE_WATCHER_DSMBC_FILTER -#define INCLUDE_WATCHER_DSMBC_FILTER - -#include - -#include -#include -#include - -#include -#include - -// Vorwärtsdeklarationen -class DSMBCFilterPool; -class ITAFFT; - -/** - * Diese Klasse realisiert Filter (d.h. Representationen von Impulsantworten im Frequenzbereich) - * für DSMBCConvolver. Solche Filter haben einen Zustand: 1) unbenutzt oder 2) momentan in einem - * Falter in Benutzung. Generell kann 1 Filter in beliebig vielen Faltern verwendet werden. - * Seine Daten dürfen aber nur modifiziert werden, wenn es nicht in Benutzung ist. - * - * Eine neue Impulsantwort wird mittels der Methode load geladen und intern transformiert. - * - * Nebenläufigkeit & Synchronisation: - * - * Instanzen der Klasse sollen nur von einem Thread zu einer Zeit benutzt werden - * (üblicherweise der Thread der die Filterdaten generiert hat). Im Sinne der Anwendung - * macht es keinen Sinn das mehrere Threads um beispielsweise die load-Methode konkurrieren. - * Deshalb unternimmt die Klasse keine Maßnahmen zur Synchronisation. - */ - -class ITA_CONVOLUTION_API DSMBCFilter : public ITAUncopyable { -public: - //! Konstruktor - DSMBCFilter(int iBlocklength, int iMaxFilterLength); - - //! Destruktor - /** - * Hinweis: Das Objekt kann nur freigegeben werden, wenn es nicht mehr benutzt wird! - */ - virtual ~DSMBCFilter(); - - //! Gibt zurück ob der Filter aktuell in Benutzung ist - bool isInUse() const; - - //! übergeordneten Filterpool zurückgeben (falls nicht vorhanden NULL) - DSMBCFilterPool* getParentFilterPool() const; - - //! Filter übergeordneten Filterpool freigeben (falls Teil eines Filterpools) - void release(); - - //! Filterdaten laden - /** - * \param pfFilterData Array mit den Filterkoeffizienten - * \param iFilterLength Anzahl Filterkoeffizienten in pfFilterData (maximal iMaxFilterLength) - * - * \note Falls das Filter in Benutzung ist wird eine ITAException geworfen! - */ - void load(const float* pfFilterData, int iFilterLength); - - //! Nullen setzen - void zeros(); - - //! Einheitsimpuls (Dirac) setzen - void identity(); - -//private: - // Interne Zustandklasse, welche Referenzzähler enthält. - // Es werden immer zwei Zähler benötigt: Prep und Use. - class State { - public: - State(DSMBCFilter* pParent); - - bool isInUse() const; - void addPrep(); - void removePrep(); - void xchangePrep2Use(); - void removeUse(); - - //private: - // Damit auf älteren Windows-System, welche keine DCAS-Operationen bereistellen, - // dieser zwei-elementige Zustand atomar verändert werden kann, - // muss eine Datenstruktur von 32-Bit realisiert werden. - // 16-Bit für die Zähler ist immer noch ausreichend - typedef struct - { - std::atomic< int16_t > iPrepRefCount; - std::atomic< int16_t > iUseRefCount; - } StateStruct; - - DSMBCFilter* m_pParent; - StateStruct m_oState; - - void modifyState(int16_t iPrepDelta, int16_t iUseDelta); - }; - - DSMBCFilterPool* m_pParent; // Übergeordneter Filterpool - int m_iBlocklength; // Blocklänge (Zeitbereich) - int m_iNumFilterParts; // Anzahl Filterteile - int m_iNumEffectiveFilterParts; // Anzahl effektiver Filterteile mit Filterkoeff. != 0 - std::vector m_vpfFreqData; // Filterdaten im Frequenzbereich (DFT-Spektren der Teile) - ITAFFT* m_pFFT; - ITACriticalSection m_csReentrance; // Reentrance-Lock für die Load-Methode - State m_oState; // Zustand - - friend class DSMBCConvolver; - friend class DSMBCFilterPool; -}; - -#endif // INCLUDE_WATCHER_DSMBC_FILTER diff --git a/include/DSMBCFilterPool.h b/include/DSMBCFilterPool.h deleted file mode 100644 index e6dea05..0000000 --- a/include/DSMBCFilterPool.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * ---------------------------------------------------------------- - * - * ITA core libs - * (c) Copyright Institute of Technical Acoustics (ITA) - * RWTH Aachen University, Germany, 2015-2017 - * - * ---------------------------------------------------------------- - * ____ __________ _______ - * // / //__ ___/ // _ | - * // / // / // /_| | - * // / // / // ___ | - * //__/ //__/ //__/ |__| - * - * ---------------------------------------------------------------- - * - */ - -#ifndef INCLUDE_WATCHER_DSMBC_FILTER_POOL -#define INCLUDE_WATCHER_DSMBC_FILTER_POOL - -#include - -#include -#include -#include - -// Vorwärtsdeklarationen -class DSMBCFilter; - -/** - * Diese Klasse realisiert eine Verwalter für Filterobjekte und - * ermöglicht ein effizientes Filter-Management mit geringem Speicherverbrauch, - * durch die automatische Wiederverwendung von Filtern. - * - * Nebenläufigkeit & Synchronisation: - * - * Instanzen der Klasse können von beliebig vielen Threads gleichzeitig benutzt werden. - * Alle Methoden mittels synchronisiert und dürfen auch mehrfach parallel aufgerufen - * werden (reentrant). Die Synchronisation ist blocking, aber die Wartezeiten sind - * gering, da innerhalb des exklusiven Zugriffs nur kurze Operationen durchgeführt werden. - * - */ - -class ITA_CONVOLUTION_API DSMBCFilterPool -{ -public: - //! Konstruktor - DSMBCFilterPool(int iBlocklength, int iMaxFilterLength, int iInitialSize); - - //! Destruktor - /** - * Hinweis: Das Objekt kann nur freigegeben werden, wenn es nicht mehr benutzt wird! - */ - virtual ~DSMBCFilterPool(); - - //! Blocklänge zurückgeben - int getBlocklength() const; - - //! Maximale Filterlänge [Anzahl Filterkoeffizienten] zurückgeben - int getMaxFilterlength() const; - - //! Anzahl freier Filter zurückgeben - int getNumFreeFilters() const; - - //! Anzahl freier Filter zurückgeben - int getNumUsedFilters() const; - - //! Anzahl freier Filter zurückgeben - int getNumTotalFilters() const; - - //! Freies Filter anfordern - DSMBCFilter* requestFilter(); - - //! Filter wieder zur anderweitigen Benutzung freigeben - /** - * Ist das Filter nicht in Benutzung, so kann es sofort weiterbenutzt werden. - * Ist das Filter in Benutzung, so wird es für die Weiterbenutzung freigebenen, - * sobald es in einem Falter (DSMBCConvolver) nicht mehr in Benutzung ist - */ - void releaseFilter(DSMBCFilter* pFilter); - -private: - int m_iBlocklength; - int m_iMaxFilterLength; - std::list m_lpFreeFilters; // Unbenutzte (freie) Filter im Pool - std::list m_lpUsedFilters; // Benutzte Filter im Pool - std::list m_lpAutoFilters; // Filter welche nicht mehr seitens den Benutzers - // gebraucht werden, aber noch in einem Falter benutzt werden - ITACriticalSection m_csFilters; // Exklusiver Zugriff auf die Listen -}; - -#endif // INCLUDE_WATCHER_DSMBC_FILTER_POOL \ No newline at end of file diff --git a/include/DSMBCTrigger.h b/include/DSMBCTrigger.h deleted file mode 100644 index 0b069c1..0000000 --- a/include/DSMBCTrigger.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ---------------------------------------------------------------- - * - * ITA core libs - * (c) Copyright Institute of Technical Acoustics (ITA) - * RWTH Aachen University, Germany, 2015-2017 - * - * ---------------------------------------------------------------- - * ____ __________ _______ - * // / //__ ___/ // _ | - * // / // / // /_| | - * // / // / // ___ | - * //__/ //__/ //__/ |__| - * - * ---------------------------------------------------------------- - * - */ - -#ifndef INCLUDE_WATCHER_DSMBC_TRIGGER -#define INCLUDE_WATCHER_DSMBC_TRIGGER - -#include - -#include - -// Lightweight atomic trigger for synchronized filter exchanges -class ITA_CONVOLUTION_API DSMBCTrigger : public ITAUncopyable -{ -public: - DSMBCTrigger() : m_iState(0) {}; - - // Returns the current state - int getState() const { return m_iState; }; - - // Pull the trigger. Update/alter the state. - void trigger() { ++m_iState; }; - -private: - volatile int m_iState; -}; - -// Simple watcher class, realization update checks on a trigger -class ITA_CONVOLUTION_API DSMBCTriggerWatch -{ -public: - DSMBCTriggerWatch() : m_pTrigger(0), bFirst(true), m_iPrevTriggerState(0) {}; - - const DSMBCTrigger* getWatchedTrigger() const { return m_pTrigger; }; - - void setWatchedTrigger(const DSMBCTrigger* pNewTrigger) { - m_pTrigger = pNewTrigger; - bFirst = true; - }; - - // Logic: We always fire, if there is no trigger associated. This is needed in the convolver. - bool fire() { - if (!m_pTrigger) return true; - - int iNewTriggerState = m_pTrigger->getState(); - if ((iNewTriggerState != m_iPrevTriggerState) || bFirst) { - m_iPrevTriggerState = iNewTriggerState; - bFirst = false; - return true; - } - - return false; - }; - -private: - const DSMBCTrigger* m_pTrigger; - bool bFirst; - int m_iPrevTriggerState; -}; - -#endif // INCLUDE_WATCHER_DSMBC_TRIGGER diff --git a/include/ITAConvolution.h b/include/ITAConvolution.h deleted file mode 100644 index 6e4f934..0000000 --- a/include/ITAConvolution.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ---------------------------------------------------------------- - * - * ITA core libs - * (c) Copyright Institute of Technical Acoustics (ITA) - * RWTH Aachen University, Germany, 2015-2017 - * - * ---------------------------------------------------------------- - * ____ __________ _______ - * // / //__ ___/ // _ | - * // / // / // /_| | - * // / // / // ___ | - * //__/ //__/ //__/ |__| - * - * ---------------------------------------------------------------- - * - */ - -#ifndef INCLUDE_WATCHER_ITA_CONVOLUTION -#define INCLUDE_WATCHER_ITA_CONVOLUTION - -#include - -#include -#include -#include - -// Vorwärtsdeklarationen -class ITAConvolutionImpl; - -/** - * Diese Klasse definiert die Schnittstelle für schnelle (offline) Faltungen. - * Die Funktionalität besteht darin zwei Signale möglichst schnell und effizient - * miteinander zu falten. Die Eingaben und Ausgaben werden im Zeitbereich übergeben. - * Instanzen der Klasse repräsentieren Faltungen eines bestimmten Typs - * (bestimmte Eingabeparameter). Damit die maximale Leistung erreicht werden kann, - * müssen vorher die Faltungsoperationen geplant werden. - */ - -class ITA_CONVOLUTION_API ITAConvolution : public ITAUncopyable -{ -public: - // TODO: Flags static const int - static const int DEFAULT_FLAGS = 0; - - //! Standardkonstruktor - ITAConvolution(); - - //! Initialisierungskonstruktor (Arrays) - ITAConvolution(int src1length, - int src2length, - int flags=DEFAULT_FLAGS); - - //! Destruktor - virtual ~ITAConvolution(); - - //! Planungsmethode (Arrays) - void plan(int src1length, - int src2length, - int flags=DEFAULT_FLAGS); - - - //! Gibt zurück ob die Faltung schon geplant ist - bool isPlanned() const; - - //! Faltungsmethode (Arrays) - virtual void convolve(const float* src1, - int src1length, - const float* src2, - int src2length, - float* dest, - int destlength); - -private: - ITAConvolutionImpl* m_pImpl; -}; - -#endif // INCLUDE_WATCHER_ITA_CONVOLUTION diff --git a/src/DSMBCConvolver.cpp b/src/DSMBCConvolver.cpp deleted file mode 100644 index e43aaca..0000000 --- a/src/DSMBCConvolver.cpp +++ /dev/null @@ -1,631 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -DSMBCConvolver::DSMBCConvolver() - : m_iBlocklength( 0 ), - m_iMaxFilterlength( 0 ), - m_iExchangeMode( SWITCH ), - m_iCrossfadeLength( 0 ), - m_pfTimeInputBuffer( NULL ), - m_pfTimeOutputBuffer1( NULL ), - m_pfTimeOutputBuffer2( NULL ), - m_pfFreqAuxBuffer( NULL ), - m_pfFreqMixdownBuffer( NULL ), - m_pCurrentFilter( NULL ), - m_pOwnPool( NULL ), - m_pCurrentPool( NULL ), - m_pFFT( NULL ), - m_pIFFT( NULL ) -{} - -DSMBCConvolver::DSMBCConvolver( const int iBlocklength, const int iMaxFilterlength, DSMBCFilterPool* pFilterPool ) - : m_iBlocklength( iBlocklength ), - m_iMaxFilterlength( iMaxFilterlength ), - m_iExchangeMode( SWITCH ), - m_iCrossfadeLength( 0 ), - m_pfTimeInputBuffer( NULL ), - m_pfTimeOutputBuffer1( NULL ), - m_pfTimeOutputBuffer2( NULL ), - m_pfFreqAuxBuffer( NULL ), - m_pfFreqMixdownBuffer( NULL ), - m_pCurrentFilter( NULL ), - m_pOwnPool( NULL ), - m_pCurrentPool( pFilterPool ), - m_pFFT( NULL ), - m_pIFFT( NULL ) -{ - init( iBlocklength, iMaxFilterlength ); -} - -DSMBCConvolver::~DSMBCConvolver() -{ - // Aktuelles Filter freigeben - DSMBCFilter* pFilter = m_pCurrentFilter; - if( ( DSMBCFilter* ) m_pCurrentFilter ) - ( *m_pCurrentFilter ).m_oState.removeUse(); - - // Nächste Filter in der Queue freigeben - FilterUpdate oUpdate; - while( m_qExchangeFilters.try_pop( oUpdate ) ) - if( oUpdate.pFilter ) oUpdate.pFilter->m_oState.removePrep(); - - // Resourcen freigeben - std::for_each( m_vpfFreqDelayLine.begin(), m_vpfFreqDelayLine.end(), fm_free ); - fm_free( m_pfTimeInputBuffer ); - fm_free( m_pfTimeOutputBuffer1 ); - fm_free( m_pfTimeOutputBuffer2 ); - fm_free( m_pfFreqAuxBuffer ); - fm_free( m_pfFreqMixdownBuffer ); - - delete m_pOwnPool; - delete m_pFFT; - delete m_pIFFT; -} - -void DSMBCConvolver::init( const int iBlocklength, const int iMaxFilterlength ) -{ - /* - * Bemerkungen: - * - * 1. Die Grääe des Filterkoeffizienten-Array pfFilterData muss - * nicht zwingend ein Vielfaches der Puffergrääe sein - * - * 2. Ferner kann seine Grääe kleiner als iBlocklength sein! - */ - - // Anzahl der Filterteile bestimmen - int n = iMaxFilterlength / iBlocklength; - if( ( iMaxFilterlength % iBlocklength ) > 0 ) - n++; - - m_iBlocklength = iBlocklength; - m_iMaxFilterlength = iBlocklength * n; - - // Leere Impulsantwort? Dann haben wir fertig! - if( n == 0 ) - return; - - /* - * Speicher fär die DFT-Koeffizienten der Filterteile allozieren - * und die Filterteile in den Frequenzbereich transformieren. - * Blockfaltungsalgoritmus bedeutet: Linke Seiten der Filterteile - * mässen mit Nullsamples gepadded werden! - */ - - m_iFreqCoeffs = iBlocklength + 1; - m_pfTimeInputBuffer = fm_falloc( 2 * iBlocklength, true ); - m_pfTimeOutputBuffer1 = fm_falloc( 2 * iBlocklength, true ); - m_pfTimeOutputBuffer2 = fm_falloc( 2 * iBlocklength, true ); - - for( int i = 0; i < n; i++ ) - m_vpfFreqDelayLine.push_back( fm_falloc( 2 * m_iFreqCoeffs, true ) ); - - // Frequenzbereichs-Mischpuffer allozieren und Rücktransformation planen - m_pfFreqAuxBuffer = fm_falloc( m_iFreqCoeffs * 2, false ); - m_pfFreqMixdownBuffer = fm_falloc( m_iFreqCoeffs * 2, false ); - - // Transformationen planen - m_pFFT = new ITAFFT( ITAFFT::FFT_R2C, 2 * iBlocklength, m_pfTimeInputBuffer, m_vpfFreqDelayLine[ 0 ] ); - m_pIFFT = new ITAFFT( ITAFFT::IFFT_C2R, 2 * iBlocklength, m_pfFreqMixdownBuffer, m_pfTimeOutputBuffer1 ); - - // Eigenen Filterpool erzeugen - m_pOwnPool = new DSMBCFilterPool( m_iBlocklength, m_iMaxFilterlength, 0 ); - if( !m_pCurrentPool ) m_pCurrentPool = m_pOwnPool; - - m_fCurrentGain = 1; - m_fNewGain = 1; -} - -int DSMBCConvolver::getBlocklength() const -{ - return m_iBlocklength; -} - -int DSMBCConvolver::getMaxFilterlength() const -{ - return m_iMaxFilterlength; -} - -const DSMBCTrigger* DSMBCConvolver::getFilterExchangeTrigger() const -{ - return m_oTriggerWatch.getWatchedTrigger(); -} - -void DSMBCConvolver::setFilterExchangeTrigger( const DSMBCTrigger* pTrigger ) -{ - m_oTriggerWatch.setWatchedTrigger( pTrigger ); -} - -int DSMBCConvolver::getFilterExchangeMode() -{ - return m_iExchangeMode; -} - -void DSMBCConvolver::setFilterExchangeMode( const int iMode ) -{ - m_iExchangeMode = iMode; -} - -int DSMBCConvolver::getFilterCrossfadeLength() -{ - return m_iCrossfadeLength; -} - -void DSMBCConvolver::setFilterCrossfadeLength( const int iLength ) -{ - m_iCrossfadeLength = iLength; -} - -float DSMBCConvolver::getGain() const -{ - return m_fCurrentGain; -} - -void DSMBCConvolver::setGain( const float fGain, const bool bSetImmediately ) -{ - m_fNewGain = fGain; - if( bSetImmediately ) m_fCurrentGain = fGain; -} - -DSMBCFilterPool* DSMBCConvolver::getFilterPool() const -{ - m_csPool.enter(); - DSMBCFilterPool* pResult = m_pCurrentPool; - m_csPool.leave(); - return pResult; -} - -void DSMBCConvolver::setFilterPool( DSMBCFilterPool* pFilterPool ) -{ - if( m_iBlocklength == 0 ) - ITA_EXCEPT1( MODAL_EXCEPTION, "Convolver instance not initialized yet" ); - - // Parameter prüfen - if( ( pFilterPool->getBlocklength() != m_iBlocklength ) || - ( pFilterPool->getMaxFilterlength() != m_iMaxFilterlength ) ) - ITA_EXCEPT1( MODAL_EXCEPTION, "Pool does not meet the properties of the convolver" ); - - m_csPool.enter(); - m_pCurrentPool = ( pFilterPool ? pFilterPool : m_pOwnPool ); - m_csPool.leave(); -} - -DSMBCFilter* DSMBCConvolver::requestFilter() -{ - m_csPool.enter(); - DSMBCFilter* pFilter = m_pCurrentPool->requestFilter(); - m_csPool.leave(); - return pFilter; -} - -void DSMBCConvolver::releaseFilter( DSMBCFilter* pFilter ) -{ - m_csPool.enter(); - m_pCurrentPool->releaseFilter( pFilter ); - m_csPool.leave(); -} - -DSMBCFilter* DSMBCConvolver::getActiveFilter() -{ - return m_pCurrentFilter; -} - -void DSMBCConvolver::exchangeFilter( DSMBCFilter* pNewFilter, const int iExchangeMode, const int iCrossfadeLength ) -{ - //DEBUG_PRINTF("[DSMBCConvolver 0x%08Xh] Exchanging to filter 0x%08Xh\n", this, pNewFilter); - - // Platzierung des Filter vermerken - if( pNewFilter ) - pNewFilter->m_oState.addPrep(); - - // Nächstes Filter in die Austausch-Queue einfügen - FilterUpdate oUpdate; - oUpdate.pFilter = pNewFilter; - oUpdate.iExchangeMode = ( iExchangeMode == AUTO ? ( int ) m_iExchangeMode : iExchangeMode ); - oUpdate.iCrossfadeLength = ( iCrossfadeLength == AUTO ? ( int ) m_iCrossfadeLength : iCrossfadeLength ); - m_qExchangeFilters.push( oUpdate ); -} - -void DSMBCConvolver::clear() -{ - fm_zero( m_pfTimeInputBuffer, 2 * m_iBlocklength ); - fm_zero( m_pfTimeOutputBuffer1, 2 * m_iBlocklength ); - fm_zero( m_pfTimeOutputBuffer2, 2 * m_iBlocklength ); - - for( size_t i = 0; i < m_vpfFreqDelayLine.size(); i++ ) - fm_zero( m_vpfFreqDelayLine[ i ], 2 * m_iFreqCoeffs ); - - fm_zero( m_pfFreqAuxBuffer, 2 * m_iFreqCoeffs ); - fm_zero( m_pfFreqMixdownBuffer, 2 * m_iFreqCoeffs ); - - if( ( DSMBCFilter* ) m_pCurrentFilter ) - { - m_pCurrentPool->releaseFilter( m_pCurrentFilter ); - m_pCurrentFilter = NULL; - } -} - -void DSMBCConvolver::process( const float* pfInputData, float* pfOutputData, const int iOutputMode ) -{ - process( pfInputData, m_iBlocklength, pfOutputData, m_iBlocklength, iOutputMode ); -} - -void DSMBCConvolver::process( const float* pfInputData, const int iInputLength, float* pfOutputData, const int iOutputLength, const int iOutputMode ) -{ - assert( iInputLength >= 0 ); - assert( iOutputLength >= 0 ); - - // Rechte Seite des Hilfspuffers in die linke kopieren. - // Danach die neuen Eingangsdaten in den rechten Hälfte plazieren. - - memcpy( m_pfTimeInputBuffer, m_pfTimeInputBuffer + m_iBlocklength, m_iBlocklength * sizeof( float ) ); - - if( pfInputData > 0 && pfInputData != nullptr ) - { - if( iInputLength >= m_iBlocklength ) - { - // Eingangsdaten am Stück kopieren - memcpy( m_pfTimeInputBuffer + m_iBlocklength, pfInputData, m_iBlocklength * sizeof( float ) ); - } - else - { - // Eingabedaten kopieren und den Rest mit Nullen füllen - memcpy( m_pfTimeInputBuffer + m_iBlocklength, pfInputData, iInputLength * sizeof( float ) ); - memset( m_pfTimeInputBuffer + m_iBlocklength + iInputLength, 0, ( m_iBlocklength - iInputLength ) * sizeof( float ) ); - } - } - else - { - // Nullen setzen. - fm_zero( m_pfTimeInputBuffer + m_iBlocklength, m_iBlocklength ); - } - - // Elemente der Frequency-domain delay line (FDL) weiterschieben - int n = ( int ) m_vpfFreqDelayLine.size(); - float* X = m_vpfFreqDelayLine.back(); - for( int i = n - 1; i > 0; i-- ) m_vpfFreqDelayLine[ i ] = m_vpfFreqDelayLine[ i - 1 ]; - m_vpfFreqDelayLine[ 0 ] = X; - - // Eingangsdaten in den Frequenzbereich transformieren - m_pFFT->execute( m_pfTimeInputBuffer, X ); - - // Globale Austausch-Parameter - int xmode = m_iExchangeMode; - int iCrossfadeLength = m_iCrossfadeLength; - - // Werte holen [atomar] - FilterUpdate oUpdate; - DSMBCFilter* C = m_pCurrentFilter; - DSMBCFilter* N = NULL; - DSMBCFilter* Z = NULL; - bool bNewFilters = false; - bool bForceSwitch = false; - - // Test auf neue Filter nur dann durchführen, wenn der Trigger signalisiert wurde - // oder gar kein Trigger zuordnet ist (dies wird in der TriggerWatch realisiert). - if( m_oTriggerWatch.fire() ) { - - // Alle bis auf das letzte Filter in der Austausch-Queue freigeben - while( m_qExchangeFilters.try_pop( oUpdate ) ) { - bNewFilters = true; - Z = oUpdate.pFilter; - - // Lokale Parameter übernehmen - xmode = oUpdate.iExchangeMode; - iCrossfadeLength = oUpdate.iCrossfadeLength; - // Wichtig: Ein Switching bei den Updates ist dominant - bForceSwitch |= ( xmode == SWITCH ); - - //DEBUG_PRINTF("[DSMBCConvolver 0x%08Xh] Popped next filter 0x%08Xh\n", this, Z); - if( N ) N->m_oState.removePrep(); - N = Z; - } - // Hinweis: N enthält jetzt das letzte Element der Queue (kann auch NULL sein) - - } - - // Keine Änderung - if( !bNewFilters ) N = C; - - if( bForceSwitch ) - { - xmode = SWITCH; - iCrossfadeLength = 0; - } - - // Im Fall von Umschalten das alte Filter sofort freigeben (wird nicht mehr benötigt) - // Dies gilt auch falls keine Ausgabedaten ausgegeben werden sollen. - if( ( xmode == SWITCH ) || ( !pfOutputData ) ) - { - if( C != N ) - { - if( C ) C->m_oState.removeUse(); - if( N ) N->m_oState.xchangePrep2Use(); - C = N; - m_pCurrentFilter = N; - } - - } - - if( !pfOutputData ) - { - m_fCurrentGain = ( float ) m_fNewGain; - return; - } - - int iOutputCount = ( std::min )( m_iBlocklength, iOutputLength ); - if( !pfOutputData ) - iOutputCount = 0; // Legacy support - - /* - * Austausch-Verfahrensweisen - * - * Generelles: Bei diesem Code wurde mehr wert auf übersichlichtlich gelegt. - * Deshalb werden die nur selten auftretenden Fälle leerer Filter - * nicht optimiert. Grundsätzlich werden zwei Stränge berechnet: - * Einer für das alte Filter und einer für das neue. Im Falle von - * hartem Unschalten wird nur ein Strang bestimmt. - */ - - if( C == N ) - { - - // Fall: Keine Austausch des Filters oder Austausch durch hartes Umschalten (siehe oben) - // Aufgabe: Nur einen Strang falten. Keine Überblendung. - - if( C != NULL ) - { - // Gleiches Filter wie bisher. Normal falten. - if( C->m_iNumEffectiveFilterParts > 0 ) { - for( int i = 0; i < C->m_iNumEffectiveFilterParts; i++ ) { - if( i == 0 ) { - // Ergebnis direkt in den Misch-Puffer speichern - fm_cmul_x( m_pfFreqMixdownBuffer, m_vpfFreqDelayLine[ i ], C->m_vpfFreqData[ i ], m_iFreqCoeffs ); - } - else { - // Ergebnis zwischenpuffern, danach auf den Misch-Puffer aufaddieren - fm_cmul_x( m_pfFreqAuxBuffer, m_vpfFreqDelayLine[ i ], C->m_vpfFreqData[ i ], m_iFreqCoeffs ); - fm_add( m_pfFreqMixdownBuffer, m_pfFreqAuxBuffer, m_iFreqCoeffs * 2 ); - } - } - - // Rücktransformation durchführen - m_pIFFT->execute( m_pfFreqMixdownBuffer, m_pfTimeOutputBuffer1 ); - - // Verstärkungs-Envelope anwenden - copyOutputApplyGain1( pfOutputData, m_pfTimeOutputBuffer1, iOutputCount, iOutputMode ); - - return; - - } - else - { - // Keine effektiven Filterteile => Ausgabe ist Null - if( iOutputMode == OUTPUT_OVERWRITE ) - memset( pfOutputData, 0, iOutputCount*sizeof( float ) ); - return; - } - - - } - else - { - // Abkürzung: Leeres Filter -> Keine Ausgangsdaten - if( iOutputMode == OUTPUT_OVERWRITE ) - { - for( int i = 0; i < iOutputCount; i++ ) - pfOutputData[ i ] = 0; - } - - m_fCurrentGain = ( float ) m_fNewGain; - - return; - } - - } - else - { - - // Fall: Austausch des Filters. Kein Umschalten. Eine Impulsantwort kann leer sein. - // Aufgabe: Nur einen Strang falten. Keine Überblendung. - - if( C != NULL ) - { - if( C->m_iNumEffectiveFilterParts > 0 ) - { - // Falten mit aktuellen Filter - for( int i = 0; i < C->m_iNumEffectiveFilterParts; i++ ) - { - if( i == 0 ) - { - // Ergebnis direkt in den Misch-Puffer speichern - fm_cmul_x( m_pfFreqMixdownBuffer, m_vpfFreqDelayLine[ i ], C->m_vpfFreqData[ i ], m_iFreqCoeffs ); - } - else - { - // Ergebnis zwischenpuffern, danach auf den Misch-Puffer aufaddieren - fm_cmul_x( m_pfFreqAuxBuffer, m_vpfFreqDelayLine[ i ], C->m_vpfFreqData[ i ], m_iFreqCoeffs ); - fm_add( m_pfFreqMixdownBuffer, m_pfFreqAuxBuffer, m_iFreqCoeffs * 2 ); - } - } - - m_pIFFT->execute( m_pfFreqMixdownBuffer, m_pfTimeOutputBuffer1 ); - - int iFadeOptions = ITA_FADE_OUT | ( xmode == CROSSFADE_LINEAR ? ITA_FADE_LINEAR : ITA_FADE_COSINE_SQUARE ); - Fade( m_pfTimeOutputBuffer1, iCrossfadeLength, iFadeOptions, 0, iCrossfadeLength ); - - } - else - { - // Keine effektiven Filterteile => Zwischenergebnis ist Null - fm_zero( m_pfTimeOutputBuffer1, m_iBlocklength ); - } - - // Altes Filter freigeben - C->m_oState.removeUse(); - - } - else - { - fm_zero( m_pfTimeOutputBuffer1, m_iBlocklength ); - } - - // Falten mit dem neuen Filter - if( N != NULL ) - { - // Neues Filter sperren - N->m_oState.xchangePrep2Use(); - - if( N->m_iNumEffectiveFilterParts > 0 ) - { - for( int i = 0; i < N->m_iNumEffectiveFilterParts; i++ ) - { - if( i == 0 ) - { - // Ergebnis direkt in den Misch-Puffer speichern - fm_cmul_x( m_pfFreqMixdownBuffer, m_vpfFreqDelayLine[ i ], N->m_vpfFreqData[ i ], m_iFreqCoeffs ); - } - else - { - // Ergebnis zwischenpuffern, danach auf den Misch-Puffer aufaddieren - fm_cmul_x( m_pfFreqAuxBuffer, m_vpfFreqDelayLine[ i ], N->m_vpfFreqData[ i ], m_iFreqCoeffs ); - fm_add( m_pfFreqMixdownBuffer, m_pfFreqAuxBuffer, m_iFreqCoeffs * 2 ); - } - } - m_pIFFT->execute( m_pfFreqMixdownBuffer, m_pfTimeOutputBuffer2 ); - - int iFadeOptions = ITA_FADE_IN | ( xmode == CROSSFADE_LINEAR ? ITA_FADE_LINEAR : ITA_FADE_COSINE_SQUARE ); - Fade( m_pfTimeOutputBuffer2, iCrossfadeLength, iFadeOptions, 0, iCrossfadeLength ); - } - else - { - // Keine effektiven Filterteile => Zwischenergebnis ist Null - fm_zero( m_pfTimeOutputBuffer2, m_iBlocklength ); - } - } - else - { - fm_zero( m_pfTimeOutputBuffer2, m_iBlocklength ); - } - - // Ausgabe normalisieren und im Ausgabepuffer zusammenkopieren - // Linke Seite von m_pfTimeOutputBuffer enthält die Nutzdaten. - copyOutputApplyGain2( pfOutputData, m_pfTimeOutputBuffer1, m_pfTimeOutputBuffer2, iOutputCount, iCrossfadeLength, iOutputMode ); - - // Filteraustausch vermerken: - m_pCurrentFilter = N; - - return; - } -} - -// Transferriert Samples vom den internen Puffern in die Ausgabe und wendet dabei die Gains an. -// Div ist ein Skalierungsfaktor (1/x) für die unnormalisierte inverse FFT. -void DSMBCConvolver::copyOutputApplyGain1( float* pfDest, const float* pfSrc, const int iOutputLength, const int iOutputMode ) -{ - // Atomares lesen in lokale Variablen - float fGain1 = m_fCurrentGain; - float fGain2 = m_fNewGain; - - if( ( fGain1 == fGain2 ) && ( fGain1 != 1 ) ) - { - // Keine Änderung und neues Gain nicht 1 => Konstanter Gain - if( iOutputMode == OUTPUT_OVERWRITE ) - { - // Ausgabe Überschreiben - for( int i = 0; i < iOutputLength; i++ ) - pfDest[ i ] = pfSrc[ i ] * fGain1; - } - else - { - // Ausgabe Aufaddieren - for( int i = 0; i < iOutputLength; i++ ) - pfDest[ i ] += pfSrc[ i ] * fGain1; - } - - } - else - { - // Verstärkung ändert sich => Linear interpolierter Gain - float c = ( fGain2 - fGain1 ) / ( float ) m_iBlocklength; - - if( iOutputMode == OUTPUT_OVERWRITE ) - { - // Ausgabe Überschreiben - for( int i = 0; i < iOutputLength; i++ ) - pfDest[ i ] = pfSrc[ i ] * ( fGain1 + i*c ); - } - else { - // Ausgabe Aufaddieren - for( int i = 0; i < iOutputLength; i++ ) - pfDest[ i ] += pfSrc[ i ] * ( fGain1 + i*c ); - } - - m_fCurrentGain = fGain2; - } -} - -// Wie oben, nur mit zwei Quellpuffern die direkt addiert werden. -void DSMBCConvolver::copyOutputApplyGain2( float* pfDest, const float* pfSrc1, const float* pfSrc2, const int iOutputLength, const int iCrossfadeLength, int iOutputMode ) -{ - // Atomares lesen in lokale Variablen - float fGain1 = m_fCurrentGain; - float fGain2 = m_fNewGain; - - if( ( fGain1 == fGain2 ) && ( fGain1 != 1 ) ) - { - // Keine Änderung und neues Gain nicht 1 => Konstanter Gain - if( iOutputMode == OUTPUT_OVERWRITE ) { - // Ausgabe Überschreiben - for( int i = 0; i < ( std::min )( iCrossfadeLength, iOutputLength ); i++ ) - pfDest[ i ] = ( pfSrc1[ i ] + pfSrc2[ i ] ) * fGain1; - for( int i = iCrossfadeLength; i < ( std::min )( m_iBlocklength, iOutputLength ); i++ ) - pfDest[ i ] = pfSrc2[ i ] * fGain1; - } - else - { - // Ausgabe Aufaddieren - for( int i = 0; i < ( std::min )( iCrossfadeLength, iOutputLength ); i++ ) - pfDest[ i ] += ( pfSrc1[ i ] + pfSrc2[ i ] ) * fGain1; - for( int i = iCrossfadeLength; i < ( std::min )( m_iBlocklength, iOutputLength ); i++ ) - pfDest[ i ] += pfSrc2[ i ] * fGain1; - } - - } - else - { - // Verstärkung ändert sich => Linear interpolierter Gain - float c = ( fGain2 - fGain1 ) / ( float ) m_iBlocklength; - - if( iOutputMode == OUTPUT_OVERWRITE ) - { - // Ausgabe Überschreiben - for( int i = 0; i < ( std::min )( iCrossfadeLength, iOutputLength ); i++ ) - pfDest[ i ] = ( pfSrc1[ i ] + pfSrc2[ i ] ) * ( fGain1 + i*c ); - for( int i = iCrossfadeLength; i < ( std::min )( m_iBlocklength, iOutputLength ); i++ ) - pfDest[ i ] = pfSrc2[ i ] * ( fGain1 + i*c ); - } - else - { - // Ausgabe Aufaddieren - for( int i = 0; i < ( std::min )( iCrossfadeLength, iOutputLength ); i++ ) - pfDest[ i ] += ( pfSrc1[ i ] + pfSrc2[ i ] ) * ( fGain1 + i*c ); - for( int i = iCrossfadeLength; i < ( std::min )( m_iBlocklength, iOutputLength ); i++ ) - pfDest[ i ] += pfSrc2[ i ] * ( fGain1 + i*c ); - } - - m_fCurrentGain = fGain2; - } -} diff --git a/src/DSMBCFilter.cpp b/src/DSMBCFilter.cpp index 9f284f3..f59ad9b 100644 --- a/src/DSMBCFilter.cpp +++ b/src/DSMBCFilter.cpp @@ -11,91 +11,96 @@ #include #include -// Leistungssparende Variante: Testen ob Filterkoeffizienten = 0 und nur effektive Teile falten. -#define WITH_POWER_SAVER 1 - -DSMBCFilter::DSMBCFilter(int iBlocklength, int iMaxFilterLength) -: m_iBlocklength(iBlocklength) -, m_pParent(NULL) -, m_pFFT(NULL) -, m_iNumEffectiveFilterParts(0) -, m_oState(this) +DSMBCFilter::DSMBCFilter( const int iBlocklength, const int iMaxFilterLength ) + : m_iBlocklength( iBlocklength ) + , m_pParent( NULL ) + , m_pFFT( NULL ) + , m_iNumEffectiveFilterParts( 0 ) + , m_oState( this ) { - m_iNumFilterParts = uprdiv(iMaxFilterLength, iBlocklength); - int iFreqCoeffs = iBlocklength+1; + m_iNumFilterParts = uprdiv( iMaxFilterLength, iBlocklength ); + int iFreqCoeffs = iBlocklength + 1; // Anzahl Filterteile bestimmen - m_vpfFreqData.resize(m_iNumFilterParts, NULL); + m_vpfFreqData.resize( m_iNumFilterParts, NULL ); // Datenpuffer allozieren - for (int i=0; ireleaseFilter(this); +void DSMBCFilter::release() +{ + if( m_pParent ) m_pParent->releaseFilter( this ); } -bool DSMBCFilter::isInUse() const { +bool DSMBCFilter::isInUse() const +{ return m_oState.isInUse(); } -void DSMBCFilter::load(const float* pfFilterData, int iFilterLength) { +void DSMBCFilter::load( const float* pfFilterData, const int iFilterLength ) +{ m_csReentrance.enter(); // Wichtig: Das Laden des Filter ist nur möglich, // wenn das Filter in keinem Falter aktuell benutzt wird - if (isInUse()) { + if( isInUse() ) + { m_csReentrance.leave(); - ITA_EXCEPT1(MODAL_EXCEPTION, "Filter is placed for use or already in use"); + ITA_EXCEPT1( MODAL_EXCEPTION, "Filter is placed for use or already in use" ); } - int iFreqCoeffs = m_iBlocklength+1; + int iFreqCoeffs = m_iBlocklength + 1; // Sonderfall: Leeres Filter -> Leerer Teilspektren - if ((pfFilterData == NULL) || (iFilterLength == 0)) { - for (int i=0; i 0) { - for (int k=0; k= ZERO_THRESHOLD) { + if( iRemain > 0 ) + { + for( int k = 0; k < std::min( iRemain, m_iBlocklength ); k++ ) { + if( std::abs( pfFilterData[ iOffset + k ] ) >= ZERO_THRESHOLD ) { // Keine Nullen in diesem Block - m_iNumEffectiveFilterParts = i+1; + m_iNumEffectiveFilterParts = i + 1; bZeros = false; break; } @@ -108,80 +113,92 @@ void DSMBCFilter::load(const float* pfFilterData, int iFilterLength) { // IFFT Normalisierungsfaktor const float fScale = m_iBlocklength*2.0F; - if ((iRemain == 0) || bZeros) { + if( ( iRemain == 0 ) || bZeros ) + { // Block Nullen setzen - memset(m_vpfFreqData[i]+m_iBlocklength, 0, m_iBlocklength*sizeof(float)); - } else { - if (iRemain < m_iBlocklength) { + memset( m_vpfFreqData[ i ] + m_iBlocklength, 0, m_iBlocklength*sizeof( float ) ); + } + else + { + if( iRemain < m_iBlocklength ) + { // Weniger als ein ganzer Block Filterkoeffizienten // (Normalisieren mit 1/2B da der Falter eine unnormalisierte IFFT benutzt) //memcpy(m_vpfFreqData[i]+m_iBlocklength, pfFilterData+iOffset, iRemain*sizeof(float)); - for (int k=0; kexecute(m_vpfFreqData[i], m_vpfFreqData[i]); + m_pFFT->execute( m_vpfFreqData[ i ], m_vpfFreqData[ i ] ); } -#if (WITH_POWER_SAVER!=1) +#ifndef ITA_CONVOLUTION_UPCONV_WITH_POWER_SAVER // Immer alle Teile falten m_iNumEffectiveFilterParts = m_iNumFilterParts; -#endif // !WITH_POWER_SAVER +#endif m_csReentrance.leave(); } -void DSMBCFilter::zeros() { - load(NULL, 0); +void DSMBCFilter::zeros() +{ + load( NULL, 0 ); } -void DSMBCFilter::identity() { +void DSMBCFilter::identity() +{ zeros(); const float pfDirac[] = { 1 }; - load(pfDirac, 1); + load( pfDirac, 1 ); } // --= State class =-- -DSMBCFilter::State::State(DSMBCFilter* pParent) { +DSMBCFilter::State::State( DSMBCFilter* pParent ) +{ m_pParent = pParent; m_oState.iPrepRefCount = 0; m_oState.iUseRefCount = 0; } -bool DSMBCFilter::State::isInUse() const +bool DSMBCFilter::State::isInUse() const { return ( 0 < m_oState.iPrepRefCount + m_oState.iUseRefCount ); } -void DSMBCFilter::State::addPrep() { - modifyState(1, 0); +void DSMBCFilter::State::addPrep() +{ + modifyState( 1, 0 ); } -void DSMBCFilter::State::removePrep() { - modifyState(-1, 0); +void DSMBCFilter::State::removePrep() +{ + modifyState( -1, 0 ); } -void DSMBCFilter::State::xchangePrep2Use() { - modifyState(-1, +1); +void DSMBCFilter::State::xchangePrep2Use() +{ + modifyState( -1, +1 ); } void DSMBCFilter::State::removeUse() { - modifyState(0, -1); + modifyState( 0, -1 ); } -void DSMBCFilter::State::modifyState(int16_t iPrepDelta, int16_t iUseDelta) +void DSMBCFilter::State::modifyState( const int16_t iPrepDelta, const int16_t iUseDelta ) { m_oState.iPrepRefCount += iPrepDelta; m_oState.iUseRefCount += iUseDelta; diff --git a/src/DSMBCFilterPool.cpp b/src/DSMBCFilterPool.cpp deleted file mode 100644 index f9b144b..0000000 --- a/src/DSMBCFilterPool.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -// Debug-Meldung ausgeben -#define VERBOSE 0 - -DSMBCFilterPool::DSMBCFilterPool(int iBlocklength, int iMaxFilterLength, int iInitialSize) -: m_iBlocklength(iBlocklength), m_iMaxFilterLength(iMaxFilterLength) -{ - for (int i=0; im_pParent = this; - m_lpFreeFilters.push_back(pFilter); - } -} - -DSMBCFilterPool::~DSMBCFilterPool() { - m_csFilters.enter(); - - std::for_each(m_lpFreeFilters.begin(), m_lpFreeFilters.end(), deleteFunctor); - std::for_each(m_lpUsedFilters.begin(), m_lpUsedFilters.end(), deleteFunctor); - std::for_each(m_lpAutoFilters.begin(), m_lpAutoFilters.end(), deleteFunctor); - - m_csFilters.leave(); -} - -int DSMBCFilterPool::getBlocklength() const { - return m_iBlocklength; -} - -int DSMBCFilterPool::getMaxFilterlength() const { - return m_iMaxFilterLength; -} - -int DSMBCFilterPool::getNumFreeFilters() const { - m_csFilters.enter(); - int iResult = (int) m_lpFreeFilters.size(); - m_csFilters.leave(); - return iResult; -} - -int DSMBCFilterPool::getNumUsedFilters() const { - m_csFilters.enter(); - int iResult = (int) m_lpUsedFilters.size() + (int) m_lpAutoFilters.size(); - m_csFilters.leave(); - return iResult; -} - -int DSMBCFilterPool::getNumTotalFilters() const { - m_csFilters.enter(); - int iResult = (int) m_lpFreeFilters.size() + (int) m_lpUsedFilters.size() + (int) m_lpAutoFilters.size(); - m_csFilters.leave(); - return iResult; -} - -DSMBCFilter* DSMBCFilterPool::requestFilter() { - m_csFilters.enter(); - - DSMBCFilter* pFilter = nullptr; - - if (m_lpFreeFilters.empty()) { - // Fall: Keine Filter in der Frei-Liste -> Zunächst schauen ob freie Filter in der Auto-Liste - if (!m_lpAutoFilters.empty()) { - for (std::list::iterator it=m_lpAutoFilters.begin(); it!=m_lpAutoFilters.end(); ++it) { - /* - * Wichtig: Wenn der Filter bereits in der Auto-Liste ist, - * hat der Benutzer für dieses Filter release() aufgerufen. - * Er braucht den Filter also nicht mehr und darf den - * ihm zuvor genannten Zeiger nicht mehr weiterbenutzen. - * Deshalb kann auch den Filter auch nicht zwischenzeitlich - * in einen anderen Falter einsetzen. - * - * Fazit: Es ist sicher hier nur-lesend zu testen! - */ - - assert( (*it) != 0 ); - - if (!(*it)->isInUse()) { - pFilter = (*it); - - // Filter wieder vergeben - m_lpAutoFilters.erase(it); -#if VERBOSE==1 - { - DEBUG_PRINTF("[DSMBCFilterPool] Reusing auto filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); - } -#endif - break; - } -// } else { -// // Nur Meldung machen -// DSMBCFilter::State::StateStruct ss; -// ss.iPrepRefCount = 0; -// ss.iUseRefCount = 0; -// if (pFilter) atomic_read32( &pFilter->m_oState.m_oState, &ss ); -//#if VERBOSE==1 -// DEBUG_PRINTF("[DSMBCFilterPool] Cannot reusing auto filter 0x%08Xh (preps=%d, uses=%d) [Used %d, Auto %d, Free %d, Total %d]\n", -// pFilter, ss.iPrepRefCount, ss.iUseRefCount, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -//#endif -// } - } - } - - if (pFilter == nullptr) { - // Fall: Auch kein freies Filter in der Auto-Liste -> Neues Filter erzeugen - pFilter = new DSMBCFilter(m_iBlocklength, m_iMaxFilterLength); - pFilter->m_pParent = this; - -#if VERBOSE==1 - DEBUG_PRINTF("[DSMBCFilterPool] Created new filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -#endif - } - - m_lpUsedFilters.push_back(pFilter); - - } else { - // Fall: Freie Filter verfügbar - pFilter = m_lpFreeFilters.back(); - m_lpFreeFilters.pop_back(); - m_lpUsedFilters.push_back(pFilter); - -//#if VERBOSE==1 -// { -// // Nur Meldung machen -// DSMBCFilter::State::StateStruct ss; -// ss.iPrepRefCount = 0; -// ss.iUseRefCount = 0; -// if (pFilter) atomic_read32( &pFilter->m_oState.m_oState, &ss ); -// DEBUG_PRINTF("[DSMBCFilterPool] Freed filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", -// pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -// } -//#endif - } - - m_csFilters.leave(); - - -#if VERBOSE==1 - DEBUG_PRINTF("[DSMBCFilterPool] Request returns filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -#endif - - return pFilter; -} - -void DSMBCFilterPool::releaseFilter(DSMBCFilter* pFilter) { - m_csFilters.enter(); - - // Nonsens einfach ignoieren - if (!pFilter) { - m_csFilters.leave(); - return; - } - -#if VERBOSE==1 - DEBUG_PRINTF("[DSMBCFilterPool] Release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -#endif - - // Zunächst die eigene Zust?ndigkeit sicherstellen - std::list::iterator it = std::find(m_lpUsedFilters.begin(), m_lpUsedFilters.end(), pFilter); - if (it == m_lpUsedFilters.end()) { - // Filter garnicht aus diesem Pool. Ignorieren ... - m_csFilters.leave(); - return; - } - - /* - // Schneller und einfacher Test auf Zuständigkeit - if (pFilter->m_pParent != this) { - m_csFilters.leave(); - return; - } - */ - - if (pFilter->isInUse()) { - // Ist der Filter noch in Faltern in Benutzung -> Zur Freigabe vormerken (Auto-Liste) - m_lpUsedFilters.erase(it); - m_lpAutoFilters.push_back(pFilter); - m_csFilters.leave(); - -#if VERBOSE==1 - DEBUG_PRINTF("[DSMBCFilterPool] Auto-release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -#endif - return; - } - - // Filter wieder in die Frei-Liste - m_lpUsedFilters.erase(it); - m_lpFreeFilters.push_back(pFilter); - -#if VERBOSE==1 - DEBUG_PRINTF("[DSMBCFilterPool] Instant-release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n", - pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters()); -#endif - - m_csFilters.leave(); -} diff --git a/src/ITAConvolution.cpp b/src/ITAConvolution.cpp deleted file mode 100644 index a389ae0..0000000 --- a/src/ITAConvolution.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -#include -#include "ITAConvolutionImpl.h" - - -ITAConvolution::ITAConvolution() : m_pImpl(NULL) {} - -ITAConvolution::ITAConvolution(int src1length, int src2length, int flags) : m_pImpl(NULL) { - plan(src1length, src2length, flags); -} - -ITAConvolution::~ITAConvolution() { - delete m_pImpl; -} - -void ITAConvolution::plan(int src1length, - int src2length, - int flags) { - if (m_pImpl) { - delete m_pImpl; - m_pImpl = NULL; - } - - m_pImpl = new ITAConvolutionImpl(src1length, src2length, flags); -} - -bool ITAConvolution::isPlanned() const { - return (m_pImpl != NULL); -} - -void ITAConvolution::convolve(const float* src1, int src1length, const float* src2, int src2length, float* dest, int destlength) { - if (m_pImpl) m_pImpl->convolve(src1, src1length, src2, src2length, dest, destlength); -} diff --git a/src/ITAConvolutionImpl.cpp b/src/ITAConvolutionImpl.cpp deleted file mode 100644 index 22cb485..0000000 --- a/src/ITAConvolutionImpl.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "ITAConvolutionImpl.h" - -#include -#include - -#include - -ITAConvolutionImpl::ITAConvolutionImpl(int src1length, int src2length, int flags) -: m_pConvolver(NULL) -, m_pFilter(NULL) -{ - int iSignallength; - int iFilterlength; - - // Kürzere Eingabe = Signal, die andere das Filter - if (src1length < src2length) { - iSignallength = src2length; - iFilterlength = src1length; - m_iFilter = 1; - } else { - iSignallength = src1length; - iFilterlength = src2length; - m_iFilter = 2; - } - - // Blocklänge = Nächste Zweierpotenz größer der Filterlänge - m_iBlocklength = (int) nextPow2( (unsigned int) iFilterlength); - m_pConvolver = new DSMBCConvolver(m_iBlocklength, iFilterlength); - m_pConvolver->setFilterExchangeMode( DSMBCConvolver::SWITCH ); - - // Filter holen - m_pFilter = m_pConvolver->requestFilter(); -} - -ITAConvolutionImpl::~ITAConvolutionImpl() { - delete m_pConvolver; -} - -void ITAConvolutionImpl::convolve(const float* src1, - int src1length, - const float* src2, - int src2length, - float* dest, - int destlength) { - - if (!m_pConvolver) return; - - const float* pfInput; - int iInputLength; - - // Filter laden - if (m_iFilter == 1) { - m_pFilter->load(src1, src1length); - pfInput = src2; - iInputLength = src2length; - } else { - m_pFilter->load(src2, src2length); - pfInput = src1; - iInputLength = src1length; - } - m_pConvolver->exchangeFilter(m_pFilter); - - // Iterativ durchfalten - int k = 0; - while (kprocess( pfInput + k, ri, dest + k, ro ); - k += ro; - } -} diff --git a/src/ITAConvolutionImpl.h b/src/ITAConvolutionImpl.h deleted file mode 100644 index 3746e60..0000000 --- a/src/ITAConvolutionImpl.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __ITA_CONVOLUTION_IMPL_H__ -#define __ITA_CONVOLUTION_IMPL_H__ - -#include - -// Vorwärtsdeklarationen -class DSMBCConvolver; -class DSMBCFilter; - -// Implementierungsklasse der Faltungsklasse ITAConvolution -class ITAConvolutionImpl : public ITAConvolution { -public: - //! Konstruktor - ITAConvolutionImpl(int src1length, - int src2length, - int flags); - - //! Destruktor - virtual ~ITAConvolutionImpl(); - - //! Faltungsmethode - virtual void convolve(const float* src1, - int src1length, - const float* src2, - int src2length, - float* dest, - int destlength); - -private: - DSMBCConvolver* m_pConvolver; - DSMBCFilter* m_pFilter; - int m_iFilter; // Index welche Eingabe der Filter ist (src1|src2) - int m_iBlocklength; -}; - -#endif // __ITA_CONVOLUTION_IMPL_H__ diff --git a/tests/DSMBCTest.cpp b/tests/DSMBCTest.cpp index 2742610..dd3098d 100644 --- a/tests/DSMBCTest.cpp +++ b/tests/DSMBCTest.cpp @@ -7,9 +7,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/tests/ITAConvolutionTest.cpp b/tests/ITAConvolutionTest.cpp index fedd12d..273a4d7 100644 --- a/tests/ITAConvolutionTest.cpp +++ b/tests/ITAConvolutionTest.cpp @@ -4,44 +4,46 @@ #include #include -#include +#include #include using namespace std; -void test1() { +void test1() +{ // Einfaches Durchfalten. Kein Austausch - const int m=7; - const int n=5; - int o = m+n-1; + const int m = 7; + const int n = 5; + int o = m + n - 1; - float* s = new float[m]; - float* h = new float[n]; - float* g = new float[o]; + float* s = new float[ m ]; + float* h = new float[ n ]; + float* g = new float[ o ]; - memset(s, 0, m*sizeof(float)); - memset(h, 0, n*sizeof(float)); - memset(g, 0, o*sizeof(float)); + memset( s, 0, m*sizeof( float ) ); + memset( h, 0, n*sizeof( float ) ); + memset( g, 0, o*sizeof( float ) ); - for (int i=0; i<(m>>1); i++) s[i] = 1; - for (int i=0; i<(n>>1); i++) h[i] = 1; + for( int i = 0; i < ( m >> 1 ); i++ ) s[ i ] = 1; + for( int i = 0; i < ( n >> 1 ); i++ ) h[ i ] = 1; //for (int i=0; i