ITASampleFrame.h 11.9 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1 2 3 4 5
/*
* ----------------------------------------------------------------
*
*		ITA core libs
*		(c) Copyright Institute of Technical Acoustics (ITA)
6
*		RWTH Aachen University, Germany, 2015-2017
Jonas Stienen's avatar
Jonas Stienen committed
7 8 9 10 11 12 13 14 15 16 17 18
*
* ----------------------------------------------------------------
*				    ____  __________  _______
*				   //  / //__   ___/ //  _   |
*				  //  /    //  /    //  /_|  |
*				 //  /    //  /    //  ___   |
*				//__/    //__/    //__/   |__|
*
* ----------------------------------------------------------------
*
*/

19 20
#ifndef INCLUDE_WATCHER_ITA_SAMPLE_FRAME
#define INCLUDE_WATCHER_ITA_SAMPLE_FRAME
Jonas Stienen's avatar
Jonas Stienen committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

// ITABase
#include <ITABaseDefinitions.h>
#include <ITASampleBuffer.h>

// STL
#include <vector>

/**
 * Ein SampleFrame in eine Menge von SamplePuffern
 */

class ITA_BASE_API ITASampleFrame
{
public:
	//! Standardkonstruktor
	/**
	 * Dieser Konstruktor erzeugt einen leeren Frame, ohne Kanle und der Lnge 0.
	 */
	ITASampleFrame();

	//! Konstruktor
	/**
	 * Erzeugt einen Frame der gewnschten Anzahl Kanle und Lnge, ohne Abtastrate.
	 * Standardmig werden Samples mit Nullen initialisiert.
	 * Fr manche Anwendungen ist im Sinne maximaler Geschwindigkeit
	 * sinnvoll diese Initialisierung auszulassen. Die Samples des Frame
	 * enthalten dann allerdings unbestimmte (mehr oder weniger zufllige) Werte.
	 *
	 * \param iChannels	Anzahl Kanle
	 * \param iLength	Lnge [Anzahl Samples]
	 * \param bZeroinit	Frame mit Nullen initialisieren?
	 */

	explicit ITASampleFrame(int iChannels, int iLength, bool bZeroinit);
	
	//! Kopierkonstruktor (Zeiger)
	/**
	 * Erzeugt einen unabhngigen Frame als Kopie des gegebenen Frames. 
	 * Der neue Frame hat die selbe Anzahl Kanle und Lnge und enthlt
	 * die gleichen Werte wie der Quellframe.
	 *
	 * \param pSource Zeiger auf den Quellframe
	 */
	ITASampleFrame(const ITASampleFrame* pSource);

	//! Kopierkonstruktor (Referenz)
	/**
	 * Erzeugt einen unabhngigen Frame als Kopie des gegebenen Frames. 
	 * Der neue Frame hat die selbe Anzahl Kanle und Lnge und enthlt
	 * die gleichen Werte wie der Quellframe.
	 *
	 * \param bSource Referenz auf den Quellframe
	 */
	ITASampleFrame(const ITASampleFrame& fSource);

	//! Ladekonstruktor (Audiodatei)
	/**
	 * Dieser Konstruktor erzeugt einen Frame indem er ihn aus einer Audiodatei ldt.
	 *
	 * \note Im Fehlerfall wird eine ITAException ausgelst.
	 */
	ITASampleFrame(const std::string& sFilename);

	//! Destruktor
	virtual ~ITASampleFrame();

	//! Ist der Frame leer?
	/**
	 * Ein Frame ist leer wenn er die Lnge 0 und/oder keine Kanle hat
	 */
	bool empty() const;

	//! Anzahl Kanle zurckgeben
	int channels() const;

	// Deprecated
	int length() const;

	//! Lnge [Anzahl Samples] zurckgeben
	int GetLength() const { return length(); };

