view QuickSpec.h @ 1:6422640a802f

first upload
author Wen X <xue.wen@elec.qmul.ac.uk>
date Tue, 05 Oct 2010 10:45:57 +0100
parents
children
line wrap: on
line source
#ifndef QuickSpecH
#define QuickSpecH

/*
  QuickSpec.cpp - TQuickSpectrogram class

  TQuickSpectrogram implements a compute-on-request spectrogram class. Every time one frame of the
  spectrogram is read from this class, it checks if the single-frame spectrogram has been computed
  already, computes it if not, and return the pointer to the spectrum.

  Further reading: "A buffering technique for real-time spectrogram displaying.pdf"
*/


#include <cstddef>
#include <stdlib.h>
#include "xcomplex.h"
#include "windowfunctions.h"
#include "fft.h"
//---------------------------------------------------------------------------

#define QSPEC_FORMAT float  //default spectral data format
#define QSpec_BufferSize 1024 //default initial buffer size, in frames, of TQuickSpectrogram


/*
  __int24 is a 24bit signed integer type and __pint24 is its pointer type. Although __int24* will also
  return a pointer to an __int24 structure, operations based on __int24* may have unspecified results,
  depending on structure alignments imposed by compiler. It is therefore necessary to have an explicit
  pointer type __pint24 to enforce 24-bit data alighment.

  Using __int24:
  When storage format is not a concern, __int24 can be used the same way as __int16 or __int32. However,
  a default 32-bit compiler may fail to implement compact 24-bit alignment to entries of an __int24[]
  array. If 24-bit alignment is desired, then always create the array dynamically with new[], which
  returns a __pint24 type pointer. Assigning a __pint24 type pointer to __int24* type variable should
  be avoided.
*/

#ifndef INT24
#define INT24
struct __int24;
struct __pint24
{
  char* p;
  __fastcall __pint24(){}
  __fastcall __pint24(const void* ap){p=(char*)ap;}
  __pint24& __fastcall operator=(const void* ap){p=(char*)ap; return *this;}
  __int24& __fastcall operator*(){return *(__int24*)p;}
  __int24& __fastcall operator[](int index){return *(__int24*)&p[3*index];}
  __pint24 __fastcall operator++(int){__pint24 result=*this; p+=3; return result;}
  __pint24& __fastcall operator++(){p+=3; return *this;}
  __pint24 __fastcall operator--(int){__pint24 result=*this; p-=3; return result;}
  __pint24& __fastcall operator--(){p-=3; return *this;}
  __pint24& __fastcall operator+=(int a){p+=3*a; return *this;}
  __pint24& __fastcall operator-=(int a){p-=3*a; return *this;}
  __fastcall operator void*() const{return p;}
};
struct __int24
{
  __int16 loword;
  __int8 hibyte;
  __fastcall __int24(){}
  __fastcall __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
  __fastcall __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
  __int24& __fastcall operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
  __int24& __fastcall operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
  __fastcall operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;}
  __pint24 operator &(){return (__pint24)this;}
  void* operator new[](size_t count){void* result=malloc(3*count); return result;}
  void operator delete[](void* p){free(p);}
};
#endif

/*
  TQuickSpectrogram is a spectrogram class the handles the computation and storage of a spectrogram.

  Using TQuickSpectrogram:

  TQuickSpectrogram provides read-only access to the spectrogram of a given waveform. The spectrogram
  contains a sequence of windowed Fourier transforms, computed from uniformly placed frames. The 0th
  frame starts at 0 (inclusive) and finishes at Wid (exclusive). Each spectrum has Wid/2+1 entries.

  Follow these steps:
  1. create a QuickSpectrogram, specifying usex and useph, and optionally, external buffer provide G
    and its arguments Id and Parent;
  2. set Data, DataLength and BytesPerSample;
  3. set frame size and hop size Wid and Offst;
  4. if G is not specified, set window type (optional extra parameter) for computing spectra;
  5. access the spectrogram via A(fr), Spec(fr) (optional) and Ph(fr) (optional).
  Steps 2~4 do not have to follow the given order.

  Call Invalidate() to notify the object of changes of waveform content.
  Call FreeBuffers() to return the object to the initial state before step 2.
*/

typedef void (*GetBuf)(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent);
class TQuickSpectrogram
{
  int BufferCount;  //number of buffers in use
  int BufferSize;   //number of frames each additional buffer holds
  int FrCount;      //number of allocated frames

  //internal storage of spectrogram
  QSPEC_FORMAT** fPh; //phase spectrogram, optional
  QSPEC_FORMAT** fA;  //amplitude spectrogram, compulsory
  cmplx<QSPEC_FORMAT>** fSpec; //complete complex spectrogram, optional

  //internal buffers (optional) for FFT
  WindowType fwt; //type of window
  int fWid;       //size of window
  int* fhbi;      //half-size bit-inversed integer table
  double fwdp;    //additional parameter specifying window type
  double* fwin;   //internal window
  cdouble* fw;    //FFT twiddle factors
  cdouble* fx;    //FFT data buffer

  //x and ph create-time switch
  bool usex;  //set at create time if complex spectrogram is required
  bool useph; //set at create time if phase spectrogram is required

  //internal methods
  void AddBuffer();
  void AddBuffer(int AddFrCount);
  void __fastcall CalculateSpectrum(int fr);
  void SetFrCapacity(int AnFrCapacity);

public:
  //if specified, Parent is responsible to supply FFT buffers through GetFFTBuffers (optional)
  int Id;               //an identifier given at create time, used as argument for calling GetFFTBuffers()
  void* Parent;         //a pointer used as argument for calling GetFFTBuffers()
  GetBuf GetFFTBuffers; //if specified, this supplies FFT buffers

  //index and validity arrays associated with internal storage
  int Capacity; //size of $Frame[] and &Valid[], usually set to the total number of frames of the data
  int* Frame;   //indices to individual frames in internal storage
  int* Valid;   //validity tags to individual frames in internal storage

  WindowType WinType; //window type for computing spectrogram
  double WinParam;    //additional parameter specifying certain window types (Gaussian, Kaiser, etc.)

  void* Data;         //pointer to waveform audio
  int DataLength;     //length of waveform audio, in samples
  int BytesPerSample; //bytes per sample of waveform audio

  int Offst;  //frame offset
  int Wid;    //frame size, the same as window size

  __fastcall TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G);
  __fastcall ~TQuickSpectrogram();

  QSPEC_FORMAT* __fastcall A(int fr);           //accesses amplitude spectrogram at frame fr
  void FreeBuffers();                           //discards all computed frames and free memory
  int Invalidate(int From, int To);             //discards computed frames
  QSPEC_FORMAT* __fastcall Ph(int fr);          //accesses phase spectrogram at frame fr
  cmplx<QSPEC_FORMAT>* __fastcall Spec(int fr); //accesses complex spectrogram at frame fr
};
#endif