Mercurial > hg > x
comparison quickspec.cpp @ 2:fc19d45615d1
* Make all file names lower-case to avoid case ambiguity
(some includes differed in case from the filenames they were
trying to include). Also replace MinGW-specific mem.h with
string.h
author | Chris Cannam |
---|---|
date | Tue, 05 Oct 2010 11:04:40 +0100 |
parents | QuickSpec.cpp@6422640a802f |
children | 5f3c32dc6e17 |
comparison
equal
deleted
inserted
replaced
1:6422640a802f | 2:fc19d45615d1 |
---|---|
1 //--------------------------------------------------------------------------- | |
2 | |
3 #include <math.h> | |
4 #include <memory.h> | |
5 #include "quickspec.h" | |
6 | |
7 | |
8 //--------------------------------------------------------------------------- | |
9 /* | |
10 method TQuickSpectrogram::TQuickSpectrogram: | |
11 | |
12 In: AParent: pointer argument for calling G, if G is specified | |
13 AnId: integer argument for calling G, if G is specified | |
14 G: pointer to a function that supplies buffers used for FFT, 0 by default | |
15 Ausex: set if complete complex spectrogram is to be buffered and accessible | |
16 Auseph: set if phase spectrogram is to be buffered and accessible | |
17 */ | |
18 __fastcall TQuickSpectrogram::TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G) | |
19 { | |
20 memset(this, 0, sizeof(TQuickSpectrogram)); | |
21 Parent=AParent; | |
22 Id=AnId; | |
23 usex=Ausex; | |
24 useph=Auseph; | |
25 GetFFTBuffers=G; | |
26 BufferSize=QSpec_BufferSize; | |
27 fwt=wtRectangle; | |
28 Wid=1024; | |
29 Offst=512; | |
30 }//TQuickSpectrogram | |
31 | |
32 //TQuickSpectrogram::~TQuickSpectrogram | |
33 __fastcall TQuickSpectrogram::~TQuickSpectrogram() | |
34 { | |
35 FreeBuffers(); | |
36 free8(fw); | |
37 free8(fwin); | |
38 free(fhbi); | |
39 }//~TQuickSpectrogram | |
40 | |
41 //--------------------------------------------------------------------------- | |
42 /* | |
43 method TQuickSpectrogram::A: accesses amplitude spectrogram by frame | |
44 | |
45 In: fr: frame index, 0-based | |
46 | |
47 Returns pointer to amplitude spectrum of the fr'th frame, NULL if N/A | |
48 */ | |
49 QSPEC_FORMAT* __fastcall TQuickSpectrogram::A(int fr) | |
50 { | |
51 if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); | |
52 if (fr<0 || fr>=Capacity) return NULL; | |
53 if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); | |
54 return fA[Frame[fr]]; | |
55 }//A | |
56 | |
57 //--------------------------------------------------------------------------- | |
58 /* | |
59 method TQuickSpectrogram::AddBuffer: increases internal buffer by BufferSize frames. Allocated buffers | |
60 beyond Capacity frames will not be indexed or used by TQuickSpectrogram. | |
61 */ | |
62 void TQuickSpectrogram::AddBuffer() | |
63 { | |
64 int base=1, Dim=Wid/2+1; | |
65 if (usex) base+=2; | |
66 if (useph) base+=1; | |
67 QSPEC_FORMAT* newbuffer=(QSPEC_FORMAT*)malloc(sizeof(QSPEC_FORMAT)*Dim*BufferSize*base); | |
68 int fr0=BufferCount*BufferSize; | |
69 for (int i=0; i<BufferSize; i++) | |
70 { | |
71 int fr=fr0+i; | |
72 if (fr<Capacity) | |
73 { | |
74 fA[fr]=&newbuffer[i*Dim]; | |
75 int base=1; | |
76 if (usex) fSpec[fr]=(cmplx<QSPEC_FORMAT>*)&newbuffer[(BufferSize+i*2)*Dim], base+=2; | |
77 if (useph) fPh[fr]=&newbuffer[(BufferSize*base+i)*Dim]; | |
78 } | |
79 else break; | |
80 } | |
81 BufferCount++; | |
82 }//AddBuffer | |
83 | |
84 /* | |
85 method TQuickSpectrogram::AddBuffer: increase internal buffer by a multiple of BufferSize so that | |
86 it will be enough to host another AddFrCount frames. | |
87 */ | |
88 void TQuickSpectrogram::AddBuffer(int AddFrCount) | |
89 { | |
90 while (FrCount+AddFrCount>BufferSize*BufferCount) AddBuffer(); | |
91 }//AddBuffer | |
92 | |
93 //--------------------------------------------------------------------------- | |
94 /* | |
95 function IntToDouble: copy content of integer array to double array | |
96 | |
97 In: in: pointer to integer array | |
98 BytesPerSample: number of bytes each integer takes | |
99 Count: size of integer array, in integers | |
100 Out: vector out[Count]. | |
101 | |
102 No return value. | |
103 */ | |
104 void IntToDouble(double* out, void* in, int BytesPerSample, int Count) | |
105 { | |
106 if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k<Count; k++) *(out++)=*(in8++)-128.0;} | |
107 else if (BytesPerSample==2) {__int16* in16=(__int16*)in; for (int k=0; k<Count; k++) *(out++)=*(in16++);} | |
108 else {__pint24 in24=(__pint24)in; for (int k=0; k<Count; k++) *(out++)=*(in24++);} | |
109 }//IntToDouble | |
110 | |
111 /* | |
112 function CalculateSpectrum: calculate spectrum of a signal in integer format | |
113 | |
114 In: Data[Wid]: integer array hosting waveform data | |
115 BytesPerSample: number of bytes each integer in Data[] takes | |
116 win[Wid]: window function used for computing spectrum | |
117 w[Wid/2], x[Wid], hbi[Wid/2]: FFT buffers | |
118 Out: x[Wid]: complex spectrum | |
119 Amp[Wid/2+1]: amplitude spectrum | |
120 Arg[Wid/2+1]: phase spectrum, optional | |
121 | |
122 No return value. | |
123 */ | |
124 void CalculateSpectrum(void* Data, int BytesPerSample, double* win, QSPEC_FORMAT* Amp, QSPEC_FORMAT* Arg, int Wid, cdouble* w, cdouble* x, int* hbi) | |
125 { | |
126 if (BytesPerSample==2) RFFTCW((__int16*)Data, win, 0, 0, log2(Wid), w, x, hbi); | |
127 else {IntToDouble((double*)x, Data, BytesPerSample, Wid); RFFTCW((double*)x, win, 0, 0, log2(Wid), w, x, hbi);} | |
128 for (int j=0; j<=Wid/2; j++) | |
129 { | |
130 Amp[j]=sqrt(x[j].x*x[j].x+x[j].y*x[j].y); | |
131 if (Arg) Arg[j]=(x[j].y==0 && x[j].x==0)?0:atan2(x[j].y, x[j].x); | |
132 } | |
133 }//CalculateSpectrum | |
134 | |
135 /* | |
136 function CalculateSpectrum: calculate spectrum of a signal in integer format, allowing the signal | |
137 length $eff be shorter than the DFT size Wid. | |
138 | |
139 In: Data[eff]: integer array hosting waveform data | |
140 BytesPerSample: number of bytes each integer in Data[] takes | |
141 win[Wid]: window function used for computing spectrum | |
142 w[Wid/2], x[Wid], hbi[Wid/2]: FFT buffers | |
143 Out: x[Wid]: complex spectrum | |
144 Amp[Wid/2+1]: amplitude spectrum | |
145 Arg[Wid/2+1]: phase spectrum, optional | |
146 | |
147 No return value. | |
148 */ | |
149 void CalculateSpectrum(void* Data, int BytesPerSample, double* win, QSPEC_FORMAT* Amp, QSPEC_FORMAT* Arg, int Wid, int eff, cdouble* w, cdouble* x, int* hbi) | |
150 { | |
151 if (eff<=0) | |
152 { | |
153 memset(Amp, 0, sizeof(double)*(Wid/2+1)); | |
154 if (Arg) memset(Arg, 0, sizeof(double)*(Wid/2+1)); | |
155 } | |
156 else if (eff<Wid) | |
157 { | |
158 double* doublex=(double*)x; | |
159 IntToDouble(doublex, Data, BytesPerSample, eff); memset(&doublex[eff], 0, sizeof(double)*(Wid-eff)); | |
160 RFFTCW(doublex, win, 0, 0, log2(Wid), w, x, hbi); | |
161 for (int j=0; j<=Wid/2; j++) | |
162 { | |
163 Amp[j]=sqrt(x[j].x*x[j].x+x[j].y*x[j].y); | |
164 if (Arg) Arg[j]=(x[j].y==0 && x[j].x==0)?0:atan2(x[j].y, x[j].x); | |
165 } | |
166 } | |
167 else | |
168 CalculateSpectrum(Data, BytesPerSample, win, Amp, Arg, Wid, w, x, hbi); | |
169 }//CalculateSpectrum | |
170 | |
171 /* | |
172 method TQuickSpectrogram::CalculateSpectrum: computes spectrogram at fr'th frame. | |
173 | |
174 In: fr: index to the frame whose spectrum is to be computed. fr must be between 0 and Capacity-1. | |
175 */ | |
176 void __fastcall TQuickSpectrogram::CalculateSpectrum(int fr) | |
177 { | |
178 cdouble *w, *x; | |
179 double* win; | |
180 int* hbi; | |
181 | |
182 //obtain FFT buffers win (window function), w (twiddle factors), x (data buffer), | |
183 //hbi (half-size bit-inversed integer table) | |
184 if (GetFFTBuffers) //then use external buffers provided through GetFFTBuffers | |
185 GetFFTBuffers(Id, w, x, win, hbi, Parent); | |
186 else //then use internal buffers | |
187 { | |
188 if (Wid!=fWid) | |
189 { //then update internal buffers to the new window size | |
190 free8(fw); free(fhbi); | |
191 fw=(cdouble*)malloc8(sizeof(cdouble)*Wid*1.5); SetTwiddleFactors(Wid, fw); | |
192 fx=&fw[Wid/2]; | |
193 fhbi=CreateBitInvTable(log2(Wid)-1); | |
194 } | |
195 if (Wid!=fWid || WinType!=fwt || WinParam!=fwdp) | |
196 { //then update internal window function to the new window type | |
197 fwin=NewWindow8(WinType, Wid, 0, &WinParam); | |
198 fwt=WinType; fwdp=WinParam; | |
199 } | |
200 fWid=Wid; | |
201 | |
202 //pick up the internal buffers | |
203 w=fw, x=fx, win=fwin, hbi=fhbi; | |
204 } | |
205 | |
206 //obtain the index of this frame in internal storage | |
207 if (Frame[fr]<0) {AddBuffer(1); Frame[fr]=FrCount; FrCount++;} | |
208 int realfr=Frame[fr]; | |
209 | |
210 //obtain the pointer to this frame's phase spectrum | |
211 QSPEC_FORMAT *lph=useph?fPh[realfr]:NULL; | |
212 //ontain the pointer to this frame's complex spectrum | |
213 cmplx<QSPEC_FORMAT>* lX=usex?fSpec[realfr]:NULL; | |
214 //choose the buffer actually used for FFT - use lX if it is specified as complex double array | |
215 //because it saves unnecessary data copying operations | |
216 cdouble *lx=(usex && sizeof(QSPEC_FORMAT)==sizeof(double))?(cdouble*)lX:x; | |
217 | |
218 //Actual FFT | |
219 if (fr*Offst+Wid<=DataLength) | |
220 ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, w, lx, hbi); | |
221 else | |
222 ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, DataLength-fr*Offst, w, x, hbi); | |
223 | |
224 //optional data copy from x to lX | |
225 if (usex && lx==x) for (int i=0; i<Wid/2+1; i++) lX[i]=x[i]; | |
226 | |
227 //tag this frame as computed and valid | |
228 Valid[fr]=1; | |
229 }//CalculateSpectrum | |
230 | |
231 //--------------------------------------------------------------------------- | |
232 /* | |
233 method TQuickSpectrogram::FreeBuffers: discards all computed spectra and free all internal buffers. | |
234 This returns the TQuickSpectrogram to its initial state before any frame is accessed. After calling | |
235 FreeBuffers() all frames will be recomputed when they are accessed. | |
236 */ | |
237 void TQuickSpectrogram::FreeBuffers() | |
238 { | |
239 if (fA) | |
240 { | |
241 for (int i=0; i<BufferCount; i++) free(fA[i*BufferSize]); | |
242 FrCount=BufferCount=Capacity=0; | |
243 free(Frame); free(Valid); | |
244 free(fA); | |
245 Frame=Valid=0, fA=0; | |
246 if (useph) {free(fPh); fPh=0;} | |
247 if (usex) {free(fSpec); fSpec=0;} | |
248 } | |
249 }//FreeBuffers | |
250 | |
251 //--------------------------------------------------------------------------- | |
252 /* | |
253 method TQuickSpectrogram::Invalidate: renders all frames that have overlap with interval [From, To], | |
254 measured in samples, as invalid. Invalid frames are recomputed when they are accessed again. | |
255 | |
256 In: [From, To]: an interval spectrogram over which needs to be updated. | |
257 | |
258 Returns the number of allocated frames affected, no matter if they were valid. | |
259 */ | |
260 int TQuickSpectrogram::Invalidate(int From, int To) | |
261 { | |
262 int result=0; | |
263 if (Frame) | |
264 { | |
265 int fr1=ceil((From-Wid+1.0)/Offst), fr2=floor(1.0*To/Offst); | |
266 if (fr1<0) fr1=0; | |
267 if (fr2>=Capacity) fr2=Capacity-1; | |
268 for (int fr=fr1; fr<=fr2; fr++) if (Frame[fr]>=0) Valid[fr]=false, result++; | |
269 } | |
270 return result; | |
271 }//Invalidate | |
272 | |
273 //--------------------------------------------------------------------------- | |
274 /* | |
275 method TQuickSpectrogram::Ph: accesses phase spectrogram by frame | |
276 | |
277 In: fr: frame index, 0-based | |
278 | |
279 Returns pointer to phase spectrum of the fr'th frame, NULL if N/A | |
280 */ | |
281 QSPEC_FORMAT* __fastcall TQuickSpectrogram::Ph(int fr) | |
282 { | |
283 if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); | |
284 if (fr<0 || fr>=Capacity) return NULL; | |
285 if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); | |
286 return fPh[Frame[fr]]; | |
287 }//Ph | |
288 | |
289 //--------------------------------------------------------------------------- | |
290 /* | |
291 method TQuickSpectrogram::SetFrCapacity: sets the capacity, i.e. the maximal number of frames handled | |
292 by this TQuickSpectrogram. | |
293 | |
294 In: AnFrCapacity: the new Capacity, in frames | |
295 | |
296 This method should not be called to set Capacity to a smaller value. | |
297 */ | |
298 void TQuickSpectrogram::SetFrCapacity(int AnFrCapacity) | |
299 { | |
300 //adjusting the size of index and validity arrays | |
301 Frame=(int*)realloc(Frame, sizeof(int)*AnFrCapacity); | |
302 Valid=(int*)realloc(Valid, sizeof(int)*AnFrCapacity); | |
303 | |
304 // | |
305 fA=(QSPEC_FORMAT**)realloc(fA, sizeof(QSPEC_FORMAT*)*AnFrCapacity); | |
306 if (usex) fSpec=(cmplx<QSPEC_FORMAT>**)realloc(fSpec, sizeof(cmplx<QSPEC_FORMAT>*)*AnFrCapacity); | |
307 if (useph) fPh=(QSPEC_FORMAT**)realloc(fPh, sizeof(QSPEC_FORMAT*)*AnFrCapacity); | |
308 if (AnFrCapacity>Capacity) | |
309 { | |
310 memset(&Frame[Capacity], 0xFF, sizeof(int)*(AnFrCapacity-Capacity)); | |
311 memset(&Valid[Capacity], 0x00, sizeof(int)*(AnFrCapacity-Capacity)); | |
312 | |
313 if (Capacity<BufferCount*BufferSize) | |
314 { | |
315 for (int fr=Capacity; fr<AnFrCapacity; fr++) | |
316 { | |
317 int bufferno=fr/BufferSize; | |
318 if (bufferno<BufferCount) | |
319 { | |
320 QSPEC_FORMAT* thisbuffer=fA[BufferSize*bufferno]; | |
321 int lfr=fr%BufferSize, base=1, Dim=Wid/2+1; | |
322 fA[fr]=&thisbuffer[lfr*Dim]; | |
323 if (usex) fSpec[fr]=(cmplx<QSPEC_FORMAT>*)(&thisbuffer[(BufferSize+lfr*2)*Dim]), base+=2; | |
324 if (useph) fPh[fr]=&thisbuffer[(BufferSize*base+lfr)*Dim]; | |
325 } | |
326 else break; | |
327 } | |
328 } | |
329 } | |
330 Capacity=AnFrCapacity; | |
331 }//SetFrCapacity | |
332 | |
333 //--------------------------------------------------------------------------- | |
334 /* | |
335 method TQuickSpectrogram::Ph: accesses complex spectrogram by frame | |
336 | |
337 In: fr: frame index, 0-based | |
338 | |
339 Returns pointer to complex spectrum of the fr'th frame, NULL if N/A | |
340 */ | |
341 cmplx<QSPEC_FORMAT>* __fastcall TQuickSpectrogram::Spec(int fr) | |
342 { | |
343 if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); | |
344 if (fr<0 || fr>=Capacity) return NULL; | |
345 if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); | |
346 return fSpec[Frame[fr]]; | |
347 }//Spec | |
348 | |
349 |