	//! Frame initialisieren
	/**
	 * Mit dieser Methode wird ein Frame initialisiert. Dies bedeutet das seine
	 * Anzahl Kanle und Lnge festgelegt wird und der Speicher alloziert wird.
	 * Falls ein Frame bereits initialisiert war, gehen alle vorherigen Daten verloren.
	 * Die Methode ermglich bequemes programmieren, da Frames zunchst per
	 * Standard-Konstruktor erzeugt werden knnen und erst spter initialisiert werden.
     *
	 * \param dSamplerate  Abtastrate [Hz] (0 => unbestimmt)
	 * \param iChannels	Anzahl Kanle
     * \param iLength	Lnge [Anzahl Samples]
	 * \param bZeroinit	Samples mit Nullen initialisieren?
	 */
116
	void Init( int iChannels, int iLength, bool bZeroinit );
Jonas Stienen's avatar
Jonas Stienen committed
117 118

	//! Legacy Init with small caps style
119 120 121
	inline void init( int iChannels, int iLength, bool bZeroinit )
	{
		return Init( iChannels, iLength, bZeroinit );
Jonas Stienen's avatar
Jonas Stienen committed
122
	};
Jonas Stienen's avatar
Jonas Stienen committed
123

124 125 126
	void Load( const std::string& sFilePath );
	void Load( const std::string& sFilePath, double& dSampleRate );
	void Store( const std::string& sFilePath, double dSampleRate = 44100.0f ) const;
Jonas Stienen's avatar
Jonas Stienen committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

	//! Speicher freigeben
	/**
	 * Gibt den fr den Frame allozierten Speicher frei und setzt seine 
	 * Anzahl Kanle und Lnge auf 0. Hierbei gehen natrlich alle Daten verloren.
	 */
	void free();
	
	//! Setzt alle Samples alles Kanle auf den gegebenen Wert
	void fill(float fValue);

	//! Setzt die Samples aller Kanle in einem Bereich auf den angegebenen Wert
	/**
	 * \param iOffset Startindex
	 * \param iCount  Anzahl Samples
	 * \param fFloat  Wert
	 */
	void fill(int iOffset, int iCount, float fValue);

	//! Setzt alle Samples aller Kanle zu Null
	void zero();

	//! Setzt einen Bereich von Samples aller Kanle zu Null
150
	void zero(int iOffset, int iCount);
Jonas Stienen's avatar
Jonas Stienen committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 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 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

	//! Setzt Einheitsimpulse in jedem Kanal
	void identity();

	//! Ein-/Ausblenden
	/**
	 * Blendet die Samples im Bereich [iOffset, iOffset+iCount] mit der
	 * angegebenen Blendfunktion ein.
	 */
	void fade(int iOffset, int iCount, int iFadeDirection, int iFadeFunction);

	//! Kreuzblenden
	/**
	 * Fhrt eine Kreuzblende von angebenen Frame in diesen Frame durch.
	 *
	 * Fr den Modus CROSSFADE_FROM gilt:
	 *
	 * Zunchst werden iOffset Samples vom angebenen Puffer kopiert.
	 * Danach werden iCount Samples zwischen den beiden Puffern kreuzgeblendet.
	 * Dahinter folgen nur noch Samples dieses Puffers.
	 */
	void crossfade(const ITASampleFrame* psfSrc, int iOffset, int iCount, int iFadeDirection, int iFadeFunction);
	void crossfade(const ITASampleFrame& sfSrc, int iOffset, int iCount, int iFadeDirection, int iFadeFunction);

	//! Einhllende
	/**
	/* Wendet eine lineare Einhllende (envelope) auf den Frame an.
	 *
	 * \param fGain0	Startwert [0..1]
	 * \param fGain1	Endwert [0..1]
	 */
	void envelope(float fGain0, float fGain1);

