xue@11: /* xue@11: Harmonic sinusoidal modelling and tools xue@11: xue@11: C++ code package for harmonic sinusoidal modelling and relevant signal processing. xue@11: Centre for Digital Music, Queen Mary, University of London. xue@11: This file copyright 2011 Wen Xue. xue@11: xue@11: This program is free software; you can redistribute it and/or xue@11: modify it under the terms of the GNU General Public License as xue@11: published by the Free Software Foundation; either version 2 of the xue@11: License, or (at your option) any later version. xue@11: */ xue@1: #ifndef QuickSpecH xue@1: #define QuickSpecH xue@1: xue@1: /* Chris@5: \file quickspec.h - TQuickSpectrogram class xue@1: xue@1: TQuickSpectrogram implements a compute-on-request spectrogram class. Every time one frame of the xue@1: spectrogram is read from this class, it checks if the single-frame spectrogram has been computed xue@1: already, computes it if not, and return the pointer to the spectrum. xue@1: xue@1: Further reading: "A buffering technique for real-time spectrogram displaying.pdf" xue@1: */ xue@1: xue@1: xue@1: #include xue@1: #include xue@1: #include "xcomplex.h" xue@1: #include "windowfunctions.h" xue@1: #include "fft.h" xue@1: //--------------------------------------------------------------------------- xue@1: xue@1: #define QSPEC_FORMAT float //default spectral data format xue@1: #define QSpec_BufferSize 1024 //default initial buffer size, in frames, of TQuickSpectrogram xue@1: xue@1: Chris@5: /** xue@1: __int24 is a 24bit signed integer type and __pint24 is its pointer type. Although __int24* will also xue@1: return a pointer to an __int24 structure, operations based on __int24* may have unspecified results, xue@1: depending on structure alignments imposed by compiler. It is therefore necessary to have an explicit xue@1: pointer type __pint24 to enforce 24-bit data alighment. xue@1: xue@1: Using __int24: xue@1: When storage format is not a concern, __int24 can be used the same way as __int16 or __int32. However, xue@1: a default 32-bit compiler may fail to implement compact 24-bit alignment to entries of an __int24[] xue@1: array. If 24-bit alignment is desired, then always create the array dynamically with new[], which xue@1: returns a __pint24 type pointer. Assigning a __pint24 type pointer to __int24* type variable should xue@1: be avoided. xue@1: */ xue@1: xue@1: #ifndef INT24 xue@1: #define INT24 xue@1: struct __int24; xue@1: struct __pint24 xue@1: { xue@1: char* p; xue@1: __fastcall __pint24(){} xue@1: __fastcall __pint24(const void* ap){p=(char*)ap;} xue@1: __pint24& __fastcall operator=(const void* ap){p=(char*)ap; return *this;} xue@1: __int24& __fastcall operator*(){return *(__int24*)p;} xue@1: __int24& __fastcall operator[](int index){return *(__int24*)&p[3*index];} xue@1: __pint24 __fastcall operator++(int){__pint24 result=*this; p+=3; return result;} xue@1: __pint24& __fastcall operator++(){p+=3; return *this;} xue@1: __pint24 __fastcall operator--(int){__pint24 result=*this; p-=3; return result;} xue@1: __pint24& __fastcall operator--(){p-=3; return *this;} xue@1: __pint24& __fastcall operator+=(int a){p+=3*a; return *this;} xue@1: __pint24& __fastcall operator-=(int a){p-=3*a; return *this;} xue@1: __fastcall operator void*() const{return p;} xue@1: }; xue@1: struct __int24 xue@1: { xue@1: __int16 loword; xue@1: __int8 hibyte; xue@1: __fastcall __int24(){} xue@1: __fastcall __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} xue@1: __fastcall __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} xue@1: __int24& __fastcall operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} xue@1: __int24& __fastcall operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} xue@1: __fastcall operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;} xue@1: __pint24 operator &(){return (__pint24)this;} xue@1: void* operator new[](size_t count){void* result=malloc(3*count); return result;} xue@1: void operator delete[](void* p){free(p);} xue@1: }; xue@1: #endif xue@1: Chris@5: Chris@5: typedef void (*GetBuf)(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent); Chris@5: /** xue@1: TQuickSpectrogram is a spectrogram class the handles the computation and storage of a spectrogram. xue@1: xue@1: Using TQuickSpectrogram: xue@1: xue@1: TQuickSpectrogram provides read-only access to the spectrogram of a given waveform. The spectrogram xue@1: contains a sequence of windowed Fourier transforms, computed from uniformly placed frames. The 0th xue@1: frame starts at 0 (inclusive) and finishes at Wid (exclusive). Each spectrum has Wid/2+1 entries. xue@1: xue@1: Follow these steps: xue@1: 1. create a QuickSpectrogram, specifying usex and useph, and optionally, external buffer provide G xue@1: and its arguments Id and Parent; xue@1: 2. set Data, DataLength and BytesPerSample; xue@1: 3. set frame size and hop size Wid and Offst; xue@1: 4. if G is not specified, set window type (optional extra parameter) for computing spectra; xue@1: 5. access the spectrogram via A(fr), Spec(fr) (optional) and Ph(fr) (optional). xue@1: Steps 2~4 do not have to follow the given order. xue@1: xue@1: Call Invalidate() to notify the object of changes of waveform content. xue@1: Call FreeBuffers() to return the object to the initial state before step 2. xue@1: */ xue@1: class TQuickSpectrogram xue@1: { Chris@5: int BufferCount; ///< number of buffers in use Chris@5: int BufferSize; ///< number of frames each additional buffer holds Chris@5: int FrCount; ///< number of allocated frames xue@1: xue@1: //internal storage of spectrogram Chris@5: QSPEC_FORMAT** fPh; ///< phase spectrogram, optional Chris@5: QSPEC_FORMAT** fA; ///< amplitude spectrogram, compulsory Chris@5: cmplx** fSpec; ///< complete complex spectrogram, optional xue@1: xue@1: //internal buffers (optional) for FFT Chris@5: WindowType fwt; ///< type of window Chris@5: int fWid; ///< size of window Chris@5: int* fhbi; ///< half-size bit-inversed integer table Chris@5: double fwdp; ///< additional parameter specifying window type Chris@5: double* fwin; ///< internal window Chris@5: cdouble* fw; ///< FFT twiddle factors Chris@5: cdouble* fx; ///< FFT data buffer xue@1: xue@1: //x and ph create-time switch Chris@5: bool usex; ///< set at create time if complex spectrogram is required Chris@5: bool useph; ///< set at create time if phase spectrogram is required xue@1: xue@1: //internal methods xue@1: void AddBuffer(); xue@1: void AddBuffer(int AddFrCount); xue@1: void __fastcall CalculateSpectrum(int fr); xue@1: xue@1: public: xue@1: //if specified, Parent is responsible to supply FFT buffers through GetFFTBuffers (optional) Chris@5: int Id; ///< an identifier given at create time, used as argument for calling GetFFTBuffers() Chris@5: void* Parent; ///< a pointer used as argument for calling GetFFTBuffers() Chris@5: GetBuf GetFFTBuffers; ///< if specified, this supplies FFT buffers xue@1: xue@1: //index and validity arrays associated with internal storage Chris@5: int Capacity; ///< size of $Frame[] and &Valid[], usually set to the total number of frames of the data Chris@5: int* Frame; ///< indices to individual frames in internal storage Chris@5: int* Valid; ///< validity tags to individual frames in internal storage xue@1: Chris@5: WindowType WinType; ///< window type for computing spectrogram Chris@5: double WinParam; ///< additional parameter specifying certain window types (Gaussian, Kaiser, etc.) xue@1: Chris@5: void* Data; ///< pointer to waveform audio Chris@5: int DataLength; ///< length of waveform audio, in samples Chris@5: int BytesPerSample; ///< bytes per sample of waveform audio xue@1: Chris@5: int Offst; ///< frame offset Chris@5: int Wid; ///< frame size, the same as window size xue@1: xue@1: __fastcall TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G); xue@1: __fastcall ~TQuickSpectrogram(); xue@1: Chris@5: QSPEC_FORMAT* __fastcall A(int fr); ///< accesses amplitude spectrogram at frame fr Chris@5: void FreeBuffers(); ///< discards all computed frames and free memory Chris@5: int Invalidate(int From, int To); ///< discards computed frames Chris@5: QSPEC_FORMAT* __fastcall Ph(int fr); ///< accesses phase spectrogram at frame fr xue@11: void SetFrCapacity(int AnFrCapacity); Chris@5: cmplx* __fastcall Spec(int fr); ///< accesses complex spectrogram at frame fr xue@1: }; xue@1: #endif