xue@11
|
1 /*
|
xue@11
|
2 Harmonic sinusoidal modelling and tools
|
xue@11
|
3
|
xue@11
|
4 C++ code package for harmonic sinusoidal modelling and relevant signal processing.
|
xue@11
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@11
|
6 This file copyright 2011 Wen Xue.
|
xue@11
|
7
|
xue@11
|
8 This program is free software; you can redistribute it and/or
|
xue@11
|
9 modify it under the terms of the GNU General Public License as
|
xue@11
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@11
|
11 License, or (at your option) any later version.
|
xue@11
|
12 */
|
xue@1
|
13 #ifndef QuickSpecH
|
xue@1
|
14 #define QuickSpecH
|
xue@1
|
15
|
xue@1
|
16 /*
|
Chris@5
|
17 \file quickspec.h - TQuickSpectrogram class
|
xue@1
|
18
|
xue@1
|
19 TQuickSpectrogram implements a compute-on-request spectrogram class. Every time one frame of the
|
xue@1
|
20 spectrogram is read from this class, it checks if the single-frame spectrogram has been computed
|
xue@1
|
21 already, computes it if not, and return the pointer to the spectrum.
|
xue@1
|
22
|
xue@1
|
23 Further reading: "A buffering technique for real-time spectrogram displaying.pdf"
|
xue@1
|
24 */
|
xue@1
|
25
|
xue@1
|
26
|
xue@1
|
27 #include <cstddef>
|
xue@1
|
28 #include <stdlib.h>
|
xue@1
|
29 #include "xcomplex.h"
|
xue@1
|
30 #include "windowfunctions.h"
|
xue@1
|
31 #include "fft.h"
|
xue@1
|
32 //---------------------------------------------------------------------------
|
xue@1
|
33
|
xue@1
|
34 #define QSPEC_FORMAT float //default spectral data format
|
xue@1
|
35 #define QSpec_BufferSize 1024 //default initial buffer size, in frames, of TQuickSpectrogram
|
xue@1
|
36
|
xue@1
|
37
|
Chris@5
|
38 /**
|
xue@1
|
39 __int24 is a 24bit signed integer type and __pint24 is its pointer type. Although __int24* will also
|
xue@1
|
40 return a pointer to an __int24 structure, operations based on __int24* may have unspecified results,
|
xue@1
|
41 depending on structure alignments imposed by compiler. It is therefore necessary to have an explicit
|
xue@1
|
42 pointer type __pint24 to enforce 24-bit data alighment.
|
xue@1
|
43
|
xue@1
|
44 Using __int24:
|
xue@1
|
45 When storage format is not a concern, __int24 can be used the same way as __int16 or __int32. However,
|
xue@1
|
46 a default 32-bit compiler may fail to implement compact 24-bit alignment to entries of an __int24[]
|
xue@1
|
47 array. If 24-bit alignment is desired, then always create the array dynamically with new[], which
|
xue@1
|
48 returns a __pint24 type pointer. Assigning a __pint24 type pointer to __int24* type variable should
|
xue@1
|
49 be avoided.
|
xue@1
|
50 */
|
xue@1
|
51
|
xue@1
|
52 #ifndef INT24
|
xue@1
|
53 #define INT24
|
xue@1
|
54 struct __int24;
|
xue@1
|
55 struct __pint24
|
xue@1
|
56 {
|
xue@1
|
57 char* p;
|
xue@1
|
58 __fastcall __pint24(){}
|
xue@1
|
59 __fastcall __pint24(const void* ap){p=(char*)ap;}
|
xue@1
|
60 __pint24& __fastcall operator=(const void* ap){p=(char*)ap; return *this;}
|
xue@1
|
61 __int24& __fastcall operator*(){return *(__int24*)p;}
|
xue@1
|
62 __int24& __fastcall operator[](int index){return *(__int24*)&p[3*index];}
|
xue@1
|
63 __pint24 __fastcall operator++(int){__pint24 result=*this; p+=3; return result;}
|
xue@1
|
64 __pint24& __fastcall operator++(){p+=3; return *this;}
|
xue@1
|
65 __pint24 __fastcall operator--(int){__pint24 result=*this; p-=3; return result;}
|
xue@1
|
66 __pint24& __fastcall operator--(){p-=3; return *this;}
|
xue@1
|
67 __pint24& __fastcall operator+=(int a){p+=3*a; return *this;}
|
xue@1
|
68 __pint24& __fastcall operator-=(int a){p-=3*a; return *this;}
|
xue@1
|
69 __fastcall operator void*() const{return p;}
|
xue@1
|
70 };
|
xue@1
|
71 struct __int24
|
xue@1
|
72 {
|
xue@1
|
73 __int16 loword;
|
xue@1
|
74 __int8 hibyte;
|
xue@1
|
75 __fastcall __int24(){}
|
xue@1
|
76 __fastcall __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
|
xue@1
|
77 __fastcall __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
|
xue@1
|
78 __int24& __fastcall operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
|
xue@1
|
79 __int24& __fastcall operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
|
xue@1
|
80 __fastcall operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;}
|
xue@1
|
81 __pint24 operator &(){return (__pint24)this;}
|
xue@1
|
82 void* operator new[](size_t count){void* result=malloc(3*count); return result;}
|
xue@1
|
83 void operator delete[](void* p){free(p);}
|
xue@1
|
84 };
|
xue@1
|
85 #endif
|
xue@1
|
86
|
Chris@5
|
87
|
Chris@5
|
88 typedef void (*GetBuf)(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent);
|
Chris@5
|
89 /**
|
xue@1
|
90 TQuickSpectrogram is a spectrogram class the handles the computation and storage of a spectrogram.
|
xue@1
|
91
|
xue@1
|
92 Using TQuickSpectrogram:
|
xue@1
|
93
|
xue@1
|
94 TQuickSpectrogram provides read-only access to the spectrogram of a given waveform. The spectrogram
|
xue@1
|
95 contains a sequence of windowed Fourier transforms, computed from uniformly placed frames. The 0th
|
xue@1
|
96 frame starts at 0 (inclusive) and finishes at Wid (exclusive). Each spectrum has Wid/2+1 entries.
|
xue@1
|
97
|
xue@1
|
98 Follow these steps:
|
xue@1
|
99 1. create a QuickSpectrogram, specifying usex and useph, and optionally, external buffer provide G
|
xue@1
|
100 and its arguments Id and Parent;
|
xue@1
|
101 2. set Data, DataLength and BytesPerSample;
|
xue@1
|
102 3. set frame size and hop size Wid and Offst;
|
xue@1
|
103 4. if G is not specified, set window type (optional extra parameter) for computing spectra;
|
xue@1
|
104 5. access the spectrogram via A(fr), Spec(fr) (optional) and Ph(fr) (optional).
|
xue@1
|
105 Steps 2~4 do not have to follow the given order.
|
xue@1
|
106
|
xue@1
|
107 Call Invalidate() to notify the object of changes of waveform content.
|
xue@1
|
108 Call FreeBuffers() to return the object to the initial state before step 2.
|
xue@1
|
109 */
|
xue@1
|
110 class TQuickSpectrogram
|
xue@1
|
111 {
|
Chris@5
|
112 int BufferCount; ///< number of buffers in use
|
Chris@5
|
113 int BufferSize; ///< number of frames each additional buffer holds
|
Chris@5
|
114 int FrCount; ///< number of allocated frames
|
xue@1
|
115
|
xue@1
|
116 //internal storage of spectrogram
|
Chris@5
|
117 QSPEC_FORMAT** fPh; ///< phase spectrogram, optional
|
Chris@5
|
118 QSPEC_FORMAT** fA; ///< amplitude spectrogram, compulsory
|
Chris@5
|
119 cmplx<QSPEC_FORMAT>** fSpec; ///< complete complex spectrogram, optional
|
xue@1
|
120
|
xue@1
|
121 //internal buffers (optional) for FFT
|
Chris@5
|
122 WindowType fwt; ///< type of window
|
Chris@5
|
123 int fWid; ///< size of window
|
Chris@5
|
124 int* fhbi; ///< half-size bit-inversed integer table
|
Chris@5
|
125 double fwdp; ///< additional parameter specifying window type
|
Chris@5
|
126 double* fwin; ///< internal window
|
Chris@5
|
127 cdouble* fw; ///< FFT twiddle factors
|
Chris@5
|
128 cdouble* fx; ///< FFT data buffer
|
xue@1
|
129
|
xue@1
|
130 //x and ph create-time switch
|
Chris@5
|
131 bool usex; ///< set at create time if complex spectrogram is required
|
Chris@5
|
132 bool useph; ///< set at create time if phase spectrogram is required
|
xue@1
|
133
|
xue@1
|
134 //internal methods
|
xue@1
|
135 void AddBuffer();
|
xue@1
|
136 void AddBuffer(int AddFrCount);
|
xue@1
|
137 void __fastcall CalculateSpectrum(int fr);
|
xue@1
|
138
|
xue@1
|
139 public:
|
xue@1
|
140 //if specified, Parent is responsible to supply FFT buffers through GetFFTBuffers (optional)
|
Chris@5
|
141 int Id; ///< an identifier given at create time, used as argument for calling GetFFTBuffers()
|
Chris@5
|
142 void* Parent; ///< a pointer used as argument for calling GetFFTBuffers()
|
Chris@5
|
143 GetBuf GetFFTBuffers; ///< if specified, this supplies FFT buffers
|
xue@1
|
144
|
xue@1
|
145 //index and validity arrays associated with internal storage
|
Chris@5
|
146 int Capacity; ///< size of $Frame[] and &Valid[], usually set to the total number of frames of the data
|
Chris@5
|
147 int* Frame; ///< indices to individual frames in internal storage
|
Chris@5
|
148 int* Valid; ///< validity tags to individual frames in internal storage
|
xue@1
|
149
|
Chris@5
|
150 WindowType WinType; ///< window type for computing spectrogram
|
Chris@5
|
151 double WinParam; ///< additional parameter specifying certain window types (Gaussian, Kaiser, etc.)
|
xue@1
|
152
|
Chris@5
|
153 void* Data; ///< pointer to waveform audio
|
Chris@5
|
154 int DataLength; ///< length of waveform audio, in samples
|
Chris@5
|
155 int BytesPerSample; ///< bytes per sample of waveform audio
|
xue@1
|
156
|
Chris@5
|
157 int Offst; ///< frame offset
|
Chris@5
|
158 int Wid; ///< frame size, the same as window size
|
xue@1
|
159
|
xue@1
|
160 __fastcall TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G);
|
xue@1
|
161 __fastcall ~TQuickSpectrogram();
|
xue@1
|
162
|
Chris@5
|
163 QSPEC_FORMAT* __fastcall A(int fr); ///< accesses amplitude spectrogram at frame fr
|
Chris@5
|
164 void FreeBuffers(); ///< discards all computed frames and free memory
|
Chris@5
|
165 int Invalidate(int From, int To); ///< discards computed frames
|
Chris@5
|
166 QSPEC_FORMAT* __fastcall Ph(int fr); ///< accesses phase spectrogram at frame fr
|
xue@11
|
167 void SetFrCapacity(int AnFrCapacity);
|
Chris@5
|
168 cmplx<QSPEC_FORMAT>* __fastcall Spec(int fr); ///< accesses complex spectrogram at frame fr
|
xue@1
|
169 };
|
xue@1
|
170 #endif
|