	//! Samples aus einem anderen Frame in den Frame kopieren
	/**
	 * Kopiert iCount Samples aus angegebenen Frame beginnend bei Leseposition iSrcOffset
	* in disen Frame, dort beginnend ab Schreibposition iDestOffset.
	 *
	 * \param psfSrc		Quellframe
	 * \param iCount		Anzahl zu kopierender Samples
	 * \param iSrcOffset	Leseposition im Quellframe
	 * \param iDestOffset	Schreibposition in diesem Frame
	 *
	 * \note Kein Schreiben ber das Frameende hinaus!
	 * \note Beide Frames mssen die gleiche Anzahl Kanle haben
	 */
	void write(const ITASampleFrame* psfSrc, int iCount, int iSrcOffset=0, int iDestOffset=0);	
	void write(const ITASampleFrame& sfSrc, int iCount, int iSrcOffset=0, int iDestOffset=0);	

	//! Zyklisches Schreiben
	/**
	 * Diese Methode erlaubt das zylische Schreiben von Samples in den Frame.
	 * Wenn die Leseanforderung das Ende der Frames berschreitet wird das
	 * Lesen einfach am Anfang des Frames fortgesetzt. Ntzlich ist diese
	 * Funktionalitt vorallem fr das Implementieren von Ringpuffern.
	 * Semantik ansonsten wie read().
	 *
	 * \param psfSrc		Quellframe
	 * \param iCount		Anzahl zu kopierender Samples
	 * \param iSrcOffset	Leseposition im Quellframe
	 * \param iDestOffset	Schreibposition in diesem Frame
	 *
	 * \note Beide Frames mssen die gleiche Anzahl Kanle haben
	 *
	 * TODO: Memory alignment fr SSE?
	 */
	void cyclic_write(const ITASampleFrame* psfSrc, int iCount, int iSrcOffset=0, int iDestOffset=0);
	void cyclic_write(const ITASampleFrame& sfSrc, int iCount, int iSrcOffset=0, int iDestOffset=0);

	//! Cyclic shifting of samples
	/**
	* @param [in] iCount Shifts the samples in frames by given count
	*/
	void CyclicShift(int iCount);

	//! In-place Addition: Jedem Sample einen konstanten Wert addieren
	void add_scalar(float fValue);

	//! In-place Subtraktion: Jedem Sample einen konstanten Wert subtrahieren
	void sub_scalar(float fValue);

	//! In-place Multiplikation: Jedes Sample mit einem konstanten Wert multiplizieren
	void mul_scalar(float fValue);

	//! In-place Division: Jedes Sample durch einen konstanten Wert dividieren
	void div_scalar(float fValue);

	// TODO: Bereiche Addieren usw.

	// Operatoren: Alle Kanle mit einem SampleBuffer
	void add_buf(const ITASampleBuffer* psbSource);
	void sub_buf(const ITASampleBuffer* psbSource);
	void mul_buf(const ITASampleBuffer* psbSource);
	void div_buf(const ITASampleBuffer* psbSource);

	// Varianten mit Referenzen
	void add_buf(const ITASampleBuffer& sbSource);
	void sub_buf(const ITASampleBuffer& sbSource);
	void mul_buf(const ITASampleBuffer& sbSource);
	void div_buf(const ITASampleBuffer& sbSource);

	//! Paarweise alle Samples des gegebenen Blockes zu den Samples diesem addieren
	/*
	 * - Mssen gleiche Anzahl Kanle und Lngen haben!
	 */
	void add_frame(const ITASampleFrame* psfSource);
	void sub_frame(const ITASampleFrame* psfSource);
	void mul_frame(const ITASampleFrame* psfSource);
	void div_frame(const ITASampleFrame* psfSource);

	// Varianten mit Referenzen
	void add_frame(const ITASampleFrame& sfSource);
	void sub_frame(const ITASampleFrame& sfSource);
	void mul_frame(const ITASampleFrame& sfSource);
	void div_frame(const ITASampleFrame& sfSource);

	// mit bergabe der Position - keine identische Lnge bentigt
	void add_frame(const ITASampleFrame* psfSource, int iPos);

	// Kombinierte Operatoren
	
