Commit ab3bba04 authored by Jonas Stienen's avatar Jonas Stienen

Initial checkin

parents
cmake_minimum_required( VERSION 2.8 )
project( ITADataSources )
list( APPEND CMAKE_MODULE_PATH "$ENV{VISTA_CMAKE_COMMON}" )
include( VistaCommon )
# dependencies
vista_use_package( ITABase REQUIRED FIND_DEPENDENCIES )
vista_use_package( ASIO QUIET )
vista_use_package( Portaudio QUIET )
if( NOT DEFINED ITA_DATA_SOURCE_WITH_INTEGRATED_ASIO )
set( ITA_DATA_SOURCE_WITH_INTEGRATED_ASIO ${VASIO_FOUND} CACHE BOOL "Build with ASIO support" )
endif( NOT DEFINED ITA_DATA_SOURCE_WITH_INTEGRATED_ASIO )
if( NOT DEFINED ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
set( ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO ${VPORTAUDIO_FOUND} CACHE BOOL "Build with Portaudio support" )
endif( NOT DEFINED ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
# includes
include_directories( "include" )
# sources
set( ITADataSourcesHeader
"include/ITABufferDataSink.h"
"include/ITABufferDataSource.h"
"include/ITADataSource.h"
"include/ITADataSourceRealization.h"
"include/ITADataSourcesDefinitions.h"
"include/ITADataSourceUtils.h"
"include/ITAFileDataSink.h"
"include/ITAFileDataSource.h"
"include/ITAPeakDetector.h"
"include/ITAStreamAmplifier.h"
#"include/ITAStreamFilter.h"
"include/ITAStreamFunctionGenerator.h"
"include/ITAStreamModalSynthesizer.h"
"include/ITAStreamMultiplier1N.h"
"include/ITAStreamPatchBay.h"
"include/ITAStreamProbe.h"
"include/ITAStreamProperties.h"
"include/ITAStreamPump.h"
"include/ITAStreamYJunction.h"
)
set( ITADataSourcesSources
"src/ITABufferDataSink.cpp"
"src/ITABufferDataSource.cpp"
"src/ITADataSource.cpp"
"src/ITADataSourceRealization.cpp"
"src/ITADataSourceUtils.cpp"
"src/ITAFileDataSink.cpp"
"src/ITAFileDataSource.cpp"
"src/ITAPeakDetector.cpp"
"src/ITAStreamAmplifier.cpp"
#"src/ITAStreamFilter.cpp"
"src/ITAStreamFunctionGenerator.cpp"
"src/ITAStreamModalSynthesizer.cpp"
"src/ITAStreamMultiplier1N.cpp"
"src/ITAStreamPatchBay.cpp"
"src/ITAStreamProbe.cpp"
"src/ITAStreamProperties.cpp"
"src/ITAStreamPump.cpp"
"src/ITAStreamYJunction.cpp"
)
if( VASIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_ASIO )
set( ITADataSourcesHeader "${ITADataSourcesHeader}" "include/ITAAsioInterface.h" )
set( ITADataSourcesSources "${ITADataSourcesSources}" "src/ITAAsioInterface.cpp" )
add_definitions( -DIEEE754_64FLOAT=1 )
endif( VASIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_ASIO )
if( VPORTAUDIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
set( ITADataSourcesHeader "${ITADataSourcesHeader}" "include/ITAPortaudioInterface.h" )
set( ITADataSourcesSources "${ITADataSourcesSources}" "src/ITAPortaudioInterface.cpp" )
endif( VPORTAUDIO_FOUND AND ITA_DATA_SOURCE_WITH_INTEGRATED_PORTAUDIO )
# compiler
add_definitions( -DITA_BASE_DLL -DITA_DATA_SOURCES_DLL -DITA_DATA_SOURCES_EXPORT )
# linker
add_library( ITADataSources SHARED ${ITADataSourcesHeader} ${ITADataSourcesSources} )
target_link_libraries( ITADataSources ${VISTA_USE_PACKAGE_LIBRARIES} )
# config
vista_configure_lib( ITADataSources )
vista_install( ITADataSources )
set( ITADATASOURCES_INCLUDE_OUTDIR "${CMAKE_CURRENT_SOURCE_DIR}/include" )
vista_create_cmake_configs( ITADataSources )
vista_create_default_info_file( ITADataSources )
set_property( TARGET ITADataSources PROPERTY FOLDER "ITACoreLibs" )
# tests
set( ITADATASOURCES_COMMON_BUILD TRUE )
add_subdirectory( "${CMAKE_CURRENT_SOURCE_DIR}/tests" )
This diff is collapsed.
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
// $Id: ITABufferDataSink.h 2900 2012-09-17 08:42:42Z stienen $
#ifndef INCLUDE_WATCHER_ITA_BUFFER_DATA_SINK
#define INCLUDE_WATCHER_ITA_BUFFER_DATA_SINK
#include <ITADataSourcesDefinitions.h>
#include <ITAAudiofileCommon.h>
#include <ITAStreamInfo.h>
// STL-Includes
#include <string>
#include <vector>
// Vorwrtsdeklarationen
class ITAAudiofileWriter;
class ITADatasource;
//! Audiodatei-Datensenke
/**
* Die Klasse ITAFileDatasink realisiert eine Datensenke fr Audiostreams,
* welche die Audiodaten in eine Datei schreibt. Der Datentransfer muss
* selbst initiiert werden.
*/
class ITA_DATA_SOURCES_API ITABufferDatasink {
public:
//! Konstruktor (Eigene Pufferverwaltung)
/**
* Dieser Konstruktor erzeugt eine Puffer-Datensenke. Die Puffer zum Speichern
* der Audiodaten werden bei diesem Konstruktor selbst erzeugt und von der
* Datenquelle verwaltet. Mit dem Aufruf des Destruktors werden die Puffer
* freigeben. Die Pufferzeiger knnen mit der Methode GetBuffers() abgerufen werden.
*
* \param pdsSource Datenquelle
* \param iBuffersize Puffergre [Anzahl Samples]
*
* \note Bei Fehlern werden ITAExceptions aufgelst.
*/
ITABufferDatasink(ITADatasource* pdsSource,
unsigned int uiBuffersize);
//! Konstruktor (Fremdverwaltete Puffer)
/**
* Dieser Konstruktor erzeugt eine Puffer-Datensenke, welche die angegebenen Puffer
* zum Speichern der Audiodaten verwendet und diese Puffer nicht selbst verwaltet.
*
* \param pdsSource Datenquelle
* \param vpfBuffer Puffer
* \param iBuffersize Puffergre [Anzahl Samples]
*
* \note Bei Fehlern werden ITAExceptions aufgelst.
*/
ITABufferDatasink(ITADatasource* pdsSource,
std::vector<float*> vpfBuffer,
unsigned int uiBuffersize);
//! Destruktor
virtual ~ITABufferDatasink();
//! Puffergre [Anzahl Samples] zurckgeben
unsigned int GetBuffersize() const;
//! Pufferzeiger zurckgeben
std::vector<float*> GetBuffers() const;
//! Schreibposition in den Puffern zurckgeben
unsigned int GetWriteCursor() const;
//! Schreibposition in den Puffern setzen
void SetWriteCursor(unsigned int uiWriteCursor);
//! Audiodaten transferrieren
/**
* Liest die gewnschte Anzahl Samples von der angeschlossenen Datenquelle
* und schreibt diese in die Audiodatei. Hierbei wird die Anzahl Samples
* auf das nchstgrere Vielfache der Blocklnge aufgerundet.
*/
void Transfer(unsigned int uiSamples);
private:
ITADatasource* m_pdsSource; // Datenquelle
std::vector<float*> m_vpfBuffer; // Puffervektor
std::vector<const float*> m_vpfBufferX; // Export-Puffervektor (const)
bool m_bManagedBuffer; // Werden die Puffer verwaltet?
unsigned int m_uiBuffersize; // Anzahl Samples im Puffer
unsigned int m_uiWriteCursor; // Schreibcursor auf den Puffern
ITAStreamInfo m_siState; // Streamzustand
};
#endif // INCLUDE_WATCHER_ITA_BUFFER_DATA_SINK
This diff is collapsed.
This diff is collapsed.
/*
+---------------------------------------------------------+
| |
| ITADatasourceDelegator.h |
| Abstrakte Basisklasse fr Datenquellen |
| |
| Autoren: Frank Wefers |
| |
| (c) Copyright Institut fr technische Akustik (ITA) |
| Aachen university of technology (RWTH), 2005-2008 |
| |
+---------------------------------------------------------+
*/
// $Id: ITADatasourceDelegator.h,v 1.2 2008-12-12 12:56:01 fwefers Exp $
#ifndef _ITADATASOURCEDELEGATOR_H_
#define _ITADATASOURCEDELEGATOR_H_
#include <ITADatasource.h>
/**
* Diese Klasse implementiert die Schnittstelle der ITADatasource, stellt die
* Datenquellen-Dienstleistungen aber nicht selbst bereit, sondern bezieht diese
* Dienstleistungen von einer anderen Datenquelle. Diese lose Kopplung ist per
* uses-Beziehung realisiert. Die Klasse vermeidet dem Programmierer Tippaufwand
* wenn das Bereitstellen von Datenquellen-Dienstleistungen mit konkreten
* Implementierungsklassen realisiert werden soll.
*
* Autor: Frank Wefers <Frank.Wefers@akustik.rwth-aachen.de>
*/
class ITADatasourceDelegator : public ITADatasource {
protected:
//! Geschtzer Standardkonstruktor
ITADatasourceDelegator()
: ITADatasource(), m_pDatasourceDelegatorTarget(0) {}
//! Geschtzer Standardkonstruktor
ITADatasourceDelegator(ITADatasource* pTarget) : m_pDatasourceDelegatorTarget(pTarget) {}
public:
virtual ~ITADatasourceDelegator() { }
unsigned int GetBlocklength() const {
return m_pDatasourceDelegatorTarget->GetBlocklength();
}
unsigned int GetNumberOfChannels() const {
return m_pDatasourceDelegatorTarget->GetNumberOfChannels();
}
double GetSamplerate() const {
return m_pDatasourceDelegatorTarget->GetSamplerate();
}
virtual const float* GetBlockPointer(unsigned int uiChannel, const ITAStreamInfo* pStreamInfo) {
return m_pDatasourceDelegatorTarget->GetBlockPointer(uiChannel, pStreamInfo);
}
virtual void IncrementBlockPointer() {
m_pDatasourceDelegatorTarget->IncrementBlockPointer();
}
protected:
ITADatasource* GetDatasourceDelegatorTarget() {
return m_pDatasourceDelegatorTarget;
}
void SetDatasourceDelegatorTarget(ITADatasource* pTarget) {
m_pDatasourceDelegatorTarget = pTarget;
}
private:
ITADatasource* m_pDatasourceDelegatorTarget;
};
#endif // _ITADATASOURCEDELEGATOR_H_
\ No newline at end of file
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
// $Id: ITADataSourceRealization.h 2900 2012-09-17 08:42:42Z stienen $
#ifndef INCLUDE_WATCHER_ITA_DATA_SOURCE_REALIZATION
#define INCLUDE_WATCHER_ITA_DATA_SOURCE_REALIZATION
#include <ITADataSourcesDefinitions.h>
#include <ITADataSource.h>
#include <ITAStreamProperties.h>
#include <ITAAtomicPrimitives.h>
// Vorwrtsdeklarationen
class ITADatasourceRealizationEventHandler;
//! Grndgerst fr die Implementierung von Datenquellen
/**
* Die Klasse ITADatasourceRealization ist ein Grundgerst fr die Implementierung
* von Datenquellen. Sie bietet dem Entwickler einen Einstiegspunkt eigene
* Datenquellen zu konstruieren und fat einige grundlegende Funktionalitt
* zusammen. ITADatasourceRealization realisiert die abstrakten Methoden
* der Oberklasse ITADatasource und bietet darber hinaus konkrete Methoden
* fr das Bereitstellen von Daten seitens der Datenquelle.
*
* Intern enthlt ein ITADatasourceRealization einen Puffer in dem die
* freizusetzenden Daten zwischengespeichert werden. Dieser Puffer
* kann nach beliebig dimensioniert werden (fr die Thread-Sicherheit mu er
* aber mindestens die Gre 2 haben). Die Klasse stellt Methoden bereit
* um Zeiger auf diesen Puffer abzurufen und diese zu inkrementieren (analog
* der publizierten Schnittstelle von ITADatasource). Dabei werden komplexe
* Aspekte der Thread-Sicherheit bercksichtigt und mssen nicht vom Entwickler
* selbst programmiert werden.
*
* \ingroup datasources
*/
class ITA_DATA_SOURCES_API ITADatasourceRealization : public ITADatasource {
public:
//! Konstruktor
/**
* \param uiChannels Anzahl der Kanle
* \param uiBlocklength Blocklnge (in Samples)
* \param uiCapacity Gre des internen Puffers in Anzahl Blcken
* (Optional, Standardwert: 2, Minimalwert: 2)
*
* \note Bei Fehlern werden ITAExceptions aufgelst.
*/
/*
ITADatasourceRealization(unsigned int uiChannels,
unsigned int uiBlocklength,
unsigned int uiCapacity=2);
*/
//! Konstruktor
/**
* \param uiChannels Anzahl der Kanle
* \param dSamplerate Abtastrate (in Hertz)
* \param uiBlocklength Blocklnge (in Samples)
* \param uiCapacity Gre des internen Puffers in Anzahl Blcken
* (Optional, Standardwert: 2, Minimalwert: 2)
*
* \note Bei Fehlern werden ITAExceptions aufgelst.
*/
ITADatasourceRealization(unsigned int uiChannels,
double dSamplerate,
unsigned int uiBlocklength,
unsigned int uiCapacity=2);
virtual ~ITADatasourceRealization();
//! -= Zurcksetzen =-
/**
* \important Darf nur aufgerufen werden, wenn das Streaming nicht luft!
*/
virtual void Reset();
//! Gibt zurck, ob Fehler whrend der Stream-Verarbeitung auftraten
bool HasStreamErrors() const;
//! Handler fr Stream-Event setzen
/**
* \important Darf nur aufgerufen werden, wenn das Streaming nicht luft!
*/
ITADatasourceRealizationEventHandler* GetStreamEventHandler() const;
//! Handler fr Stream-Event setzen
/**
* \important Darf nur aufgerufen werden, wenn das Streaming nicht luft!
*/
void SetStreamEventHandler(ITADatasourceRealizationEventHandler* pHandler);
// -= Realisierung der abstrakten Methoden von "ITADatasource" =-
const ITAStreamProperties* GetStreamProperties() const { return &m_oStreamProps; }
unsigned int GetBlocklength() const { return m_uiBlocklength; }
unsigned int GetNumberOfChannels() const { return m_uiChannels; }
double GetSamplerate() const { return m_dSamplerate; }
virtual const float* GetBlockPointer(unsigned int uiChannel, const ITAStreamInfo* pStreamInfo);
virtual void IncrementBlockPointer();
//! Schreibzeiger abrufen
/**
* Diese Methode gibt den Zeiger die aktuelle Schreibposition im internen Puffer zurck.
* Der Rckgabewert ist niemals NULL.
*
* \param uiChannel Index des Kanals (Wertebereich: [0, Kanle-1])
* \return Zeiger auf die aktuelle Position des internen Puffers
*/
virtual float* GetWritePointer(unsigned int uiChannel);
//! Schreibzeiger inkrementieren
/**
* Der Aufruf dieser Methode inkrementiert den internen Schreibzeiger.
* Dadurch stellt die Datenquelle die nchsten Daten bereit. Wenn Sie die
* Schreiboperationen auf den Ausgabeblcken der Datenquelle abgeschlossen
* haben, <b>mssen</b> Sie diese Methode aufrufen, um diese Daten durch die
* Datenquelle bereitzustellen.
*/
virtual void IncrementWritePointer();
//! Nachrichten-Methode
/*
* Wird aufgerufen, wenn GetBlockPointer vom Stream aufgerufen wird,
* noch bevor intern Daten verarbeitert werden (also noch vor ProcessStream)
*/
virtual void PreGetBlockPointer() {};
//! Nachrichten-Methode
/*
* Wird aufgerufen, nachdem IncrementBlockPointer vom Stream aufgerufen wurde.
*/
virtual void PostIncrementBlockPointer() {};
//! Verarbeitungsmethode
/**
* Diese Hook-Methode wird von der Klasse aufgerufen, wenn neue Stream-Daten
* produziert werden sollen. Unterklassen sollten diese Methode redefinieren,
* um die Verarbeitung von Samples zu realisieren.
*/
virtual void ProcessStream(const ITAStreamInfo* ) {};
protected:
/*
* [fwe] Der Einfachheit halber werden diese Variablen hier
* protected zugnglich gemacht. Dies erspart hufige
* Tipparbeit in Unterklassen. Bitte diese Werte aber
* nur lesend [read-only] benutzen!!
*/
double m_dSamplerate; // Abtastrate [Hz]
unsigned int m_uiChannels; // Anzahl Kanle
unsigned int m_uiBlocklength; // Streaming Puffergre [Samples]
private:
ITAStreamProperties m_oStreamProps; // Audiostream-Parameter
unsigned int m_uiBufferSize; // Puffergre
unsigned int m_uiReadCursor; // Leseposition
unsigned int m_uiWriteCursor; // Schreibposition
float* m_pfBuffer; // Puffer (Kanle interleaved!)
ITAAtomicInt m_iGBPEntrances; // Anzahl paralleler Eintritte in GBP
ITAAtomicBool m_bGBPFirst; // Erster Eintritt in GBP seit letztem IBP (=> Daten produzieren)
int m_iBufferUnderflows; // DEBUG: Zhler fr Buffer-Leerlufe
int m_iBufferOverflows; // DEBUG: Zhler fr Buffer-berlufe
int m_iGBPReentrances; // DEBUG: Zhler parallele Wiedereintritte in GBP
int m_iIBPReentrances; // DEBUG: Zhler parallele Wiedereintritte in IBP
ITADatasourceRealizationEventHandler* m_pEventHandler; // Handler fr Stream-Events
void Init(unsigned int uiChannels,
unsigned int uiBlocklength,
unsigned int uiCapacity);
};
//! Schnittstelle fr Nachrichten-Verarbeitung der Klasse ITADatasourceRealization
class ITA_DATA_SOURCES_API ITADatasourceRealizationEventHandler {
public:
virtual ~ITADatasourceRealizationEventHandler() {};
virtual void HandlePreGetBlockPointer(ITADatasourceRealization* pSender, unsigned int uiChannel);
virtual void HandlePostIncrementBlockPointer(ITADatasourceRealization* pSender);
virtual void HandleProcessStream(ITADatasourceRealization* pSender, const ITAStreamInfo* pStreamInfo);
};
#endif // INCLUDE_WATCHER_ITA_DATA_SOURCE_REALIZATION
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
// $Id: ITADataSourceUtils.h 2900 2012-09-17 08:42:42Z stienen $
#ifndef INCLUDE_WATCHER_ITA_DATA_SOURCE_UTILS
#define INCLUDE_WATCHER_ITA_DATA_SOURCE_UTILS
#include <ITADataSourcesDefinitions.h>
#include <string> // Strings der Standard Template Library (STL)
// Vorwärtsdeklarationen
class ITADatasource;
/**
* \defgroup utilfuncs Hilfsfunktionen
*/
/*@{*/
//! Daten einer Datenquelle in einen Puffer schreiben
/**
* Holt eine gewissen Anzahl Samples von einer Datenquelle und
* schreibt diese in eine Puffer.
*
* \param pSource Zeiger auf die Datenquelle
* \param ppfDest Zeiger auf das Array der Puffer (jeweils für die Kanäle)
* \param uiNumberOfSamples Anzahl der Samples
* \param dGain Verstärkungsfaktor (optional)
* \param bOnline Echtzeit-Modus verwenden? (d.h. reale Dauern zwischen den
* Datenanforderungen verwenden). Falls false, werden die
* Daten direkt hintereinander angefordert (Maximaler Datendurchsatz)
* \param bDisplayProgress Fortschritt auf der Konsole ausgeben? (Optional, Standard: Nein)
*
* \note Gibt die Datenquelle den Nullzeiger zurück, wird für
* den betreffenden Block Stille in den Puffer geschrieben
* \note Ausnahmebehandlung mittels der Klasse ITAException
*/
ITA_DATA_SOURCES_API void WriteFromDatasourceToBuffer(ITADatasource* pSource,
float** ppfDest,
unsigned int uiNumberOfSamples,
double dGain=1.0,
bool bOnline=true,
bool bDisplayProgress=false);
//! Daten einer Datenquelle in eine Datei schreiben
/**
* Holt eine gewissen Anzahl Samples von einer Datenquelle und
* schreibt diese in eine Audiodatei.
*
* \param pSource Zeiger auf die Datenquelle
* \param sFilename Dateiname der Zieldatei
* \param uiNumberOfSamples Anzahl der Samples
* \param dGain Verstärkungsfaktor (optional)
* \param bOnline Echtzeit-Modus verwenden? (d.h. reale Dauern zwischen den
* Datenanforderungen verwenden). Falls false, werden die
* Daten direkt hintereinander angefordert (Maximaler Datendurchsatz)
* \param bDisplayProgress Fortschritt auf der Konsole ausgeben? (Optional, Standard: Nein)
*
* \note Gibt die Datenquelle den Nullzeiger zurück, wird für
* den betreffenden Block Stille in die Datei geschrieben
* \note Ausnahmebehandlung mittels der Klasse ITAException
*/
ITA_DATA_SOURCES_API void WriteFromDatasourceToFile(ITADatasource* pSource,
std::string sFilename,
unsigned int uiNumberOfSamples,
double dGain=1.0,
bool bOnline=true,
bool bDisplayProgress=false);
#endif // INCLUDE_WATCHER_ITA_DATA_SOURCE_UTILS
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |
* //__/ //__/ //__/ |__|
*
* ----------------------------------------------------------------
*
*/
// $Id: ITADataSourceDefinitions.h 2900 2012-09-17 08:42:42Z stienen $
#ifndef INCLUDE_WATCHER_ITA_DATA_SOURCES_DEFINITIONS
#define INCLUDE_WATCHER_ITA_DATA_SOURCES_DEFINITIONS
#ifdef ITA_DATA_SOURCES_DLL
#ifdef ITA_DATA_SOURCES_EXPORT
#define ITA_DATA_SOURCES_API __declspec(dllexport)
#else
#define ITA_DATA_SOURCES_API __declspec(dllimport)
#endif
#else
#define ITA_DATA_SOURCES_API
#endif
#endif // INCLUDE_WATCHER_ITA_DATA_SOURCES_DEFINITIONS
/*
* ----------------------------------------------------------------
*
* ITA core libs
* (c) Copyright Institute of Technical Acoustics (ITA)
* RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
* ____ __________ _______
* // / //__ ___/ // _ |
* // / // / // /_| |
* // / // / // ___ |