	// Werte eines anderen Frames mit einer Konstante multiplizieren und dann hierauf addieren
	// Semantik: 
	// for i from 0 to iCount-1 do
	//   this[dest_offset + i] += (scalar * source[src_offset + i])
	//
	// iSrcOffset = Leseposition im Quellpuffer
	// iDestOffset = Schreibposition in diesem Puffer
	// iCount = Anzahl Samples
	void muladd_frame(const ITASampleFrame* psfSource, float fScalar, int iSrcOffset, int iDestOffset, int iCount);
	void muladd_frame(const ITASampleFrame& sfSource, float fScalar, int iSrcOffset, int iDestOffset, int iCount);


	//! Spitzenwert suchen
	/**
	 * Sucht den betragsgrten Wert unter allen Samples im Frame und gibt dessen Betragswert zurck.
	 * Auf Wunsch wird auch der Kanal und Index der ersten Samples zurckgegeben, das diesen
	 * Spitzenwert erreichte (erste Fundstelle).
	 */
	float findPeak(int* piChannel=NULL, int* piPeakIndex=NULL);

	//! Negieren (Multiplikation mit -1 bzw. Phasendrehungum 180)
	void negate();

	//! Normalize
	/*
	 * Normalizes all data with regard to the overall maximum peak, i.e. all buffers are
	 * devided by the same value.
	 *
	 * \return Overall peak value that has been used for normalization (can be negative)
	 */
302 303 304 305 306
	float Normalize();
	inline float normalize()
	{
		return Normalize();
	};
Jonas Stienen's avatar
Jonas Stienen committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

	//! Read/Write Indizierungsoperator fr Zugriff auf Kanaldaten
	ITASampleBuffer& operator[](int iChannel);

	//! Read-only Indizierungsoperator
	const ITASampleBuffer& operator[](int iChannel) const;

	//! Zuweisungsoperator
	/**
	 * Dieser Operator weist dem Puffer alle Samples eines anderen Quellpuffers zu.
	 * Hierzu wird zunchst die Lnge des Puffer der des Quellpuffers angepasst.
	 * Anschlieend werden alle Samples kopiert.
	 */
	ITASampleFrame& operator=(const ITASampleFrame& rhs);

	//! Arithemtische Operatoren (Aliase fr arithmetische Methoden - siehe oben)
	ITASampleFrame& operator+=(const float rhs);
	ITASampleFrame& operator-=(const float rhs);
	ITASampleFrame& operator*=(const float rhs);
	ITASampleFrame& operator/=(const float rhs);
	ITASampleFrame& operator+=(const ITASampleBuffer& rhs);
	ITASampleFrame& operator-=(const ITASampleBuffer& rhs);
	ITASampleFrame& operator*=(const ITASampleBuffer& rhs);
	ITASampleFrame& operator/=(const ITASampleBuffer& rhs);
	ITASampleFrame& operator+=(const ITASampleFrame& rhs);
	ITASampleFrame& operator-=(const ITASampleFrame& rhs);
	ITASampleFrame& operator*=(const ITASampleFrame& rhs);
	ITASampleFrame& operator/=(const ITASampleFrame& rhs);

	//! Informationen ber den Puffer als Zeichenkette zurckgeben
	std::string toString() const;

	//! berblendfunktionen
	enum {
		LINEAR = 0,			//!< Lineare berblendung aka. Rampe
		COSINE_SQUARE = 1	//!< Cosinus-Quadrat berblendung (aka Hanning-Fenster)
	};

	//! berblendrichtungen
	enum {
		FADE_IN = 0,	//!< Einblenden
		FADE_OUT = 1	//!< Ausblenden
	};

	enum {
		CROSSFADE_TO_SOURCE = 0,	//!< Kreuzblende hin zum Quellsignal
		CROSSFADE_FROM_SOURCE = 1	//!< Kreuzblende weg vom Quellsignal
	};

private:
	int m_iChannels;
	int m_iLength;
	std::vector<ITASampleBuffer> m_vChannels;

	// Alias fr Iteratoren auf den Kanlen (weniger Schreibarbeit ;-)
	typedef std::vector<ITASampleBuffer>::iterator ch_it;
};

365
#endif // INCLUDE_WATCHER_ITA_SAMPLE_FRAME