xue@0
|
1 /*
|
xue@0
|
2 Harmonic Visualiser
|
xue@0
|
3
|
xue@0
|
4 An audio file viewer and editor.
|
xue@0
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@0
|
6 This file copyright 2011 Wen Xue.
|
xue@0
|
7
|
xue@0
|
8 This program is free software; you can redistribute it and/or
|
xue@0
|
9 modify it under the terms of the GNU General Public License as
|
xue@0
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@0
|
11 License, or (at your option) any later version.
|
xue@0
|
12 */
|
xue@0
|
13 //---------------------------------------------------------------------------
|
xue@0
|
14 #include <vcl.h>
|
xue@0
|
15 #include <values.h>
|
xue@0
|
16 #pragma hdrstop
|
xue@0
|
17
|
xue@0
|
18 #include "WaveView.h"
|
xue@0
|
19 #include <math.h>
|
xue@0
|
20 #include <math.hpp>
|
xue@0
|
21 #pragma package(smart_init)
|
xue@0
|
22 #define HEIGHT (Height)
|
xue@0
|
23 #define WIDTH (Width)
|
xue@0
|
24 #define FATP FromAmplitudeToPixel
|
xue@0
|
25 #define FPTA FromPixelToAmplitude
|
xue@0
|
26 #define FDFTP FromDigiFreqToPixel
|
xue@0
|
27 #define FPTDF FromPixelToDigiFreq
|
xue@0
|
28 #define FPTS FromPixelToSample
|
xue@0
|
29 #define FSTP FromSampleToPixel
|
xue@0
|
30
|
xue@0
|
31 //---------------------------------------------------------------------------
|
xue@0
|
32 //---------------------------------------------------------------------------
|
xue@0
|
33
|
xue@0
|
34 void DoubleToInt(void* out, int BytesPerSample, double* in, int Count)
|
xue@0
|
35 {
|
xue@0
|
36 if (BytesPerSample==1){unsigned char* out8=(unsigned char*)out; for (int k=0; k<Count; k++) *(out8++)=floor(*(in++)+128.5);}
|
xue@0
|
37 else if (BytesPerSample==2) {__int16* out16=(__int16*)out; for (int k=0; k<Count; k++) *(out16++)=floor(*(in++)+0.5);}
|
xue@0
|
38 else {__pint24 out24=(__pint24)out; for (int k=0; k<Count; k++) *(out24++)=floor(*(in++)+0.5);}
|
xue@0
|
39 }
|
xue@0
|
40
|
xue@0
|
41 //convert int array to double. truncate int24 to int16.
|
xue@0
|
42 void IntToDouble2416(double* out, void* in, int BytesPerSample, int Count)
|
xue@0
|
43 {
|
xue@0
|
44 if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k<Count; k++) *(out++)=*(in8++)-128.0;}
|
xue@0
|
45 else if (BytesPerSample==2) {__int16* in16=(__int16*)in; for (int k=0; k<Count; k++) *(out++)=*(in16++);}
|
xue@0
|
46 else {__pint24 in24=(__pint24)in; for (int k=0; k<Count; k++) *(out++)=*(in24++)>>8;}
|
xue@0
|
47 }
|
xue@0
|
48
|
xue@0
|
49 //dest-=src*amp
|
xue@0
|
50 void MultiSub(void* dest, void* src, int BytesPerSample, double* amp, int Count)
|
xue@0
|
51 {
|
xue@0
|
52 if (BytesPerSample==1){unsigned char *dest8=(unsigned char*)dest, *src8=(unsigned char*)src; for (int k=0; k<Count; k++) *(dest8++)-=(*(src8++)-128.0)**(amp++);}
|
xue@0
|
53 else if (BytesPerSample==2) {__int16 *dest16=(__int16*)dest, *src16=(__int16*)src; for (int k=0; k<Count; k++) *(dest16++)-=(*(src16++)**(amp++));}
|
xue@0
|
54 else {__pint24 dest24=(__pint24)dest, src24=(__pint24)src; for (int k=0; k<Count; k++) *(dest24++)-=(*(src24++)**(amp++));}
|
xue@0
|
55 }
|
xue@0
|
56
|
xue@0
|
57 void AddDoubleToInt1624(void* dest, int BytesPerSample, double* src, int Count, double a)
|
xue@0
|
58 {
|
xue@0
|
59 if (BytesPerSample==1){unsigned char* dest8=(unsigned char*)dest; for (int k=0; k<Count; k++) *(dest8++)+=*(src++)*a;}
|
xue@0
|
60 else if (BytesPerSample==2) {__int16* dest16=(__int16*)dest; for (int k=0; k<Count; k++) *(dest16++)+=*(src++)*a;}
|
xue@0
|
61 else {a*=256; __pint24 dest24=(__pint24)dest; for (int k=0; k<Count; k++) *(dest24++)+=*(src++)*a;}
|
xue@0
|
62 }
|
xue@0
|
63
|
xue@0
|
64 void PlayNote(double f, bool semitone=true)
|
xue@0
|
65 {
|
xue@0
|
66 if (f<=0) return;
|
xue@0
|
67 TWaveAudio* WV=new TWaveAudio(NULL); int Sps=WV->SamplesPerSec;
|
xue@0
|
68 double Sps25=Sps/4.0; __int16 data[48000]; int amp=2048, har=3;
|
xue@0
|
69 if (semitone) f=440*pow(2.0l, floor(Log2(f/440)*12+0.5)/12.0);
|
xue@0
|
70 if (f<200) har=600/f, amp*=pow(200/f, 0.7);
|
xue@0
|
71 for (int i=0; i<Sps; i++){double fdata=0; for (int j=1; j<=har; j++){if (j*f<Sps/2) fdata+=sin(2*M_PI*i*j*f/Sps)/j/j;} data[i]=amp*fdata*exp(-i/Sps25);}
|
xue@0
|
72 WV->WriteSamples(data, Sps);
|
xue@0
|
73 AnsiString FileName=ExtractFilePath(Application->ExeName)+"temp0";
|
xue@0
|
74 WV->SaveToFile(FileName); delete WV;
|
xue@0
|
75 PlaySound(FileName.c_str(), 0, SND_FILENAME|SND_ASYNC);
|
xue@0
|
76 }
|
xue@0
|
77
|
xue@0
|
78 AnsiString SemitoneToPitch(double f)
|
xue@0
|
79 {
|
xue@0
|
80 static char* notename[]={"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
|
xue@0
|
81 int fd=floor(f+0.5);
|
xue@0
|
82 double fr=f-fd;
|
xue@0
|
83 int oct=floor(fd/12.0);
|
xue@0
|
84 int note=fd-oct*12;
|
xue@0
|
85 int fr2=floor(fr*100+0.5);
|
xue@0
|
86 if (fr2==0) return AnsiString().sprintf("%s%d", notename[note], oct+4, fr2);
|
xue@0
|
87 else if (fr2>0)
|
xue@0
|
88 {
|
xue@0
|
89 if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d+.%d", notename[note], oct+4, fr2);}
|
xue@0
|
90 else return AnsiString().sprintf("%s%d+.%02d", notename[note], oct+4, fr2);
|
xue@0
|
91 }
|
xue@0
|
92 else
|
xue@0
|
93 {
|
xue@0
|
94 fr2=-fr2;
|
xue@0
|
95 if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d-.%d", notename[note], oct+4, fr2);}
|
xue@0
|
96 else return AnsiString().sprintf("%s%d-.%02d", notename[note], oct+4, fr2);
|
xue@0
|
97 }
|
xue@0
|
98 }
|
xue@0
|
99
|
xue@0
|
100 void TextOutline(TCanvas* Canv, AnsiString Text, int X, int Y, TColor FC, TColor BC)
|
xue@0
|
101 {
|
xue@0
|
102 Canv->Font->Color=BC; Canv->TextOut(X-1, Y, Text); Canv->TextOut(X+1, Y, Text); Canv->TextOut(X, Y-1, Text);
|
xue@0
|
103 Canv->TextOut(X, Y+1, Text); Canv->Font->Color=FC; Canv->TextOut(X, Y, Text);
|
xue@0
|
104 }
|
xue@0
|
105
|
xue@0
|
106 //*
|
xue@0
|
107 //TFFilter: TF-filtering with cosinal interpolation
|
xue@0
|
108 //Identical data and dataout allowed.
|
xue@0
|
109 void TFFilter(TWaveView* WV, int Channel, TWaveViewSelections* Selections, bool Pass, bool allduration=false)
|
xue@0
|
110 {
|
xue@0
|
111 int Count=WV->Length, Wid=WV->SpecRes, Offst=WV->SpecOffst;
|
xue@0
|
112 int hWid=Wid/2, Order=Log2(Wid), frst, fren;
|
xue@0
|
113 {
|
xue@0
|
114 int Fr=(Count-Wid)/Offst+1;
|
xue@0
|
115 if (allduration) frst=0, fren=Fr;
|
xue@0
|
116 else
|
xue@0
|
117 {
|
xue@0
|
118 frst=floor((WV->StartPos-hWid)*1.0/Offst+0.5); if (frst<0) frst=0;
|
xue@0
|
119 fren=floor((WV->EndPos-hWid)*1.0/Offst+0.5); if (fren>Fr) fren=Fr;
|
xue@0
|
120 }
|
xue@0
|
121 }
|
xue@0
|
122 int frcount=fren-frst;
|
xue@0
|
123 int** filter=new int*[frcount]; //signals if man atom is kept or discarded
|
xue@0
|
124 filter[0]=new int[frcount*Wid]; for (int i=1; i<frcount; i++) filter[i]=&filter[0][i*Wid];
|
xue@0
|
125
|
xue@0
|
126 //fill local filter table: entries "1" in the table are kept, "0" are discarded
|
xue@0
|
127 if (Pass) memset(filter[0], 0, sizeof(int)*frcount*Wid);
|
xue@0
|
128 else for (int i=0; i<frcount; i++) for (int j=0; j<Wid; j++) filter[i][j]=1;
|
xue@0
|
129 for (int i=0; i<Selections->Count; i++)
|
xue@0
|
130 {
|
xue@0
|
131 int lx1, lx2, ly1, ly2;
|
xue@0
|
132 lx1=floor((Selections->Items[i].StartPos-hWid)*1.0/Offst+0.5)-frst;
|
xue@0
|
133 lx2=floor((Selections->Items[i].EndPos-hWid)*1.0/Offst+0.5)-frst;
|
xue@0
|
134 ly1=Selections->Items[i].StartDigiFreq*Wid;
|
xue@0
|
135 ly2=Selections->Items[i].EndDigiFreq*Wid;
|
xue@0
|
136 if (lx1<0) lx1=0; if (lx2>=frcount) lx2=frcount-1;
|
xue@0
|
137 if (ly1<0) ly1=0; if (ly1>hWid) ly1=hWid;
|
xue@0
|
138 if (Pass) for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=1;
|
xue@0
|
139 else for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=0;
|
xue@0
|
140 }
|
xue@0
|
141 double* lxfr=new double[frcount]; //the ratio of kept atoms of each frame
|
xue@0
|
142 for (int i=0; i<frcount; i++)
|
xue@0
|
143 {
|
xue@0
|
144 lxfr[i]=0;
|
xue@0
|
145 for (int j=0; j<=hWid; j++) if (filter[i][j]) lxfr[i]=lxfr[i]+1;
|
xue@0
|
146 lxfr[i]/=(hWid+1);
|
xue@0
|
147 }
|
xue@0
|
148
|
xue@0
|
149 //construct the window used for interpolation
|
xue@0
|
150 double* winf=WV->fwin; //this is the one used to compute Spec
|
xue@0
|
151 double* wini=NewWindow8(wtHann, Wid, NULL, NULL, 0); //this is an idea COLA window
|
xue@0
|
152 if (hWid!=Offst){double tmp=Offst*1.0/hWid; for (int i=0; i<Wid; i++) wini[i]*=tmp;} //this normalizes COLA to perfect reconstruction OLA
|
xue@0
|
153 double* winrec; //this window is the one actually to be applied after IFFT
|
xue@0
|
154 if (WV->SpecWindowType==wtHann) winrec=0;
|
xue@0
|
155 else
|
xue@0
|
156 {
|
xue@0
|
157 winrec=new double[Wid];
|
xue@0
|
158 for (int i=0; i<Wid; i++)
|
xue@0
|
159 if (winf[i]!=0) winrec[i]=wini[i]/winf[i];
|
xue@0
|
160 else winrec[i]=0;
|
xue@0
|
161 }
|
xue@0
|
162 AllocateFFTBuffer(Wid, ldata, w, x);
|
xue@0
|
163 int* hbitinv=CreateBitInvTable(Order-1);
|
xue@0
|
164
|
xue@0
|
165 int bps=WV->BytesPerSample;
|
xue@0
|
166 char* data8=&WV->Data8[Channel][frst*Offst*bps];
|
xue@0
|
167
|
xue@0
|
168 for (int fr=0; fr<frcount; fr++)
|
xue@0
|
169 {
|
xue@0
|
170 if (lxfr[fr]!=0 && lxfr[fr]!=1) WV->Spec[Channel][frst+fr];
|
xue@0
|
171 }
|
xue@0
|
172
|
xue@0
|
173 int prefetchcount=Wid/Offst;
|
xue@0
|
174 char** prefetch=new char*[prefetchcount]; prefetch[0]=new char[prefetchcount*bps*Wid]; for (int i=1; i<prefetchcount; i++) prefetch[i]=&prefetch[0][i*Wid*bps];
|
xue@0
|
175
|
xue@0
|
176 for (int fr=0; fr<frcount; fr++)
|
xue@0
|
177 {
|
xue@0
|
178 if (fr==0)
|
xue@0
|
179 {
|
xue@0
|
180 //prefetch frames
|
xue@0
|
181 for (int i=0; i<prefetchcount; i++)
|
xue@0
|
182 if (i<frcount && lxfr[i]==0) memcpy(prefetch[i], &data8[i*Offst*bps], Wid*bps);
|
xue@0
|
183 }
|
xue@0
|
184 //prefetch[fr%prefetchcount] now contains the fr-th frame
|
xue@0
|
185 char* wvdata=&data8[fr*Offst*bps];
|
xue@0
|
186 char* fdata=prefetch[fr%prefetchcount];
|
xue@0
|
187 if (lxfr[fr]==0)
|
xue@0
|
188 {
|
xue@0
|
189 //remove original frame (windowed) from signal
|
xue@0
|
190 MultiSub(wvdata, fdata, bps, wini, Wid);
|
xue@0
|
191 }
|
xue@0
|
192 else if (lxfr[fr]==1)
|
xue@0
|
193 {
|
xue@0
|
194 //do nothing = leave originl frame (windowed) as is
|
xue@0
|
195 }
|
xue@0
|
196 else
|
xue@0
|
197 {
|
xue@0
|
198 //replace original frame (windowed) with syntheszed frame, but here
|
xue@0
|
199 // is a subtractive approach: you synthesize what is subtracted instead
|
xue@0
|
200 // and remove it directly without windowing original data
|
xue@0
|
201 cmplx<QSPEC_FORMAT>* spec=WV->Spec[Channel][frst+fr];
|
xue@0
|
202 for (int i=0; i<=hWid; i++)
|
xue@0
|
203 if (filter[fr][i]==0) x[i]=spec[i];
|
xue@0
|
204 else x[i]=0;
|
xue@0
|
205 CIFFTR(x, Order, w, ldata, hbitinv);
|
xue@0
|
206 if (winrec) for (int i=0; i<Wid; i++) ldata[i]*=winrec[i];
|
xue@0
|
207 AddDoubleToInt1624(wvdata, bps, ldata, Wid, -1);
|
xue@0
|
208 }
|
xue@0
|
209 //prefetch next
|
xue@0
|
210 if (fr+prefetchcount<frcount && lxfr[fr+prefetchcount]==0) memcpy(fdata, &data8[(fr+prefetchcount)*Offst*bps], bps*Wid);
|
xue@0
|
211 }
|
xue@0
|
212
|
xue@0
|
213 FreeFFTBuffer(ldata);
|
xue@0
|
214 free(hbitinv);
|
xue@0
|
215
|
xue@0
|
216 delete[] filter[0]; delete[] filter;
|
xue@0
|
217 delete[] prefetch[0]; delete[] prefetch;
|
xue@0
|
218 delete[] lxfr;
|
xue@0
|
219 delete[] winrec;
|
xue@0
|
220 free8(wini);
|
xue@0
|
221 } //*/
|
xue@0
|
222
|
xue@0
|
223 //---------------------------------------------------------------------------
|
xue@0
|
224 void FeedFFTBuffers(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent)
|
xue@0
|
225 {
|
xue@0
|
226 TWaveView* WV=(TWaveView*)Parent;
|
xue@0
|
227 w=WV->fw;
|
xue@0
|
228 x=WV->fx;
|
xue@0
|
229 win=WV->fwin;
|
xue@0
|
230 hbi=WV->fhbi;
|
xue@0
|
231 }
|
xue@0
|
232
|
xue@0
|
233 //---------------------------------------------------------------------------
|
xue@0
|
234 static inline void ValidCtrCheck(TWaveView *)
|
xue@0
|
235 {
|
xue@0
|
236 new TWaveView(NULL);
|
xue@0
|
237 }
|
xue@0
|
238 //---------------------------------------------------------------------------
|
xue@0
|
239 __fastcall TWaveView::TWaveView(TComponent* Owner, bool usex, bool usep)
|
xue@0
|
240 : TCustomControl(Owner)
|
xue@0
|
241 {
|
xue@0
|
242 if (!dynamic_cast<TCustomForm*>(Owner))
|
xue@0
|
243 Parent=dynamic_cast<TWinControl*>(Owner);
|
xue@0
|
244
|
xue@0
|
245 DisableMouseWheelZoom=false;
|
xue@0
|
246
|
xue@0
|
247 FTools.Clear();
|
xue@0
|
248 FPitchScalePart=1;
|
xue@0
|
249 FSectionProgress=-1;
|
xue@0
|
250
|
xue@0
|
251 FShowCursor=true;
|
xue@0
|
252 FShowCursorText=true;
|
xue@0
|
253 FShowInfo=true;
|
xue@0
|
254 FShowPaneInfo=true;
|
xue@0
|
255 FPlayNoteInSemitone=true;
|
xue@0
|
256
|
xue@0
|
257 FAutoSpecAmp=false;
|
xue@0
|
258 FSpecAmp=1;
|
xue@0
|
259
|
xue@0
|
260 for (int i=0; i<WV2_MAX_CHANNEL; i++) FSpectrogram[i]=new TQuickSpectrogram(this, i, usex, usep, FeedFFTBuffers);
|
xue@0
|
261
|
xue@0
|
262 FSpecRes=1024;
|
xue@0
|
263 FSpecOffst=FSpecRes/2;
|
xue@0
|
264 FSpecWindowType=wtHamming;
|
xue@0
|
265 FSpecWindowParamD[0]=32*log(2.0)/(M_PI*M_PI);
|
xue@0
|
266
|
xue@0
|
267 FLocalDataTimeGrid=true;
|
xue@0
|
268 FForceHamming=true;
|
xue@0
|
269 FCurrentPane=-1;
|
xue@0
|
270 FCalculateFrameCount=0;
|
xue@0
|
271 FSamplesPerSec=44100;
|
xue@0
|
272 FBlockSize=8192;
|
xue@0
|
273 FCaption="";
|
xue@0
|
274 FOnGetOpMode=0;
|
xue@0
|
275 FOnGetPlaybackStartAndEndPos=0;
|
xue@0
|
276 FOnInfoDblClick=0;
|
xue@0
|
277 FOnMousePointer=0;
|
xue@0
|
278 FOnMouseLocalData=0;
|
xue@0
|
279 FOnSelectedChange=0;
|
xue@0
|
280 FCustomCursorText=0;
|
xue@0
|
281 FOnCustomPaint=0;
|
xue@0
|
282 FCustomInfo=0;
|
xue@0
|
283 FCustomPaneInfo=0;
|
xue@0
|
284 FCustomProperty=0;
|
xue@0
|
285 FOnPageChange=0;
|
xue@0
|
286 FOnScaleChange=0;
|
xue@0
|
287 FOnPlaybackDone=0;
|
xue@0
|
288 FOnPaint=0;
|
xue@0
|
289 FCustomItemExtractClick=0;
|
xue@0
|
290 FCustomXZoomClick=0;
|
xue@0
|
291 FCustomYZoomClick=0;
|
xue@0
|
292 FLength=0;
|
xue@0
|
293 InfoRectAtPointer=-1;
|
xue@0
|
294 ObjectAtPointer=0;
|
xue@0
|
295 StartObject=0;
|
xue@0
|
296
|
xue@0
|
297 FSection=new TDataAudio(this);
|
xue@0
|
298 PlayBuffer0=0;
|
xue@0
|
299 PlayBuffer1=0;
|
xue@0
|
300
|
xue@0
|
301 FSelectionBorderWidth=1;
|
xue@0
|
302
|
xue@0
|
303 FBytesPerSample=2;
|
xue@0
|
304 FStereoMode=wvpStereo;
|
xue@0
|
305 TimeStamp1=0;
|
xue@0
|
306 TimeStamp2=0;
|
xue@0
|
307
|
xue@0
|
308 FAxisColor=clBlack;
|
xue@0
|
309 FBackColor=clLtGray;
|
xue@0
|
310 FCursorColorBright=clLime;
|
xue@0
|
311 FCursorColorDim=clRed;
|
xue@0
|
312 FInfoColor0=clWhite;
|
xue@0
|
313 FInfoColor1=clBlack;
|
xue@0
|
314 FInfoColor2=clRed;
|
xue@0
|
315 FWaveColor=clBlack;
|
xue@0
|
316 WaveBackColor=clWhite;
|
xue@0
|
317 Brush->Color=FBackColor;
|
xue@0
|
318
|
xue@0
|
319 FSelectedAreaColorX=clWhite;
|
xue@0
|
320 FSelectedFrameColorX=clWhite;
|
xue@0
|
321 FSelectingFrameColorX=clWhite;
|
xue@0
|
322
|
xue@0
|
323 Height=150;
|
xue@0
|
324 Width=150;
|
xue@0
|
325 FWaveAudio=0;
|
xue@0
|
326
|
xue@0
|
327 InfoLeft=0;
|
xue@0
|
328 InfoTop=0;
|
xue@0
|
329
|
xue@0
|
330 FExtractMode=WV2_HSELECT;
|
xue@0
|
331 FSelectMode=WV2_HSELECT;
|
xue@0
|
332 FOpMode=wopIdle;
|
xue@0
|
333 FAutoExtractMode=true;
|
xue@0
|
334 FRulerAlignX=alTop;
|
xue@0
|
335 FRulerAlignY=alLeft;
|
xue@0
|
336
|
xue@0
|
337 FLocalDataOn=false;
|
xue@0
|
338 FClickFocus=false;
|
xue@0
|
339 FMultiSelect=false;
|
xue@0
|
340 FDefaultPopupMenu=true;
|
xue@0
|
341 FDefaultPropertyItems=true;
|
xue@0
|
342 FProgressCursor=true;
|
xue@0
|
343 FYZoomRate=1;
|
xue@0
|
344 FStartDigiFreq=0;
|
xue@0
|
345 FEndDigiFreq=0.5;
|
xue@0
|
346
|
xue@0
|
347 FSelections=new TWaveViewSelections;
|
xue@0
|
348
|
xue@0
|
349 FFonts[0]=new TFont; FFonts[0]->Color=clBlue; FFonts[0]->Height=12; FFonts[0]->Name="Ariel";
|
xue@0
|
350 FFonts[1]=new TFont; FFonts[1]->Color=clYellow; FFonts[1]->Height=12; FFonts[1]->Name="Ariel";
|
xue@0
|
351 FFonts[2]=new TFont; FFonts[2]->Color=clYellow; FFonts[2]->Height=12; FFonts[2]->Name="Ariel";
|
xue@0
|
352 FFonts[3]=new TFont; FFonts[3]->Color=clWhite; FFonts[3]->Height=12; FFonts[3]->Name="Ariel";
|
xue@0
|
353 FFonts[4]=new TFont; FFonts[4]->Color=clBlack; FFonts[4]->Height=12; FFonts[4]->Name="Ariel";
|
xue@0
|
354 FFonts[5]=new TFont; FFonts[5]->Color=clBlack; FFonts[5]->Height=12; FFonts[5]->Name="Ariel";
|
xue@0
|
355
|
xue@0
|
356 TWaveViewRulerSetting ASetting={clRed, clWhite, clBlack, TColor(clGray/2), clSilver, 4, 3, FFonts[0], true};
|
xue@0
|
357 DefaultRulerSetting[0]=ASetting;
|
xue@0
|
358 TWaveViewRulerSetting ASetting1={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[1], false};
|
xue@0
|
359 DefaultRulerSetting[1]=ASetting1;
|
xue@0
|
360 TWaveViewRulerSetting ASetting2={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[2], false};
|
xue@0
|
361 DefaultRulerSetting[2]=ASetting2;
|
xue@0
|
362 TWaveViewRulerSetting ASetting3={clRed, clBlack, clYellow, clRed, clBlack, 4, 3, FFonts[3], false};
|
xue@0
|
363 DefaultRulerSetting[3]=ASetting3;
|
xue@0
|
364 FRulerUnitTime=0;
|
xue@0
|
365 FRulerUnitFreq=0;
|
xue@0
|
366 FRulerUnitAmp=0;
|
xue@0
|
367
|
xue@0
|
368 DefaultPaneInfoFont=FFonts[4];
|
xue@0
|
369 DefaultInfoFont=FFonts[5];
|
xue@0
|
370
|
xue@0
|
371 ItemExtract=NewItem(WV2_STRINGS_Extract,NULL,false,true,NULL,NULL,"ItemExtract");
|
xue@0
|
372 ItemPlay=NewItem(WV2_STRINGS_Play, NULL,false,true,NULL,NULL,"ItemPlay");
|
xue@0
|
373 ItemProperty=NewItem(WV2_STRINGS_Properties,NULL,false, true,NULL,NULL,"ItemProperty");
|
xue@0
|
374 ItemSeparator1=NewItem("-",NULL,false,false,NULL,NULL,"ItemSeparator1");
|
xue@0
|
375 ItemXZoomRestore=NewItem(WV2_STRINGS_X_zoom_all,NULL,false,true,NULL,NULL,"ItemXZoomRestore");
|
xue@0
|
376 ItemYZoomRestore=NewItem(WV2_STRINGS_Y_zoom_all,NULL,false,true,NULL,NULL,"ItemYZoomRestore");
|
xue@0
|
377
|
xue@0
|
378 TMenuItem** Items=new TMenuItem*[6];
|
xue@0
|
379 Items[0]=ItemExtract;
|
xue@0
|
380 Items[1]=ItemPlay;
|
xue@0
|
381 Items[2]=ItemProperty;
|
xue@0
|
382 Items[3]=ItemSeparator1;
|
xue@0
|
383 Items[4]=ItemXZoomRestore;
|
xue@0
|
384 Items[5]=ItemYZoomRestore;
|
xue@0
|
385 FMenu=NewPopupMenu(this, "FMenu", paLeft, true, Items, 5);
|
xue@0
|
386 FMenu->AutoHotkeys=maManual;
|
xue@0
|
387 FMenu->OnPopup=FMenuPopup;
|
xue@0
|
388 delete[] Items;
|
xue@0
|
389 PopupMenu=FMenu;
|
xue@0
|
390
|
xue@0
|
391 ItemExtract->OnClick=ItemExtractClick;
|
xue@0
|
392 ItemPlay->OnClick=ItemPlayClick;
|
xue@0
|
393 ItemProperty->OnClick=ItemPropertyClick;
|
xue@0
|
394 ItemXZoomRestore->OnClick=ItemXZoomClick;
|
xue@0
|
395 ItemYZoomRestore->OnClick=ItemYZoomClick;
|
xue@0
|
396 ItemXZoomRestore->Tag=ITEMXZOOMRESTORE_TAG;
|
xue@0
|
397 ItemYZoomRestore->Tag=ITEMYZOOMRESTORE_TAG;
|
xue@0
|
398 FScrollBar=0;
|
xue@0
|
399
|
xue@0
|
400 CheckWaveOutDevCaps(this);
|
xue@0
|
401
|
xue@0
|
402 DoubleBuffered=true;
|
xue@0
|
403
|
xue@0
|
404 fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); //fft buffer
|
xue@0
|
405 fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes]; //fft buffer
|
xue@0
|
406 SetTwiddleFactors(FSpecRes, fw);
|
xue@0
|
407 fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); //window function
|
xue@0
|
408 fhbi=CreateBitInvTable(Log2(FSpecRes)-1);
|
xue@0
|
409
|
xue@0
|
410 memset(Basic0, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL);
|
xue@0
|
411 memset(Basic1, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL);
|
xue@0
|
412
|
xue@0
|
413
|
xue@0
|
414
|
xue@0
|
415 AutoScroll=false;
|
xue@0
|
416 ForceOLA=false;
|
xue@0
|
417 LoopPlay=false;
|
xue@0
|
418 LoopMode=0;
|
xue@0
|
419 }
|
xue@0
|
420
|
xue@0
|
421 __fastcall TWaveView::~TWaveView()
|
xue@0
|
422 {
|
xue@0
|
423 delete FSelections;
|
xue@0
|
424
|
xue@0
|
425 FreeData(FChannels);
|
xue@0
|
426 FreeInternalBitmaps(FChannels);
|
xue@0
|
427 FreeSpectrograms();
|
xue@0
|
428
|
xue@0
|
429 free8(fwin);
|
xue@0
|
430 free8(fw);
|
xue@0
|
431 free(fhbi);
|
xue@0
|
432
|
xue@0
|
433 for (int i=0; i<WV2_FONT_NUMBER; i++) delete FFonts[i];
|
xue@0
|
434 }
|
xue@0
|
435
|
xue@0
|
436 //This counts the number of frames to be computed for displaying dX columns of pixels located as frames xx[0:dX-1].
|
xue@0
|
437 int TWaveView::CalculateSpectrogramX(int channel, double* xx, int dX, bool interpolate)
|
xue@0
|
438 {
|
xue@0
|
439 TQuickSpectrogram* FS=FSpectrogram[channel];
|
xue@0
|
440 if (FS->Capacity==0) FS->SetFrCapacity((FLength-FSpecRes)/FSpecOffst+2);
|
xue@0
|
441 int calculatefrcount=0;
|
xue@0
|
442 for (int x=0; x<dX; x++)
|
xue@0
|
443 {
|
xue@0
|
444 double ffr=xx[x];
|
xue@0
|
445 int fr=floor(ffr);
|
xue@0
|
446 if (fr>=0 && fr<FS->Capacity && (interpolate || ffr-fr<=0.5))
|
xue@0
|
447 {
|
xue@0
|
448 if (FS->Frame[fr]<0 || FS->Valid[fr]==0) calculatefrcount++;
|
xue@0
|
449 }
|
xue@0
|
450 if (fr+1>=0 && fr+1<FS->Capacity && (interpolate || ffr-fr>=0.5))
|
xue@0
|
451 {
|
xue@0
|
452 if (FS->Frame[fr+1]<0 || FS->Valid[fr+1]==0) calculatefrcount++;
|
xue@0
|
453 }
|
xue@0
|
454 }
|
xue@0
|
455 return calculatefrcount;
|
xue@0
|
456 }
|
xue@0
|
457
|
xue@0
|
458 //Set the state of Play menuitem according to device capacity
|
xue@0
|
459 void __fastcall TWaveView::CheckWaveOutDevCaps(TObject* Sender)
|
xue@0
|
460 {
|
xue@0
|
461 WAVEOUTCAPS woc;
|
xue@0
|
462 if (waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc))==MMSYSERR_NOERROR)
|
xue@0
|
463 ItemPlay->Enabled=true;
|
xue@0
|
464 else
|
xue@0
|
465 ItemPlay->Enabled=false;
|
xue@0
|
466 }
|
xue@0
|
467
|
xue@0
|
468 void __fastcall TWaveView::ClearSelections(TObject* Sender)
|
xue@0
|
469 {
|
xue@0
|
470 FSelections->Clear();
|
xue@0
|
471 }
|
xue@0
|
472
|
xue@0
|
473 void __fastcall TWaveView::Click()
|
xue@0
|
474 {
|
xue@0
|
475 if (ObjectAtPointer && ObjectAtPointer->OnClick) ObjectAtPointer->OnClick(this);
|
xue@0
|
476 TControl::Click();
|
xue@0
|
477 }
|
xue@0
|
478
|
xue@0
|
479 void TWaveView::ClearSpectrogram(int index)
|
xue@0
|
480 {
|
xue@0
|
481 FSpectrogram[index]->FreeBuffers();
|
xue@0
|
482 }
|
xue@0
|
483
|
xue@0
|
484 void TWaveView::ClearSpectrograms()
|
xue@0
|
485 {
|
xue@0
|
486 for (int i=0; i<FChannels; i++) FSpectrogram[i]->FreeBuffers();
|
xue@0
|
487 }
|
xue@0
|
488
|
xue@0
|
489 TCursor __fastcall TWaveView::ControlCursorAtPos(int X, int Y)
|
xue@0
|
490 {
|
xue@0
|
491 TWaveViewSelHitTest ht=SelHitTest(X, Y);
|
xue@0
|
492 if (ht==selInner)
|
xue@0
|
493 return crSizeAll;
|
xue@0
|
494 if (ht==selLeft || ht==selRight)
|
xue@0
|
495 return crSizeWE;
|
xue@0
|
496 if (ht==selTop || ht==selBottom)
|
xue@0
|
497 return crSizeNS;
|
xue@0
|
498 if (ht==selTopLeft || ht==selBottomRight)
|
xue@0
|
499 return crSizeNWSE;
|
xue@0
|
500 if (ht==selTopRight || ht==selBottomLeft)
|
xue@0
|
501 return crSizeNESW;
|
xue@0
|
502 return crArrow;
|
xue@0
|
503 }
|
xue@0
|
504
|
xue@0
|
505 int __fastcall TWaveView::CreatePanes(int X, int Y)
|
xue@0
|
506 {
|
xue@0
|
507 return FPanes.CreatePanes(ClientRect, X, Y);
|
xue@0
|
508 }
|
xue@0
|
509
|
xue@0
|
510 void __fastcall TWaveView::DblClick()
|
xue@0
|
511 {
|
xue@0
|
512 if (FShowInfo && InfoRectAtPointer>=0 && FOnInfoDblClick) FOnInfoDblClick(this);
|
xue@0
|
513 if (ObjectAtPointer && ObjectAtPointer->OnDblClick) ObjectAtPointer->OnDblClick(this);
|
xue@0
|
514 TControl::DblClick();
|
xue@0
|
515 }
|
xue@0
|
516
|
xue@0
|
517
|
xue@0
|
518 void __fastcall TWaveView::DefaultShowProperty(bool selection)
|
xue@0
|
519 {
|
xue@0
|
520 if (!selection)
|
xue@0
|
521 ShowMessage(AnsiString().sprintf(WV2_STRINGS_1,
|
xue@0
|
522 WV2_STRINGS_Properties_current_audio,
|
xue@0
|
523 WV2_STRINGS_Time, FEndPos-FStartPos, (FEndPos-FStartPos)*1.0/FSamplesPerSec,
|
xue@0
|
524 WV2_STRINGS_From, FStartPos, FStartPos*1.0/FSamplesPerSec,
|
xue@0
|
525 WV2_STRINGS_To, FEndPos, FEndPos*1.0/FSamplesPerSec,
|
xue@0
|
526 WV2_STRINGS_Frequency, FEndDigiFreq-FStartDigiFreq,
|
xue@0
|
527 WV2_STRINGS_From, FStartDigiFreq,
|
xue@0
|
528 WV2_STRINGS_To, FEndDigiFreq,
|
xue@0
|
529 WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec,
|
xue@0
|
530 WV2_STRINGS_Samples_per_second, FSamplesPerSec,
|
xue@0
|
531 WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample
|
xue@0
|
532 ));
|
xue@0
|
533 else
|
xue@0
|
534 ShowMessage(AnsiString().sprintf(WV2_STRINGS_1,
|
xue@0
|
535 WV2_STRINGS_Properties_selection,
|
xue@0
|
536 WV2_STRINGS_Time, FSelections->Length, (FSelections->Length)*1.0/FSamplesPerSec,
|
xue@0
|
537 WV2_STRINGS_From, FSelections->StartPos, FSelections->StartPos*1.0/FSamplesPerSec,
|
xue@0
|
538 WV2_STRINGS_To, FSelections->EndPos, FSelections->EndPos*1.0/FSamplesPerSec,
|
xue@0
|
539 WV2_STRINGS_Frequency, FSelections->EndDigiFreq-FSelections->StartDigiFreq,
|
xue@0
|
540 WV2_STRINGS_From, FSelections->StartDigiFreq,
|
xue@0
|
541 WV2_STRINGS_To, FSelections->EndDigiFreq,
|
xue@0
|
542 WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec,
|
xue@0
|
543 WV2_STRINGS_Samples_per_second, FSamplesPerSec,
|
xue@0
|
544 WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample
|
xue@0
|
545 ));
|
xue@0
|
546 }
|
xue@0
|
547
|
xue@0
|
548 void __fastcall TWaveView::DoExtract(TObject* Sender)
|
xue@0
|
549 {
|
xue@0
|
550 if (FCustomItemExtractClick) FCustomItemExtractClick(Sender);
|
xue@0
|
551 else
|
xue@0
|
552 {
|
xue@0
|
553 UndoExtractSelection=GetCurrentRange();
|
xue@0
|
554 bool pagechange=false;
|
xue@0
|
555 bool spanchange=false;
|
xue@0
|
556 if (FExtractMode & WV2_HSELECT)
|
xue@0
|
557 {
|
xue@0
|
558 if (FEndPos!=FSelections->EndPos) FEndPos=FSelections->EndPos, pagechange=spanchange=true;
|
xue@0
|
559 if (FStartPos!=FSelections->StartPos) FStartPos=FSelections->StartPos, pagechange=spanchange=true;
|
xue@0
|
560 }
|
xue@0
|
561 if (FExtractMode & WV2_VSELECT)
|
xue@0
|
562 {
|
xue@0
|
563 if (FEndDigiFreq!=FSelections->EndDigiFreq) FEndDigiFreq=FSelections->EndDigiFreq, spanchange=true;
|
xue@0
|
564 if (FStartDigiFreq!=FSelections->StartDigiFreq) FStartDigiFreq=FSelections->StartDigiFreq, spanchange=true;
|
xue@0
|
565 }
|
xue@0
|
566 if (spanchange) Invalidate();
|
xue@0
|
567 if (pagechange) PageChange();
|
xue@0
|
568 }
|
xue@0
|
569 }
|
xue@0
|
570
|
xue@0
|
571 void __fastcall TWaveView::DrawBitmap(TObject* Sender)
|
xue@0
|
572 {
|
xue@0
|
573 Graphics::TBitmap* bmp=(Graphics::TBitmap*)Sender;
|
xue@0
|
574 Canvas->Draw(0, 0, bmp);
|
xue@0
|
575 }
|
xue@0
|
576
|
xue@0
|
577 void __fastcall TWaveView::DrawCaption(AnsiString ACaption)
|
xue@0
|
578 {
|
xue@0
|
579 TSize ASize=Canvas->TextExtent(ACaption);
|
xue@0
|
580 SetBkMode(Canvas->Handle, TRANSPARENT);
|
xue@0
|
581 Canvas->TextOut(Width-ASize.cx-4, 2, ACaption);
|
xue@0
|
582 }
|
xue@0
|
583
|
xue@0
|
584 void __fastcall TWaveView::DrawCursor(int PaneIndex, int X, int Y)
|
xue@0
|
585 {
|
xue@0
|
586 int m=FPanes.Margin;
|
xue@0
|
587 TRect Rect=FPanes.Rect[PaneIndex];
|
xue@0
|
588 Canvas->Brush->Style=bsSolid; Canvas->Pen->Mode=pmCopy;
|
xue@0
|
589 TColor AColor=(FPanes.Type[PaneIndex]==0)?FCursorColorDim:FCursorColorBright;
|
xue@0
|
590 Canvas->Brush->Color=AColor; Canvas->Pen->Color=AColor;
|
xue@0
|
591
|
xue@0
|
592 int xtip, xbott, ytip, ybott;
|
xue@0
|
593 TPoint Points[3];
|
xue@0
|
594 if (FRulerAlignX==alTop) xtip=Rect.top+2, xbott=Rect.top-m+1;
|
xue@0
|
595 else xtip=Rect.bottom-2, xbott=Rect.bottom+m-1;
|
xue@0
|
596 Points[0]=Point(X, xtip); Points[1]=Point(X-m/2, xbott); Points[2]=Point(X+m/2, xbott);
|
xue@0
|
597 Canvas->Polygon(Points, 2);
|
xue@0
|
598 if (FRulerAlignY==alLeft) ytip=Rect.left+2, ybott=Rect.left-m+1;
|
xue@0
|
599 else ytip=Rect.right-2, ybott=Rect.right+m-1;
|
xue@0
|
600 Points[0]=Point(ytip, Y); Points[1]=Point(ybott, Y-m/2); Points[2]=Point(ybott, Y+m/2);
|
xue@0
|
601 Canvas->Polygon(Points, 2);
|
xue@0
|
602
|
xue@0
|
603 Canvas->Brush->Style=bsClear;
|
xue@0
|
604 if (FShowCursorText)
|
xue@0
|
605 {
|
xue@0
|
606 int type=FPanes.Type[PaneIndex];
|
xue@0
|
607 TWaveViewRulerSetting RS=DefaultRulerSetting[type];
|
xue@0
|
608 Canvas->Font=RS.UnitFont;
|
xue@0
|
609 TColor FC=RS.FrontColor, BC=RS.BackColor;
|
xue@0
|
610 int textheight=Canvas->TextHeight("0")-2;
|
xue@0
|
611
|
xue@0
|
612 TStringList* List;
|
xue@0
|
613 if (FCustomCursorText) List=(TStringList*)FCustomCursorText(this);
|
xue@0
|
614 else
|
xue@0
|
615 {
|
xue@0
|
616 List=new TStringList;
|
xue@0
|
617 List->Add(CurrentTime);
|
xue@0
|
618 List->Add(AnsiString().sprintf("%.4gs", CurrentTime*1.0/FSamplesPerSec));
|
xue@0
|
619 if (FPanes.HasFreqAxis[PaneIndex])
|
xue@0
|
620 {
|
xue@0
|
621 List->Add(AnsiString().sprintf("%.1ffr", (this->CurrentTime-FSpecRes/2)*1.0/FSpecOffst));
|
xue@0
|
622 }
|
xue@0
|
623 List->Add("");
|
xue@0
|
624 if (FPanes.HasFreqAxis[PaneIndex])
|
xue@0
|
625 {
|
xue@0
|
626 double f=CurrentDigiFreq*FSamplesPerSec;
|
xue@0
|
627 List->Add(AnsiString().sprintf("%.6ghz", f));
|
xue@0
|
628 List->Add(AnsiString().sprintf("%.5gbin", CurrentDigiFreq*FSpecRes));
|
xue@0
|
629 if (f<WV2_MIN_LOG_FREQ) f=WV2_MIN_LOG_FREQ;
|
xue@0
|
630 List->Add(SemitoneToPitch(12*Log2(f/C4)));
|
xue@0
|
631 }
|
xue@0
|
632 else if (FPanes.Type[PaneIndex]==0)
|
xue@0
|
633 {
|
xue@0
|
634 int a=floor(FPTA(PaneIndex, Y)+0.5);
|
xue@0
|
635 List->Add(AnsiString().sprintf("%d", a));
|
xue@0
|
636 }
|
xue@0
|
637 }
|
xue@0
|
638
|
xue@0
|
639 int i=0, y=(FRulerAlignX==alTop)?xtip:(xtip-textheight), dtextheight=(FRulerAlignX==alTop)?textheight:-textheight;
|
xue@0
|
640 while (i<List->Count && List->Strings[i]!="")
|
xue@0
|
641 {
|
xue@0
|
642 TextOutline(Canvas, List->Strings[i], X-Canvas->TextWidth(List->Strings[i])/2+1, y, FC, BC);
|
xue@0
|
643 y+=dtextheight; i++;
|
xue@0
|
644 }
|
xue@0
|
645 while (i<List->Count && List->Strings[i]=="") i++;
|
xue@0
|
646 y=Y-textheight*(List->Count-i)*0.5;
|
xue@0
|
647 while (i<List->Count)
|
xue@0
|
648 {
|
xue@0
|
649 if (FRulerAlignY==alLeft) TextOutline(Canvas, List->Strings[i], ytip, y, FC, BC);
|
xue@0
|
650 else TextOutline(Canvas, List->Strings[i], ytip-Canvas->TextWidth(List->Strings[i]), y, FC, BC);
|
xue@0
|
651 y+=textheight; i++;
|
xue@0
|
652 }
|
xue@0
|
653
|
xue@0
|
654 delete List;
|
xue@0
|
655 }
|
xue@0
|
656 }
|
xue@0
|
657
|
xue@0
|
658 void __fastcall TWaveView::DrawInfo()
|
xue@0
|
659 {
|
xue@0
|
660 TStringList* List;
|
xue@0
|
661 if (FCustomInfo) List=(TStringList*)FCustomInfo(this);
|
xue@0
|
662 else
|
xue@0
|
663 {
|
xue@0
|
664 List=new TStringList;
|
xue@0
|
665 List->Add(AnsiString().sprintf(" %d-channel, %dhz, %dbit. ", FChannels, FSamplesPerSec, FBytesPerSample*8));
|
xue@0
|
666 double fs=FStartPos*1.0/FSamplesPerSec, fe=FEndPos*1.0/FSamplesPerSec;
|
xue@0
|
667 List->Add(AnsiString().sprintf(" Time(%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe));
|
xue@0
|
668 List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", FStartDigiFreq*FSamplesPerSec, FEndDigiFreq*FSamplesPerSec));
|
xue@0
|
669 }
|
xue@0
|
670 InfoRectCount=List->Count;
|
xue@0
|
671 Canvas->Font=DefaultInfoFont;
|
xue@0
|
672 Canvas->Brush->Style=bsSolid; Canvas->Font->Color=FInfoColor0;
|
xue@0
|
673 int textheight=Canvas->TextHeight("0");
|
xue@0
|
674 int left=InfoLeft, right, top=InfoTop, bottom=top+textheight;
|
xue@0
|
675 for (int i=0; i<InfoRectCount; i++)
|
xue@0
|
676 {
|
xue@0
|
677 if (i==InfoRectAtPointer)
|
xue@0
|
678 {
|
xue@0
|
679 Canvas->Brush->Color=FInfoColor2;
|
xue@0
|
680 Canvas->TextOut(left, top, List->Strings[i]);
|
xue@0
|
681 }
|
xue@0
|
682 else
|
xue@0
|
683 {
|
xue@0
|
684 Canvas->Brush->Color=FInfoColor1;
|
xue@0
|
685 Canvas->TextOut(left, top, List->Strings[i]);
|
xue@0
|
686 }
|
xue@0
|
687 right=left+Canvas->TextWidth(List->Strings[i]);
|
xue@0
|
688 if (i<WV2_INFORECTCOUNT) InfoRect[i]=TRect(left, top, right, bottom);
|
xue@0
|
689 left=right;
|
xue@0
|
690 }
|
xue@0
|
691
|
xue@0
|
692 delete List;
|
xue@0
|
693 }
|
xue@0
|
694
|
xue@0
|
695 void DrawRuler(double t1, double t2, TCanvas* Canv, TRect& Rect, TWaveViewRulerSetting RS, TAlign Align, bool ticking)
|
xue@0
|
696 {
|
xue@0
|
697 double trange=fabs(t2-t1);
|
xue@0
|
698 if (trange<=0) return;
|
xue@0
|
699 double unit=pow(10, floor(Log10(trange))), tick;
|
xue@0
|
700 trange/=unit;
|
xue@0
|
701
|
xue@0
|
702 int tickperunit;
|
xue@0
|
703 if (trange<2) {unit*=0.5; tickperunit=5;}
|
xue@0
|
704 else if (trange<5) {tickperunit=5;}
|
xue@0
|
705 else {unit*=2; tickperunit=4;}
|
xue@0
|
706 tick=unit/tickperunit;
|
xue@0
|
707
|
xue@0
|
708 if (!ticking)
|
xue@0
|
709 {
|
xue@0
|
710 int Y0=Rect.top, Y1=Rect.bottom;
|
xue@0
|
711 Canv->Pen->Color=RS.GridColor;
|
xue@0
|
712 int u1=ceil(t1/tick), u2=floor(t2/tick);
|
xue@0
|
713 if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
|
xue@0
|
714 for (int u=u1; u<=u2; u++)
|
xue@0
|
715 {
|
xue@0
|
716 double t=(u*tick-t1)/(t2-t1);
|
xue@0
|
717 int pos=Rect.left+(Rect.right-Rect.left)*t;
|
xue@0
|
718 Canv->MoveTo(pos, Y0);
|
xue@0
|
719 Canv->LineTo(pos, Y1);
|
xue@0
|
720 }
|
xue@0
|
721 }
|
xue@0
|
722 else
|
xue@0
|
723 {
|
xue@0
|
724 Canv->Brush->Style=bsClear;
|
xue@0
|
725 Canv->Font=RS.UnitFont;
|
xue@0
|
726 int Y0, Y1tick, Y1unit, YText;
|
xue@0
|
727 if (Align==alTop) Y0=Rect.top, Y1tick=Rect.top+RS.TickSize, Y1unit=Rect.top+RS.UnitTickSize, YText=Y1unit;
|
xue@0
|
728 else Y0=Rect.bottom, Y1tick=Rect.bottom-RS.TickSize, Y1unit=Rect.bottom-RS.UnitTickSize, YText=Y1unit-Canv->TextHeight("0");
|
xue@0
|
729
|
xue@0
|
730 int u1=ceil(t1/tick), u2=floor(t2/tick);
|
xue@0
|
731 if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
|
xue@0
|
732 for (int u=u1; u<=u2; u++)
|
xue@0
|
733 {
|
xue@0
|
734 double t=(u*tick-t1)/(t2-t1);
|
xue@0
|
735 int pos=Rect.left+(Rect.right-Rect.left)*t;
|
xue@0
|
736 Canv->MoveTo(pos, Y0);
|
xue@0
|
737 if (u%tickperunit==0)
|
xue@0
|
738 {
|
xue@0
|
739 Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(pos, Y1unit);
|
xue@0
|
740 AnsiString text=u*tick;
|
xue@0
|
741 TextOutline(Canv, text, pos-Canv->TextWidth(text)/2+1, YText, RS.UnitFont->Color, RS.BackColor);
|
xue@0
|
742 }
|
xue@0
|
743 else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(pos, Y1tick);}
|
xue@0
|
744 }
|
xue@0
|
745 }
|
xue@0
|
746 }
|
xue@0
|
747
|
xue@0
|
748 void DrawRulerV(double t1, double t2, TCanvas* Canv, TRect& Rect, TWaveViewRulerSetting RS, TAlign Align, bool ticking, AnsiString (*CustomText)(double)=NULL, void (*CustomUnit)(double, double&, int&)=0)
|
xue@0
|
749 {
|
xue@0
|
750 double trange=fabs(t2-t1);
|
xue@0
|
751 if (trange<=0) return;
|
xue@0
|
752 double unit=pow(10, floor(Log10(trange)));
|
xue@0
|
753 int tickperunit;
|
xue@0
|
754
|
xue@0
|
755 trange/=unit;
|
xue@0
|
756 if (CustomUnit) CustomUnit(trange, unit, tickperunit);
|
xue@0
|
757 else
|
xue@0
|
758 {
|
xue@0
|
759 if (trange<2) {unit*=0.2; tickperunit=4;}
|
xue@0
|
760 else if (trange<5) {unit*=0.5; tickperunit=5;}
|
xue@0
|
761 else {tickperunit=5;}
|
xue@0
|
762 }
|
xue@0
|
763
|
xue@0
|
764 double tick=unit/tickperunit;
|
xue@0
|
765 if (!ticking)
|
xue@0
|
766 {
|
xue@0
|
767 int X0=Rect.left, X1=Rect.right;
|
xue@0
|
768 Canv->Pen->Color=RS.GridColor;
|
xue@0
|
769 int u1=ceil(t1/tick), u2=floor(t2/tick);
|
xue@0
|
770 if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
|
xue@0
|
771 for (int u=u1; u<=u2; u++)
|
xue@0
|
772 {
|
xue@0
|
773 double t=(u*tick-t1)/(t2-t1);
|
xue@0
|
774 int pos=Rect.top+(Rect.bottom-Rect.top)*t;
|
xue@0
|
775 Canv->MoveTo(X0, pos);
|
xue@0
|
776 Canv->LineTo(X1, pos);
|
xue@0
|
777 }
|
xue@0
|
778 }
|
xue@0
|
779 else
|
xue@0
|
780 {
|
xue@0
|
781 Canv->Brush->Style=bsClear;
|
xue@0
|
782 Canv->Font=RS.UnitFont;
|
xue@0
|
783 int X0, X1tick, X1unit, XText;
|
xue@0
|
784 if (Align==alLeft) X0=Rect.left, X1tick=Rect.left+RS.TickSize, X1unit=Rect.left+RS.UnitTickSize, XText=X1unit;
|
xue@0
|
785 else X0=Rect.right, X1tick=Rect.right-RS.TickSize, X1unit=Rect.right-RS.UnitTickSize, XText=X1unit;
|
xue@0
|
786
|
xue@0
|
787 int u1=ceil(t1/tick), u2=floor(t2/tick);
|
xue@0
|
788 if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
|
xue@0
|
789 for (int u=u1; u<=u2; u++)
|
xue@0
|
790 {
|
xue@0
|
791 double t=(u*tick-t1)/(t2-t1);
|
xue@0
|
792 int pos=Rect.top+(Rect.bottom-Rect.top)*t;
|
xue@0
|
793 Canv->MoveTo(X0, pos);
|
xue@0
|
794 if (u%tickperunit==0)
|
xue@0
|
795 {
|
xue@0
|
796 Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(X1unit, pos);
|
xue@0
|
797 AnsiString text=CustomText?CustomText(u*tick):AnsiString(u*tick);
|
xue@0
|
798 TextOutline(Canv, text, (Align==alLeft)?XText:XText-Canv->TextWidth(text), pos-Canv->TextHeight(text)/2, RS.UnitFont->Color, RS.BackColor);
|
xue@0
|
799 }
|
xue@0
|
800 else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(X1tick, pos);}
|
xue@0
|
801 }
|
xue@0
|
802 }
|
xue@0
|
803 }
|
xue@0
|
804
|
xue@0
|
805 AnsiString SemitoneToHz(double f)
|
xue@0
|
806 {
|
xue@0
|
807 return AnsiString().sprintf("%.1f", 440*pow(2, f/12));
|
xue@0
|
808 }
|
xue@0
|
809
|
xue@0
|
810 void SemitoneUnit(double range, double& unit, int& tickperunit)
|
xue@0
|
811 {
|
xue@0
|
812 if (range<2) {unit*=0.2; tickperunit=4;}
|
xue@0
|
813 else if (range<5) {unit*=0.5; tickperunit=5;}
|
xue@0
|
814 else {tickperunit=5;}
|
xue@0
|
815
|
xue@0
|
816 if (unit>2)
|
xue@0
|
817 {
|
xue@0
|
818 if (unit<6) unit=6, tickperunit=6;
|
xue@0
|
819 else if (unit<12) unit=12, tickperunit=6;
|
xue@0
|
820 else if (unit<24) unit=24, tickperunit=6;
|
xue@0
|
821 else if (unit<36) unit=36, tickperunit=6;
|
xue@0
|
822 else if (unit<48) unit=48, tickperunit=4;
|
xue@0
|
823 else unit=60, tickperunit=5;
|
xue@0
|
824 }
|
xue@0
|
825 else if (unit<0.01)
|
xue@0
|
826 {
|
xue@0
|
827 unit=0.01;
|
xue@0
|
828 tickperunit=5;
|
xue@0
|
829 }
|
xue@0
|
830 }
|
xue@0
|
831
|
xue@0
|
832 void __fastcall TWaveView::DrawPane(int Channel, int Type, int YScale, int Rulers, TCanvas* Canv, TRect& Rect)
|
xue@0
|
833 {
|
xue@0
|
834 if (Channel>=FChannels) return;
|
xue@0
|
835
|
xue@0
|
836 Canv->Pen->Mode=pmCopy; Canv->Pen->Style=psSolid; Canv->Brush->Style=bsSolid;
|
xue@0
|
837
|
xue@0
|
838 if (Type==0) {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(Rect);}
|
xue@0
|
839
|
xue@0
|
840 HRGN Rgn=CreateRectRgn(Rect.left, Rect.top, Rect.right, Rect.bottom);
|
xue@0
|
841 SelectClipRgn(Canv->Handle, Rgn);
|
xue@0
|
842
|
xue@0
|
843 double TStart, TEnd;
|
xue@0
|
844 if (FRulerUnitTime==0) TStart=FStartPos, TEnd=FEndPos;
|
xue@0
|
845 else TStart=FStartPos*1.0/FSamplesPerSec, TEnd=FEndPos*1.0/FSamplesPerSec;
|
xue@0
|
846 double AStart, AEnd;
|
xue@0
|
847 if (FRulerUnitAmp==0) {AStart=-1.0/YZoomRate; AEnd=-AStart;}
|
xue@0
|
848 else {AStart=-(1<<(FBytesPerSample*8-1))/YZoomRate; AEnd=-AStart;}
|
xue@0
|
849 double FStart, FEnd; AnsiString (*ATranslateFreq)(double); void (*AUnit)(double, double&, int&);
|
xue@0
|
850 if (YScale==0)
|
xue@0
|
851 {
|
xue@0
|
852 if (FRulerUnitFreq==0) FStart=FStartDigiFreq*FSamplesPerSec, FEnd=FEndDigiFreq*FSamplesPerSec;
|
xue@0
|
853 else if (FRulerUnitFreq==1) FStart=FStartDigiFreq*FSpecRes, FEnd=FEndDigiFreq*FSpecRes;
|
xue@0
|
854 ATranslateFreq=0; AUnit=0;
|
xue@0
|
855 }
|
xue@0
|
856 else
|
xue@0
|
857 {
|
xue@0
|
858 FStart=12*Log2(WV2_LOG_FREQ(FStartDigiFreq)*FSamplesPerSec/C4), FEnd=12*Log2(WV2_LOG_FREQ(FEndDigiFreq)*FSamplesPerSec/C4);
|
xue@0
|
859 if (FRulerUnitFreq==0) ATranslateFreq=SemitoneToHz;
|
xue@0
|
860 else ATranslateFreq=SemitoneToPitch;
|
xue@0
|
861 AUnit=SemitoneUnit;
|
xue@0
|
862 }
|
xue@0
|
863
|
xue@0
|
864 if (DefaultRulerSetting[Type].pre_drawing)
|
xue@0
|
865 {
|
xue@0
|
866 if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, false);
|
xue@0
|
867 if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) {}
|
xue@0
|
868 if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, false);
|
xue@0
|
869 }
|
xue@0
|
870 switch(Type)
|
xue@0
|
871 {
|
xue@0
|
872 case 0:
|
xue@0
|
873 DrawWaveForm(Channel, Canv, Rect, FStartPos, FEndPos, FYZoomRate, true);
|
xue@0
|
874 break;
|
xue@0
|
875 case 1:
|
xue@0
|
876 case 2:
|
xue@0
|
877 DrawSpectrogramX(Channel, CurrentRange, YScale, Canv, Rect, FSpecAmp, false, true, Type);
|
xue@0
|
878 break;
|
xue@0
|
879 }
|
xue@0
|
880
|
xue@0
|
881 if (FSelections->Count) DrawSelections(Type, Canv, Rect, YScale);
|
xue@0
|
882 if (TWaveViewPanes::FreqAxis(Type) && FTools.Contains(wvtPitchScale)) DrawPitchScale(Type, Canv, Rect, YScale);
|
xue@0
|
883 if (FSectionProgress>0 && FProgressCursor) DrawPlaybackCursor(FSectionProgress, Canv, Rect, Type);
|
xue@0
|
884 {
|
xue@0
|
885 if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, true);
|
xue@0
|
886 if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) DrawRulerV(FEnd, FStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true, ATranslateFreq, AUnit);
|
xue@0
|
887 if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true);
|
xue@0
|
888 }
|
xue@0
|
889
|
xue@0
|
890 SelectClipRgn(Canv->Handle, NULL);
|
xue@0
|
891 DeleteObject(Rgn);
|
xue@0
|
892 }
|
xue@0
|
893
|
xue@0
|
894 void __fastcall TWaveView::DrawPaneInfo(int Channel, int Type, int YScale, TCanvas* Canv, TRect& Rect)
|
xue@0
|
895 {
|
xue@0
|
896 TStringList* List;
|
xue@0
|
897 if (FCustomPaneInfo) List=(TStringList*)FCustomPaneInfo(this);
|
xue@0
|
898 else
|
xue@0
|
899 {
|
xue@0
|
900 List=new TStringList;
|
xue@0
|
901 if (FSelections->Count>0 && FSelections->Focus>=0)
|
xue@0
|
902 {
|
xue@0
|
903 List->Add("Current Selection");
|
xue@0
|
904 List->Add(AnsiString().sprintf("Time: from %d to %d", FSelections->StartPos, FSelections->EndPos));
|
xue@0
|
905 List->Add(AnsiString().sprintf("Frequency: from %.1fhz to %.1fhz", FSelections->StartDigiFreq*FSamplesPerSec, FSelections->EndDigiFreq*FSamplesPerSec));
|
xue@0
|
906 }
|
xue@0
|
907 }
|
xue@0
|
908
|
xue@0
|
909 if (List->Count>0)
|
xue@0
|
910 {
|
xue@0
|
911 Canvas->Font=DefaultPaneInfoFont;
|
xue@0
|
912 int textheight=Canvas->TextHeight("0"), textwidth=Canvas->TextWidth("0");
|
xue@0
|
913 int height=textheight*List->Count+textheight;
|
xue@0
|
914 int width=Canvas->TextWidth(List->Strings[0]); for (int i=1; i<List->Count; i++) {int AW=Canvas->TextWidth(List->Strings[i]); if (width<AW) width=AW;} width+=textwidth*2;
|
xue@0
|
915 int left, right, top, bottom;
|
xue@0
|
916 if (FRulerAlignY==alLeft) {right=Rect.right*0.95+Rect.left*0.05; left=right-width;}
|
xue@0
|
917 else {left=Rect.left*0.95+Rect.right*0.05; right=left+width;}
|
xue@0
|
918 top=Rect.top*0.9+Rect.bottom*0.1; bottom=top+height;
|
xue@0
|
919
|
xue@0
|
920 Canvas->Pen->Style=psClear; Canvas->Pen->Mode=pmMerge; Canvas->Brush->Style=bsSolid;
|
xue@0
|
921 if (Type==0) Canvas->Brush->Color=(TColor)RGB(224, 224, 224);
|
xue@0
|
922 else Canvas->Brush->Color=TColor(clGray/2);
|
xue@0
|
923 Canvas->Rectangle(left, top, right, bottom);
|
xue@0
|
924
|
xue@0
|
925 Canvas->Brush->Style=bsClear;
|
xue@0
|
926 if (Type==0) Canvas->Font->Color=FCursorColorDim;
|
xue@0
|
927 else Canvas->Font->Color=FCursorColorBright;
|
xue@0
|
928 for (int i=0; i<List->Count; i++)
|
xue@0
|
929 {
|
xue@0
|
930 if (FRulerAlignY==alLeft) Canvas->TextOut(right-textwidth-Canvas->TextWidth(List->Strings[i]), top+(i+0.5)*textheight, List->Strings[i]);
|
xue@0
|
931 else Canvas->TextOut(left+textwidth, top+(i+0.5)*textheight, List->Strings[i]);
|
xue@0
|
932 }
|
xue@0
|
933 }
|
xue@0
|
934 delete List;
|
xue@0
|
935 }
|
xue@0
|
936
|
xue@0
|
937 void __fastcall TWaveView::DrawPanes(int Type)
|
xue@0
|
938 {
|
xue@0
|
939 for (int i=0; i<FPanes.Count; i++)
|
xue@0
|
940 {
|
xue@0
|
941 int Content=FPanes.Content[i];
|
xue@0
|
942 if (Content<0) {Canvas->Brush->Color=FBackColor; Canvas->FillRect(FPanes.Rect[i]);}
|
xue@0
|
943 else
|
xue@0
|
944 {
|
xue@0
|
945 int type=Content/WV2_MAX_CHANNEL, channel=Content%WV2_MAX_CHANNEL;
|
xue@0
|
946 if (Type<0 || Type==type) DrawPane(channel, type, FPanes.YScale[i], FPanes.Rulers[i], Canvas, FPanes.Rect[i]);
|
xue@0
|
947 }
|
xue@0
|
948 }
|
xue@0
|
949 if (FCurrentPane>=0 && FShowPaneInfo) DrawPaneInfo(FCurrentPane, FPanes.Type[FCurrentPane], FPanes.YScale[FCurrentPane], Canvas, FPanes.Rect[FCurrentPane]);
|
xue@0
|
950 }
|
xue@0
|
951
|
xue@0
|
952 void __fastcall TWaveView::DrawPitchScale(int Type, TCanvas* Canv, TRect& Rect, int yscale)
|
xue@0
|
953 {
|
xue@0
|
954 int pswidth=100;
|
xue@0
|
955 int NumberOfTicks=25;
|
xue@0
|
956 double endl=0.7;
|
xue@0
|
957 int X=FSTP(CurrentTime, Rect.left, Rect.right);
|
xue@0
|
958 int X1=X-pswidth, X2=X+pswidth;
|
xue@0
|
959 if (X1-Rect.left<(X-Rect.left)*2/3) X1=Rect.left+(X-Rect.left)*2/3;
|
xue@0
|
960 if (Rect.right-X2<(Rect.right-X)*2/3) X2=Rect.right-(Rect.right-X)*2/3;
|
xue@0
|
961 int psl=X1-X;
|
xue@0
|
962 int psr=X2-X;
|
xue@0
|
963
|
xue@0
|
964 double f0=CurrentDigiFreq/FPitchScalePart;
|
xue@0
|
965 int Y0=FDFTP(f0, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
|
xue@0
|
966
|
xue@0
|
967 double f6=f0*(NumberOfTicks+3);
|
xue@0
|
968 int Y6=FDFTP(f6, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
|
xue@0
|
969
|
xue@0
|
970 Canvas->Pen->Color=TColor(clGray/2);
|
xue@0
|
971 Canvas->Pen->Style=psDot;
|
xue@0
|
972 Canvas->MoveTo(X, Y0+5);
|
xue@0
|
973 Canvas->LineTo(X, Y6);
|
xue@0
|
974 Canvas->MoveTo(X1, Y0);
|
xue@0
|
975 Canvas->LineTo(X2, Y0);
|
xue@0
|
976 Canvas->Pen->Color=clGray;
|
xue@0
|
977
|
xue@0
|
978 for (int k=2; k<=NumberOfTicks; k++)
|
xue@0
|
979 {
|
xue@0
|
980 f6=(NumberOfTicks-k*endl+1.0)/NumberOfTicks;
|
xue@0
|
981 X1=X+psl*f6;
|
xue@0
|
982 X2=X+psr*f6;
|
xue@0
|
983 Y6=FDFTP(f0*k, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
|
xue@0
|
984 Canvas->MoveTo(X1, Y6);
|
xue@0
|
985 Canvas->LineTo(X2, Y6);
|
xue@0
|
986 }
|
xue@0
|
987
|
xue@0
|
988 Canvas->Pen->Style=psSolid;
|
xue@0
|
989 }
|
xue@0
|
990
|
xue@0
|
991 void __fastcall TWaveView::DrawPlaybackCursor(int Position, TCanvas* Canv, TRect& Rect, int Type)
|
xue@0
|
992 {
|
xue@0
|
993 int X=FSTP(Position, Rect.left, Rect.right);
|
xue@0
|
994 if (X>=Rect.left && X<Rect.right)
|
xue@0
|
995 {
|
xue@0
|
996 Canv->Pen->Mode=pmCopy;
|
xue@0
|
997 Canv->Pen->Style=psSolid;
|
xue@0
|
998 Canv->Pen->Color=clGreen;
|
xue@0
|
999 if (TWaveViewPanes::FreqAxis(Type))
|
xue@0
|
1000 {
|
xue@0
|
1001 Canv->MoveTo(X, Rect.top*0.5+Rect.bottom*0.5);
|
xue@0
|
1002 Canv->LineTo(X, Rect.bottom);
|
xue@0
|
1003 }
|
xue@0
|
1004 else
|
xue@0
|
1005 {
|
xue@0
|
1006 Canv->MoveTo(X, Rect.top*0.75+Rect.bottom*0.25);
|
xue@0
|
1007 Canv->LineTo(X, Rect.top*0.25+Rect.bottom*0.75);
|
xue@0
|
1008 }
|
xue@0
|
1009 }
|
xue@0
|
1010 }
|
xue@0
|
1011
|
xue@0
|
1012 void __fastcall TWaveView::DrawSelection(int Type, TCanvas* Canv, TRect& Rect, int yscale, int Index, TColor FrameColorX)
|
xue@0
|
1013 {
|
xue@0
|
1014 if (Index<0 || Index>=FSelections->Count) return;
|
xue@0
|
1015 TWaveViewSelection sel=FSelections->Items[Index];
|
xue@0
|
1016
|
xue@0
|
1017 double x1=FSTP(sel.StartPos, Rect.left, Rect.right);
|
xue@0
|
1018 double x2=FSTP(sel.EndPos, Rect.left, Rect.right);
|
xue@0
|
1019
|
xue@0
|
1020 if (!TWaveViewPanes::FreqAxis(Type))
|
xue@0
|
1021 {
|
xue@0
|
1022 Canvas->Pen->Mode=pmCopy;
|
xue@0
|
1023 // Canvas->Pen->Style=psSolid;
|
xue@0
|
1024 Canvas->Pen->Color=FrameColorX;
|
xue@0
|
1025 Canvas->MoveTo(x1, Rect.top); Canvas->LineTo(x1, Rect.bottom);
|
xue@0
|
1026 Canvas->MoveTo(x2, Rect.top); Canvas->LineTo(x2, Rect.bottom);
|
xue@0
|
1027 }
|
xue@0
|
1028 else
|
xue@0
|
1029 {
|
xue@0
|
1030 int y2=ceil(FDFTP(sel.StartDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale));
|
xue@0
|
1031 int y1=floor(FDFTP(sel.EndDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale));
|
xue@0
|
1032 Canvas->Pen->Mode=pmCopy;
|
xue@0
|
1033 // Canvas->Pen->Style=psSolid;
|
xue@0
|
1034 Canvas->Pen->Color=FrameColorX;
|
xue@0
|
1035 Canvas->Brush->Style=bsClear;
|
xue@0
|
1036 if (x1==x2 || y1==y2) {Canvas->MoveTo(x1, y1); Canvas->LineTo(x2, y2);}
|
xue@0
|
1037 else Canvas->Rectangle(x1, y1, x2+1, y2+1);
|
xue@0
|
1038 }
|
xue@0
|
1039 }
|
xue@0
|
1040
|
xue@0
|
1041 void __fastcall TWaveView::DrawSelections(int Type, TCanvas* Canv, TRect& Rect, int yscale)
|
xue@0
|
1042 {
|
xue@0
|
1043 for (int i=0; i<FSelections->Count; i++)
|
xue@0
|
1044 {
|
xue@0
|
1045 if (i==FSelections->Focus && FOpMode<=wopReselect)
|
xue@0
|
1046 Canvas->Pen->Style=psSolid;
|
xue@0
|
1047 else
|
xue@0
|
1048 Canvas->Pen->Style=psDot;
|
xue@0
|
1049 DrawSelection(Type, Canv, Rect, yscale, i, FSelectedFrameColorX);
|
xue@0
|
1050 }
|
xue@0
|
1051 }
|
xue@0
|
1052
|
xue@0
|
1053 void __fastcall TWaveView::DrawSemitones(int start, int end, TCanvas* Canv, TRect& Rect, int yscale)
|
xue@0
|
1054 {
|
xue@0
|
1055 for (int i=start; i<end; i++)
|
xue@0
|
1056 {
|
xue@0
|
1057 int f=FDFTP(440*pow(2, i/12.0)/FSamplesPerSec, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
|
xue@0
|
1058 Canv->Pen->Mode=pmXor;
|
xue@0
|
1059 Canv->Pen->Style=psSolid;
|
xue@0
|
1060 if (i%12==0)
|
xue@0
|
1061 Canv->Pen->Color=clGray;
|
xue@0
|
1062 else
|
xue@0
|
1063 Canv->Pen->Color=TColor(clGray/2);
|
xue@0
|
1064 Canv->MoveTo(0, f);
|
xue@0
|
1065 Canv->LineTo(Width, f);
|
xue@0
|
1066 }
|
xue@0
|
1067 }
|
xue@0
|
1068
|
xue@0
|
1069 void __fastcall TWaveView::DrawSpectrogramX(int channel, TWaveViewSelection Sel, int yscale, TCanvas* ACanvas, TRect ARect, double amp, bool forceresample, bool basic, int specstyle)
|
xue@0
|
1070 {
|
xue@0
|
1071 int dX=ARect.Width(), dY=ARect.Height(), HWid=FSpecRes/2;
|
xue@0
|
1072 double *xx=(double*)malloc8(sizeof(double)*(dX+dY)), *yy=&xx[dX];
|
xue@0
|
1073 FPTS(xx, dX, Sel.StartPos, Sel.EndPos); for (int x=0; x<dX; x++) xx[x]=(xx[x]-HWid)/FSpecOffst;
|
xue@0
|
1074
|
xue@0
|
1075 double framepersample=(Sel.EndPos-Sel.StartPos)*1.0/FSpecOffst/dX;
|
xue@0
|
1076 bool interpolate=(framepersample<1);
|
xue@0
|
1077 int Fr=CalculateSpectrogramX(channel, xx, dX, interpolate);
|
xue@0
|
1078 double ampnorm=1.0/(1<<(BytesPerSample*8-4))/sqrt(1.0*FSpecRes);
|
xue@0
|
1079 if (basic)
|
xue@0
|
1080 {
|
xue@0
|
1081 //draw on the internal bitmap Basic1, ignoring ARect and Sel arguments
|
xue@0
|
1082 //check is the content of Basic1 should be resampled since last time
|
xue@0
|
1083 bool resample=forceresample|(Fr>0);
|
xue@0
|
1084 if (!Basic1[channel])
|
xue@0
|
1085 {
|
xue@0
|
1086 Graphics::TBitmap* NewBmp=new Graphics::TBitmap;
|
xue@0
|
1087 NewBmp->PixelFormat=pf32bit;
|
xue@0
|
1088 NewBmp->Transparent=true;
|
xue@0
|
1089 NewBmp->TransparentMode=tmAuto;
|
xue@0
|
1090 Basic1[channel]=NewBmp;
|
xue@0
|
1091 resample=true;
|
xue@0
|
1092 }
|
xue@0
|
1093 sBasic1Settings BS; BS.X=ARect.Width(), BS.Y=ARect.Height(), BS.Sel=Sel, BS.amp=amp, BS.yscale=yscale, BS.specstyle=specstyle;
|
xue@0
|
1094 if (Basic1Settings[channel]!=BS) {Basic1Settings[channel]=BS; Basic1[channel]->Width=BS.X; Basic1[channel]->Height=BS.Y; resample=true;}
|
xue@0
|
1095
|
xue@0
|
1096 //resample records sampled range change and picture size change
|
xue@0
|
1097 if (resample)
|
xue@0
|
1098 {
|
xue@0
|
1099 if (FAutoSpecAmp) SetAutomaticSpecAmp(channel, xx, Sel.StartDigiFreq, Sel.EndDigiFreq, BS.X, BS.Y);
|
xue@0
|
1100 QSPEC_FORMAT maxvisiblespec;
|
xue@0
|
1101 if (specstyle==1)
|
xue@0
|
1102 {
|
xue@0
|
1103 FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; y<dY; y++) yy[y]=FSpecRes*yy[y];
|
xue@0
|
1104 maxvisiblespec=SampleSpectrogramX(channel, Basic1[channel], xx, yy, BS.X, BS.Y, amp*ampnorm, interpolate);
|
xue@0
|
1105 }
|
xue@0
|
1106 else if (specstyle==2) maxvisiblespec=SamplePeakSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, Basic1[channel], xx, BS.X, BS.Y, amp*ampnorm);
|
xue@0
|
1107 else if (specstyle==3) maxvisiblespec=SampleSinuSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, Basic1[channel], xx, BS.X, BS.Y, amp*ampnorm);
|
xue@0
|
1108 if (!FAutoSpecAmp) maxv_specamp=maxvisiblespec*FSpecAmp;
|
xue@0
|
1109 }
|
xue@0
|
1110 ACanvas->CopyRect(ARect, Basic1[channel]->Canvas, TRect(0, 0, BS.X, BS.Y));
|
xue@0
|
1111 }
|
xue@0
|
1112 else
|
xue@0
|
1113 {
|
xue@0
|
1114 Graphics::TBitmap* bmp=new Graphics::TBitmap;
|
xue@0
|
1115 bmp->PixelFormat=pf32bit; bmp->Width=ARect.Width(); bmp->Height=ARect.Height();
|
xue@0
|
1116 if (specstyle==1)
|
xue@0
|
1117 {
|
xue@0
|
1118 FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; y<dY; y++) yy[y]=FSpecRes*yy[y];
|
xue@0
|
1119 SampleSpectrogramX(channel, bmp, xx, yy, bmp->Width, bmp->Height, amp*ampnorm, interpolate);
|
xue@0
|
1120 }
|
xue@0
|
1121 else if (specstyle==2) SamplePeakSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm);
|
xue@0
|
1122 else if (specstyle==3) SampleSinuSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm);
|
xue@0
|
1123 ACanvas->CopyRect(ARect, bmp->Canvas, TRect(0, 0, bmp->Width, bmp->Height));
|
xue@0
|
1124 delete bmp;
|
xue@0
|
1125 }
|
xue@0
|
1126 free8(xx);
|
xue@0
|
1127 }
|
xue@0
|
1128
|
xue@0
|
1129 void __fastcall DrawWaveForm(TCanvas* Canv, TRect ARect, void* data, int BytesPerSample, int startpos, int endpos, double amp, TColor Color1, TColor Color2)
|
xue@0
|
1130 {
|
xue@0
|
1131 int i, j, X=ARect.Width(), Y=ARect.Height(), Xs=ARect.left, Ys=ARect.top, Y0=Y/2, hundred=100;
|
xue@0
|
1132 double Ymax, Ymin;
|
xue@0
|
1133 int LengthRatio=(endpos-startpos)/X;
|
xue@0
|
1134 Canv->Pen->Color=Color1;
|
xue@0
|
1135
|
xue@0
|
1136 amp=Y*amp/(1<<(BytesPerSample*8));
|
xue@0
|
1137
|
xue@0
|
1138 bool b8=(BytesPerSample==1), b16=(BytesPerSample==2), b24=(BytesPerSample==3);
|
xue@0
|
1139
|
xue@0
|
1140 if (false)
|
xue@0
|
1141 {
|
xue@0
|
1142 unsigned char* Data8=(unsigned char*)data;
|
xue@0
|
1143 Canv->MoveTo(Xs+0, Ys+Y0-(Data8[startpos]-0x80)*amp);
|
xue@0
|
1144 if (LengthRatio<4)
|
xue@0
|
1145 for (i=1; i<X; i++)
|
xue@0
|
1146 Canv->LineTo(Xs+i, Ys+Y0-(Data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp);
|
xue@0
|
1147 else
|
xue@0
|
1148 {
|
xue@0
|
1149 for (i=0; i<X; i++)
|
xue@0
|
1150 {
|
xue@0
|
1151 int localstart=startpos+__int64(endpos-startpos)*i/X;
|
xue@0
|
1152 int vlocal, vlocalmin=Data8[localstart];
|
xue@0
|
1153 int vlocalmax=vlocalmin;
|
xue@0
|
1154
|
xue@0
|
1155 for (j=1; j<LengthRatio; j++)
|
xue@0
|
1156 {
|
xue@0
|
1157 vlocal=Data8[localstart+j];
|
xue@0
|
1158 if (vlocal<vlocalmin) vlocalmin=vlocal;
|
xue@0
|
1159 if (vlocal>vlocalmax) vlocalmax=vlocal;
|
xue@0
|
1160 }
|
xue@0
|
1161 Ymax=Y0-(vlocalmin-0x80)*amp;
|
xue@0
|
1162 Ymin=Y0-(vlocalmax-0x80)*amp;
|
xue@0
|
1163 if (Canv->PenPos.y*2>Ymin+Ymax)
|
xue@0
|
1164 {
|
xue@0
|
1165 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1166 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1167 }
|
xue@0
|
1168 else
|
xue@0
|
1169 {
|
xue@0
|
1170 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1171 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1172 }
|
xue@0
|
1173 }
|
xue@0
|
1174 }
|
xue@0
|
1175 }
|
xue@0
|
1176 else
|
xue@0
|
1177 {
|
xue@0
|
1178 unsigned __int8* data8; __int16* data16; __pint24 data24;
|
xue@0
|
1179
|
xue@0
|
1180 if (b16) {data16=(__int16*)data; Canv->MoveTo(Xs, Ys+Y0-data16[startpos]*amp);}
|
xue@0
|
1181 else if (b24) {data24=(__pint24)data; Canv->MoveTo(Xs, Ys+Y0-data24[startpos]*amp);}
|
xue@0
|
1182 else if (b8) {data8=(unsigned __int8*)data; Canv->MoveTo(Xs, Ys+Y0-(data8[startpos]-0x80)*amp);}
|
xue@0
|
1183
|
xue@0
|
1184 if (LengthRatio<1)
|
xue@0
|
1185 for (i=1; i<X; i++)
|
xue@0
|
1186 {
|
xue@0
|
1187 if (b16) Canv->LineTo(Xs+i, Ys+Y0-data16[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp);
|
xue@0
|
1188 else if (b24) Canv->LineTo(Xs+i, Ys+Y0-data24[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp);
|
xue@0
|
1189 else if (b8) Canv->LineTo(Xs+i, Ys+Y0-(data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp);
|
xue@0
|
1190 }
|
xue@0
|
1191 else
|
xue@0
|
1192 {
|
xue@0
|
1193 for (i=0; i<X; i++)
|
xue@0
|
1194 {
|
xue@0
|
1195 int vlocalmin, vlocalmax;
|
xue@0
|
1196 int localstart=startpos+__int64(endpos-startpos)*i/X;
|
xue@0
|
1197 int vlocal, jump=LengthRatio/hundred+1;
|
xue@0
|
1198 if (b16) vlocalmin=vlocalmax=data16[localstart];
|
xue@0
|
1199 else if (b24) vlocalmin=vlocalmax=data24[localstart]; //(*data24)[localstart];
|
xue@0
|
1200 else if (b8) vlocalmin=vlocalmax=data8[localstart]-0x80;
|
xue@0
|
1201 for (j=LengthRatio-1; j>0; j-=jump)
|
xue@0
|
1202 {
|
xue@0
|
1203 if (b16) vlocal=data16[localstart+j];
|
xue@0
|
1204 else if (b24) vlocal=data24[localstart+j]; //(*data24)[localstart+j];
|
xue@0
|
1205 else if (b8) vlocal=data8[localstart+j]-0x80;
|
xue@0
|
1206 if (vlocal<vlocalmin) vlocalmin=vlocal;
|
xue@0
|
1207 if (vlocal>vlocalmax) vlocalmax=vlocal;
|
xue@0
|
1208 }
|
xue@0
|
1209 double rmin=vlocalmin*amp, rmax=vlocalmax*amp;
|
xue@0
|
1210 Ymax=Y0-rmin, Ymin=Y0-rmax;
|
xue@0
|
1211 if (rmin<0 && rmax>0)
|
xue@0
|
1212 {
|
xue@0
|
1213 int Y1=(rmax-rmin)/4;
|
xue@0
|
1214 int Y2=Y0+Y1;
|
xue@0
|
1215 Y1=Y0-Y1;
|
xue@0
|
1216 if (Canv->PenPos.y*2>Ymin+Ymax)
|
xue@0
|
1217 {
|
xue@0
|
1218 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1219 Canv->LineTo(Xs+i, Ys+Y2);
|
xue@0
|
1220 Canv->Pen->Color=Color2;
|
xue@0
|
1221 Canv->LineTo(Xs+i, Ys+Y1);
|
xue@0
|
1222 Canv->Pen->Color=Color1;
|
xue@0
|
1223 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1224 }
|
xue@0
|
1225 else
|
xue@0
|
1226 {
|
xue@0
|
1227 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1228 Canv->LineTo(Xs+i, Ys+Y1);
|
xue@0
|
1229 Canv->Pen->Color=Color2;
|
xue@0
|
1230 Canv->LineTo(Xs+i, Ys+Y2);
|
xue@0
|
1231 Canv->Pen->Color=Color1;
|
xue@0
|
1232 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1233 }
|
xue@0
|
1234 }
|
xue@0
|
1235 else
|
xue@0
|
1236 {
|
xue@0
|
1237 if (Canv->PenPos.y*2>Ymin+Ymax)
|
xue@0
|
1238 {
|
xue@0
|
1239 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1240 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1241 }
|
xue@0
|
1242 else
|
xue@0
|
1243 {
|
xue@0
|
1244 Canv->LineTo(Xs+i, Ys+Ymin);
|
xue@0
|
1245 Canv->LineTo(Xs+i, Ys+Ymax);
|
xue@0
|
1246 }
|
xue@0
|
1247 }
|
xue@0
|
1248 }
|
xue@0
|
1249 }
|
xue@0
|
1250 }
|
xue@0
|
1251 }
|
xue@0
|
1252
|
xue@0
|
1253 /*
|
xue@0
|
1254 The internal bitmap Basic0 is used to contain the default waveform bitmap.
|
xue@0
|
1255 Whenever this method is called with FCanvas assigned to ACanvas, it draws the
|
xue@0
|
1256 waveform of the current section to Basic1, regardless of AStartPos or AnEndPos.
|
xue@0
|
1257 */
|
xue@0
|
1258 void __fastcall TWaveView::DrawWaveForm(int channel, TCanvas* ACanvas, TRect ARect, int AStartPos, int AnEndPos, double amp, bool basic)
|
xue@0
|
1259 {
|
xue@0
|
1260 if (AnEndPos<=AStartPos) return;
|
xue@0
|
1261 TRect bmpRect;
|
xue@0
|
1262 Graphics::TBitmap* bmp;
|
xue@0
|
1263 if (basic)
|
xue@0
|
1264 {
|
xue@0
|
1265 bool resample=false;
|
xue@0
|
1266 if (!Basic0[channel])
|
xue@0
|
1267 {
|
xue@0
|
1268 Graphics::TBitmap* NewBmp=new Graphics::TBitmap;
|
xue@0
|
1269 NewBmp->PixelFormat=pf32bit;
|
xue@0
|
1270 NewBmp->Transparent=true;
|
xue@0
|
1271 NewBmp->TransparentMode=tmFixed;
|
xue@0
|
1272 Basic0[channel]=NewBmp;
|
xue@0
|
1273 resample=true;
|
xue@0
|
1274 }
|
xue@0
|
1275 sBasic0Settings BS={ARect.Width(), ARect.Height(), FStartPos, FEndPos, FYZoomRate};
|
xue@0
|
1276 if (Basic0Settings[channel]!=BS)
|
xue@0
|
1277 {
|
xue@0
|
1278 Basic0Settings[channel]=BS;
|
xue@0
|
1279 Basic0[channel]->Width=BS.X;
|
xue@0
|
1280 Basic0[channel]->Height=BS.Y;
|
xue@0
|
1281 resample=true;
|
xue@0
|
1282 }
|
xue@0
|
1283 if (!resample)
|
xue@0
|
1284 {
|
xue@0
|
1285 ACanvas->CopyRect(ARect, Basic0[channel]->Canvas, TRect(0, 0, BS.X, BS.Y));
|
xue@0
|
1286 // ACanvas->Draw(ARect.left, ARect.top, Basic0[channel]);
|
xue@0
|
1287 return;
|
xue@0
|
1288 }
|
xue@0
|
1289 AStartPos=FStartPos, AnEndPos=FEndPos;
|
xue@0
|
1290 bmp=Basic0[channel];
|
xue@0
|
1291 bmpRect=TRect(0, 0, BS.X, BS.Y);
|
xue@0
|
1292 }
|
xue@0
|
1293 else
|
xue@0
|
1294 {
|
xue@0
|
1295 bmp=new Graphics::TBitmap;
|
xue@0
|
1296 bmp->PixelFormat=pf32bit;
|
xue@0
|
1297 bmp->Width=ARect.Width();
|
xue@0
|
1298 bmp->Height=ARect.Height();
|
xue@0
|
1299 bmpRect=TRect(0, 0, bmp->Width, bmp->Height);
|
xue@0
|
1300 }
|
xue@0
|
1301
|
xue@0
|
1302 TCanvas* Canv=bmp->Canvas;
|
xue@0
|
1303 if (ACanvas==Canvas) Canv->CopyRect(bmpRect, ACanvas, ARect);
|
xue@0
|
1304 else {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(bmpRect);}
|
xue@0
|
1305 Canv->Pen->Mode=pmCopy;
|
xue@0
|
1306 Canv->Pen->Style=psSolid;
|
xue@0
|
1307 int Y=bmpRect.Height(), X=bmpRect.Width(), Y0=Y/2;
|
xue@0
|
1308 Canv->Pen->Color=FAxisColor; Canv->MoveTo(0, Y0); Canv->LineTo(X, Y0);
|
xue@0
|
1309 ::DrawWaveForm(Canv, bmpRect, FData[channel], FBytesPerSample, AStartPos, AnEndPos, FYZoomRate, FWaveColor, FWaveColor2);
|
xue@0
|
1310
|
xue@0
|
1311 ACanvas->CopyRect(ARect, Canv, bmpRect);
|
xue@0
|
1312 if (!basic) delete bmp;
|
xue@0
|
1313 }
|
xue@0
|
1314
|
xue@0
|
1315 //Call this when the waveview data buffer is updated externally
|
xue@0
|
1316 void __fastcall TWaveView::ExtDataChange(TObject* Sender)
|
xue@0
|
1317 {
|
xue@0
|
1318 ClearSpectrograms();
|
xue@0
|
1319 InvalidateBasic(-1, 0);
|
xue@0
|
1320 }
|
xue@0
|
1321
|
xue@0
|
1322 void __fastcall TWaveView::ExtDataChange(TObject* Sender, int Channel, int From, int To)
|
xue@0
|
1323 {
|
xue@0
|
1324 FSpectrogram[Channel]->Invalidate(From, To);
|
xue@0
|
1325 InvalidateBasic(Channel, 0);
|
xue@0
|
1326 Invalidate();
|
xue@0
|
1327 }
|
xue@0
|
1328
|
xue@0
|
1329 void WaveViewPlayLoadFrame(double* frame, int n, int readfrom, char* data, int bps, int datalen, int datast, int dataen, bool loop, double* win, double* &loopframe)
|
xue@0
|
1330 {
|
xue@0
|
1331 int hn=n/2;
|
xue@0
|
1332 if (readfrom+n<dataen) IntToDouble2416(frame, &data[readfrom*bps], bps, n);
|
xue@0
|
1333 else if (readfrom<dataen)
|
xue@0
|
1334 {
|
xue@0
|
1335 IntToDouble2416(frame, &data[readfrom*bps], bps, dataen-readfrom);
|
xue@0
|
1336 }
|
xue@0
|
1337 else memset(frame, 0, sizeof(double)*n); //this line shall never be reached
|
xue@0
|
1338
|
xue@0
|
1339 if (readfrom+n>dataen-hn)
|
xue@0
|
1340 {
|
xue@0
|
1341 if (!loop)
|
xue@0
|
1342 {
|
xue@0
|
1343
|
xue@0
|
1344 if (readfrom>dataen-hn)
|
xue@0
|
1345 {
|
xue@0
|
1346 double* lwin=&win[n-(dataen-readfrom)];
|
xue@0
|
1347 for (int i=0; i<dataen-readfrom; i++) frame[i]*=lwin[i];
|
xue@0
|
1348 }
|
xue@0
|
1349 else if (readfrom>dataen-n)
|
xue@0
|
1350 {
|
xue@0
|
1351 double* lwin=&win[n-(dataen-readfrom)];
|
xue@0
|
1352 for (int i=dataen-hn-readfrom; i<dataen-readfrom; i++) frame[i]*=lwin[i];
|
xue@0
|
1353 }
|
xue@0
|
1354 else
|
xue@0
|
1355 {
|
xue@0
|
1356 double *lframe=&frame[dataen-hn-readfrom], *lwin=&win[hn];
|
xue@0
|
1357 for (int i=0; i<hn; i++) lframe[i]*=lwin[i];
|
xue@0
|
1358 }
|
xue@0
|
1359 }
|
xue@0
|
1360 else if (readfrom+n>dataen-hn/2) //notice it is during looped playback
|
xue@0
|
1361 {
|
xue@0
|
1362 if (readfrom>dataen-hn/2 && loopframe)
|
xue@0
|
1363 {
|
xue@0
|
1364 memcpy(frame, &loopframe[readfrom-(dataen-hn/2)], sizeof(double)*(hn-readfrom+dataen-hn/2));
|
xue@0
|
1365 IntToDouble2416(&frame[dataen-readfrom+hn/2], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2);
|
xue@0
|
1366 }
|
xue@0
|
1367 else if (readfrom+hn>dataen-hn/2 && loopframe)
|
xue@0
|
1368 {
|
xue@0
|
1369 memcpy(&frame[dataen-hn/2-readfrom], loopframe, sizeof(double)*hn);
|
xue@0
|
1370 IntToDouble2416(&frame[dataen+hn/2-readfrom], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2);
|
xue@0
|
1371 }
|
xue@0
|
1372 else
|
xue@0
|
1373 {
|
xue@0
|
1374 //calculate loopframe, of size hn
|
xue@0
|
1375 free8(loopframe);
|
xue@0
|
1376 loopframe=(double*)malloc8(sizeof(double)*n);
|
xue@0
|
1377 double* looped=&loopframe[hn];
|
xue@0
|
1378 if (dataen+hn/2<=datalen) IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, hn);
|
xue@0
|
1379 else
|
xue@0
|
1380 {
|
xue@0
|
1381 IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, datalen-(dataen-hn/2));
|
xue@0
|
1382 memset(&loopframe[datalen-(dataen-hn/2)], 0, sizeof(double)*(dataen+hn/2-datalen));
|
xue@0
|
1383 }
|
xue@0
|
1384 if (datast>hn/2) IntToDouble2416(looped, &data[(datast-hn/2)*bps], bps, hn);
|
xue@0
|
1385 else
|
xue@0
|
1386 {
|
xue@0
|
1387 memset(looped, 0, sizeof(double)*(hn/2-datast));
|
xue@0
|
1388 IntToDouble2416(&looped[hn/2-datast], data, bps, datast+hn/2);
|
xue@0
|
1389 }
|
xue@0
|
1390 for (int i=0; i<hn; i++) loopframe[i]=loopframe[i]*(1-win[i])+looped[i]*(win[i]);
|
xue@0
|
1391
|
xue@0
|
1392 memcpy(&frame[dataen-readfrom-hn/2], loopframe, sizeof(double)*(readfrom+n-(dataen-hn/2)));
|
xue@0
|
1393 }
|
xue@0
|
1394 }
|
xue@0
|
1395 }
|
xue@0
|
1396 else if (loop && readfrom<datast+hn/2 && loopframe)
|
xue@0
|
1397 {
|
xue@0
|
1398 memcpy(frame, &loopframe[hn/2+readfrom-datast], sizeof(double)*(hn/2-readfrom+datast));
|
xue@0
|
1399 }
|
xue@0
|
1400 }
|
xue@0
|
1401
|
xue@0
|
1402 //playback filter used for unbuffered play has in-frame time alias
|
xue@0
|
1403 int __fastcall TWaveView::FillBlock(void* ABlock)
|
xue@0
|
1404 {
|
xue@0
|
1405 char* Block=(char*)ABlock;
|
xue@0
|
1406 FSectionBlocks++;
|
xue@0
|
1407 bool stereo=(FSection->Channels==2);
|
xue@0
|
1408 int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2;
|
xue@0
|
1409
|
xue@0
|
1410 int BlockSize=FSection->BlockSize/PlayBytesPerSample/FSection->Channels;
|
xue@0
|
1411 if (LoopPlay && LoopMode)
|
xue@0
|
1412 {
|
xue@0
|
1413 if (LoopMode==1) //loop visible
|
xue@0
|
1414 FSectionStartPos=FStartPos, FSectionEndPos=FEndPos;
|
xue@0
|
1415 else if (LoopMode==2)//loop selection
|
xue@0
|
1416 FSectionStartPos=FSelections->StartPos, FSectionEndPos=FSelections->EndPos;
|
xue@0
|
1417 if (PBPR<FSectionStartPos) PBPR=FSectionStartPos, ForceOLA=true;
|
xue@0
|
1418 }
|
xue@0
|
1419
|
xue@0
|
1420 char *lData0, *lData1;
|
xue@0
|
1421
|
xue@0
|
1422 if (stereo)
|
xue@0
|
1423 {
|
xue@0
|
1424 if (FStereoMode==wvpSwap) lData0=(char*)FData[1], lData1=(char*)FData[0];
|
xue@0
|
1425 else lData0=(char*)FData[0], lData1=(char*)FData[1];
|
xue@0
|
1426 }
|
xue@0
|
1427 else lData0=(char*)((FChannels>1 && FStereoMode==wvpRight)?FData[1]:FData[0]);
|
xue@0
|
1428
|
xue@0
|
1429 int Wid=FSpecRes, HWid=Wid/2;
|
xue@0
|
1430 while (PBPA<BlockSize && PBPR<FSectionEndPos)
|
xue@0
|
1431 {
|
xue@0
|
1432 int newPBPR=PBPR+HWid, newPBPA;
|
xue@0
|
1433 if (newPBPR>=FSectionEndPos)
|
xue@0
|
1434 {
|
xue@0
|
1435 if (!LoopPlay) newPBPR=FSectionEndPos, newPBPA=PBPA+FSectionEndPos-PBPR;
|
xue@0
|
1436 else newPBPR=newPBPR-FSectionEndPos+FSectionStartPos, newPBPA=PBPA+HWid;// looping=true;
|
xue@0
|
1437 }
|
xue@0
|
1438 else newPBPA=PBPA+HWid;
|
xue@0
|
1439
|
xue@0
|
1440 double k=GetFMask(famp, PBPR, FPlaybackFilter);
|
xue@0
|
1441
|
xue@0
|
1442 if (k==0)
|
xue@0
|
1443 {
|
xue@0
|
1444 if (prevk==1)
|
xue@0
|
1445 {
|
xue@0
|
1446 for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]*=fw2[HWid+i];
|
xue@0
|
1447 if (stereo) for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]*=fw2[HWid+i];
|
xue@0
|
1448 }
|
xue@0
|
1449 memset(&PlayBuffer0[PBPA+HWid], 0, sizeof(double)*HWid);
|
xue@0
|
1450 if (stereo) memset(&PlayBuffer1[PBPA+HWid], 0, sizeof(double)*HWid);
|
xue@0
|
1451 }
|
xue@0
|
1452 else
|
xue@0
|
1453 {
|
xue@0
|
1454 double* dbfx=(double*)fx;
|
xue@0
|
1455 WaveViewPlayLoadFrame(dbfx, Wid, PBPR, lData0, FBytesPerSample, FLength, FSectionStartPos, FSectionEndPos, LoopPlay, fw2, loopframe0);
|
xue@0
|
1456
|
xue@0
|
1457 //filtering
|
xue@0
|
1458 if (k!=1)
|
xue@0
|
1459 {
|
xue@0
|
1460 RFFTCW(dbfx, fw1, NULL, NULL, Log2(Wid), fw, fx, fhbi);
|
xue@0
|
1461 for (int i=0; i<=HWid; i++) fx[i].x*=famp[i], fx[i].y*=famp[i];
|
xue@0
|
1462 CIFFTR(fx, Log2(Wid), fw, dbfx, fhbi);
|
xue@0
|
1463 }
|
xue@0
|
1464
|
xue@0
|
1465 //first half frame
|
xue@0
|
1466 if (k==1 && prevk==1 && !ForceOLA) {}
|
xue@0
|
1467 else
|
xue@0
|
1468 {
|
xue@0
|
1469 if (prevk==1) for(int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]*=fw2[HWid+i];
|
xue@0
|
1470 if (k==1) for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]+=dbfx[i]*fw2[i];
|
xue@0
|
1471 else for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]+=dbfx[i]*fw2_fw1[i];
|
xue@0
|
1472 ForceOLA=false;
|
xue@0
|
1473 }
|
xue@0
|
1474
|
xue@0
|
1475 //second half frame
|
xue@0
|
1476 if (k==1) for (int i=HWid; i<Wid; i++) PlayBuffer0[PBPA+i]=dbfx[i];
|
xue@0
|
1477 else for (int i=HWid; i<Wid; i++) PlayBuffer0[PBPA+i]=dbfx[i]*fw2_fw1[i];
|
xue@0
|
1478
|
xue@0
|
1479 if (stereo)
|
xue@0
|
1480 {
|
xue@0
|
1481 //load frame
|
xue@0
|
1482 WaveViewPlayLoadFrame(dbfx, Wid, PBPR, lData1, FBytesPerSample, FLength, FSectionStartPos, FSectionEndPos, LoopPlay, fw2, loopframe1);
|
xue@0
|
1483
|
xue@0
|
1484 //filtering
|
xue@0
|
1485 if (k!=1)
|
xue@0
|
1486 {
|
xue@0
|
1487 RFFTCW(dbfx, fw1, NULL, NULL, Log2(Wid), fw, fx, fhbi);
|
xue@0
|
1488 for (int i=0; i<=HWid; i++) fx[i].x*=famp[i], fx[i].y*=famp[i];
|
xue@0
|
1489 CIFFTR(fx, Log2(Wid), fw, dbfx, fhbi);
|
xue@0
|
1490 }
|
xue@0
|
1491
|
xue@0
|
1492 //first half frame
|
xue@0
|
1493 if (k==1 && prevk==1 && !ForceOLA) {}
|
xue@0
|
1494 else
|
xue@0
|
1495 {
|
xue@0
|
1496 if (prevk==1) for(int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]*=fw2[HWid+i];
|
xue@0
|
1497 if (k==1) for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]+=dbfx[i]*fw2[i];
|
xue@0
|
1498 else for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]+=dbfx[i]*fw2_fw1[i];
|
xue@0
|
1499 }
|
xue@0
|
1500
|
xue@0
|
1501 //second half frame
|
xue@0
|
1502 if (k==1) for (int i=HWid; i<Wid; i++) PlayBuffer1[PBPA+i]=dbfx[i];
|
xue@0
|
1503 else for (int i=HWid; i<Wid; i++) PlayBuffer1[PBPA+i]=dbfx[i]*fw2_fw1[i];
|
xue@0
|
1504 }
|
xue@0
|
1505 }
|
xue@0
|
1506 PBPR=newPBPR;
|
xue@0
|
1507 PBPA=newPBPA;
|
xue@0
|
1508 prevk=k;
|
xue@0
|
1509 }
|
xue@0
|
1510
|
xue@0
|
1511 if (stereo) DoubleToIntInterleave(Block, PlayBytesPerSample, &PlayBuffer0[PBPW], &PlayBuffer1[PBPW], BlockSize);
|
xue@0
|
1512 else DoubleToInt(Block, PlayBytesPerSample, &PlayBuffer0[PBPW], BlockSize);
|
xue@0
|
1513
|
xue@0
|
1514 PBPW+=BlockSize;
|
xue@0
|
1515 if (PBPA-PBPW<BlockSize)
|
xue@0
|
1516 {
|
xue@0
|
1517 if (PBPA-PBPW+HWid>0)
|
xue@0
|
1518 {
|
xue@0
|
1519 memmove(PlayBuffer0, &PlayBuffer0[PBPW], sizeof(double)*(PBPA-PBPW+HWid));
|
xue@0
|
1520 if (stereo) memmove(PlayBuffer1, &PlayBuffer1[PBPW], sizeof(double)*(PBPA-PBPW+HWid));
|
xue@0
|
1521 }
|
xue@0
|
1522 PBPA-=PBPW; PBPW=0;
|
xue@0
|
1523 }
|
xue@0
|
1524 if (PBPA>0) return FSection->BlockSize;
|
xue@0
|
1525 else return (BlockSize+PBPA)*PlayBytesPerSample*FSection->Channels;
|
xue@0
|
1526 }
|
xue@0
|
1527
|
xue@0
|
1528 void __fastcall TWaveView::FMenuPopup(TObject* Sender)
|
xue@0
|
1529 {
|
xue@0
|
1530 ItemExtract->Visible=(FLength>0 && FSelections->Count>0 && FSelections->Focus>=0);
|
xue@0
|
1531 ItemPlay->Visible=(FLength>0);
|
xue@0
|
1532 ItemProperty->Visible=(FLength>0);
|
xue@0
|
1533 ItemXZoomRestore->Visible=(FLength>0 && (FStartPos!=0 || FEndPos!=FLength));
|
xue@0
|
1534 bool hfa=FPanes.HasFreqAxis[FCurrentPane];
|
xue@0
|
1535 ItemYZoomRestore->Visible=(FLength>0 && (!hfa && YZoomRate!=1 || hfa && (FStartDigiFreq!=0 || FEndDigiFreq!=0.5)));
|
xue@0
|
1536 }
|
xue@0
|
1537
|
xue@0
|
1538 void __fastcall TWaveView::FocusSelection(int Index)
|
xue@0
|
1539 {
|
xue@0
|
1540 if (Index>=0 && Index<FSelections->Count && Index!=FSelections->Focus)
|
xue@0
|
1541 {
|
xue@0
|
1542 FSelections->Focus=Index;
|
xue@0
|
1543 if (FOnSelectedChange) FOnSelectedChange(this);
|
xue@0
|
1544 Invalidate();
|
xue@0
|
1545 }
|
xue@0
|
1546 }
|
xue@0
|
1547
|
xue@0
|
1548 void __fastcall TWaveView::FreeData(int ch)
|
xue@0
|
1549 {
|
xue@0
|
1550 if (ch>=FChannels || ch<0)
|
xue@0
|
1551 {
|
xue@0
|
1552 for (int i=0; i<FChannels; i++)
|
xue@0
|
1553 {
|
xue@0
|
1554 delete[] FData[i];
|
xue@0
|
1555 FData[i]=0;
|
xue@0
|
1556 }
|
xue@0
|
1557 }
|
xue@0
|
1558 else
|
xue@0
|
1559 {
|
xue@0
|
1560 delete[] FData[ch];
|
xue@0
|
1561 FData[ch]=0;
|
xue@0
|
1562 }
|
xue@0
|
1563 }
|
xue@0
|
1564
|
xue@0
|
1565 void __fastcall TWaveView::FreeInternalBitmaps(int ch)
|
xue@0
|
1566 {
|
xue@0
|
1567 if (ch>=FChannels || ch<0)
|
xue@0
|
1568 {
|
xue@0
|
1569 for (int i=0; i<FChannels; i++)
|
xue@0
|
1570 {
|
xue@0
|
1571 delete Basic0[i]; Basic0[i]=0;
|
xue@0
|
1572 delete Basic1[i]; Basic1[i]=0;
|
xue@0
|
1573 }
|
xue@0
|
1574 }
|
xue@0
|
1575 else
|
xue@0
|
1576 {
|
xue@0
|
1577 delete Basic0[ch]; Basic0[ch]=0;
|
xue@0
|
1578 delete Basic1[ch]; Basic1[ch]=0;
|
xue@0
|
1579 }
|
xue@0
|
1580 }
|
xue@0
|
1581
|
xue@0
|
1582 void __fastcall TWaveView::FreeSpectrograms()
|
xue@0
|
1583 {
|
xue@0
|
1584 for (int i=0; i<WV2_MAX_CHANNEL; i++)
|
xue@0
|
1585 {
|
xue@0
|
1586 delete FSpectrogram[i]; FSpectrogram[i]=0;
|
xue@0
|
1587 }
|
xue@0
|
1588 }
|
xue@0
|
1589
|
xue@0
|
1590 double __fastcall TWaveView::FromAmplitudeToPixel(int PaneIndex, double Amplitude)
|
xue@0
|
1591 {
|
xue@0
|
1592 if (FPanes.Type[PaneIndex]) return 0;
|
xue@0
|
1593 int top=FPanes.Rect[PaneIndex].top, height=FPanes.Rect[PaneIndex].Height();
|
xue@0
|
1594 if (FBytesPerSample==0) Amplitude-=128;
|
xue@0
|
1595 return top+height/2-Amplitude*YZoomRate*height/(1<<(FBytesPerSample*8));
|
xue@0
|
1596 }
|
xue@0
|
1597
|
xue@0
|
1598 double __fastcall TWaveView::FromPixelToAmplitude(int PaneIndex, double Y)
|
xue@0
|
1599 {
|
xue@0
|
1600 if (FPanes.Type[PaneIndex]) return 0;
|
xue@0
|
1601 int top=FPanes.Rect[PaneIndex].top, height=FPanes.Rect[PaneIndex].Height();
|
xue@0
|
1602 double ap=-1.0*(Y-(top+height/2))/height;
|
xue@0
|
1603 double result=(1<<(FBytesPerSample*8))*ap/YZoomRate;
|
xue@0
|
1604 if (FBytesPerSample==1) result+=128;
|
xue@0
|
1605 return result;
|
xue@0
|
1606 }
|
xue@0
|
1607
|
xue@0
|
1608 double __fastcall TWaveView::FromDigiFreqToPixel(int PaneIndex, double DigiFreq)
|
xue@0
|
1609 {
|
xue@0
|
1610 if (FEndDigiFreq-FStartDigiFreq<=0) return 0;
|
xue@0
|
1611 if (!FPanes.HasFreqAxis[PaneIndex]) return 0;
|
xue@0
|
1612 if (FPanes.YScale[PaneIndex]==1) //log scale
|
xue@0
|
1613 {
|
xue@0
|
1614 double AStartDigiFreq=WV2_LOG_FREQ(FStartDigiFreq),
|
xue@0
|
1615 AnEndDigiFreq=WV2_LOG_FREQ(FEndDigiFreq);
|
xue@0
|
1616 DigiFreq=WV2_LOG_FREQ(DigiFreq);
|
xue@0
|
1617 return FPanes.Rect[PaneIndex].top+FPanes.Rect[PaneIndex].Height()*log(DigiFreq/AnEndDigiFreq)/log(AStartDigiFreq/AnEndDigiFreq);
|
xue@0
|
1618 }
|
xue@0
|
1619 else
|
xue@0
|
1620 return FPanes.Rect[PaneIndex].top+FPanes.Rect[PaneIndex].Height()*(DigiFreq-FEndDigiFreq)/(FStartDigiFreq-FEndDigiFreq);
|
xue@0
|
1621 }
|
xue@0
|
1622
|
xue@0
|
1623 double __fastcall TWaveView::FromDigiFreqToPixel(double DigiFreq, double AStartDigiFreq, double AnEndDigiFreq, int Y1, int Y2, int YScale)
|
xue@0
|
1624 {
|
xue@0
|
1625 if (FEndDigiFreq-FStartDigiFreq<=0) return 0;
|
xue@0
|
1626 if (YScale==1) //log scale
|
xue@0
|
1627 {
|
xue@0
|
1628 AStartDigiFreq=WV2_LOG_FREQ(AStartDigiFreq),
|
xue@0
|
1629 AnEndDigiFreq=WV2_LOG_FREQ(AnEndDigiFreq);
|
xue@0
|
1630 DigiFreq=WV2_LOG_FREQ(DigiFreq);
|
xue@0
|
1631 return Y1+(Y2-Y1)*log(DigiFreq/AnEndDigiFreq)/log(AStartDigiFreq/AnEndDigiFreq);
|
xue@0
|
1632 }
|
xue@0
|
1633 else
|
xue@0
|
1634 return Y1+(Y2-Y1)*(DigiFreq-AnEndDigiFreq)/(AStartDigiFreq-AnEndDigiFreq);
|
xue@0
|
1635 }
|
xue@0
|
1636
|
xue@0
|
1637 double __fastcall TWaveView::FromPixelToDigiFreq(int PaneIndex, double Y)
|
xue@0
|
1638 {
|
xue@0
|
1639 if (FEndDigiFreq-FStartDigiFreq<0) return 0;
|
xue@0
|
1640 if (!FPanes.HasFreqAxis[PaneIndex]) return 0;
|
xue@0
|
1641 double ap=1.0*(Y-FPanes.Rect[PaneIndex].top)/FPanes.Rect[PaneIndex].Height();
|
xue@0
|
1642 if (FPanes.YScale[PaneIndex]==1) //log scale
|
xue@0
|
1643 {
|
xue@0
|
1644 double AStartDigiFreq=WV2_LOG_FREQ(FStartDigiFreq),
|
xue@0
|
1645 AnEndDigiFreq=WV2_LOG_FREQ(FEndDigiFreq);
|
xue@0
|
1646 return AnEndDigiFreq*pow(AStartDigiFreq/AnEndDigiFreq, ap);
|
xue@0
|
1647 }
|
xue@0
|
1648 else
|
xue@0
|
1649 return FEndDigiFreq+(FStartDigiFreq-FEndDigiFreq)*ap;
|
xue@0
|
1650 }
|
xue@0
|
1651
|
xue@0
|
1652 void __fastcall TWaveView::FromPixelToDigiFreq(int YScale, double* DigiFreq, int Count, double AStartDigiFreq, double AnEndDigiFreq)
|
xue@0
|
1653 {
|
xue@0
|
1654 if (FEndDigiFreq-FStartDigiFreq<0) {memset (DigiFreq, 0, sizeof(double)*Count); return;}
|
xue@0
|
1655 if (YScale==0) //linear scale
|
xue@0
|
1656 {
|
xue@0
|
1657 double StartEndDigiFreq=(AnEndDigiFreq-AStartDigiFreq)/Count;
|
xue@0
|
1658 double AS=AStartDigiFreq+StartEndDigiFreq*0.5;
|
xue@0
|
1659 for (int i=0; i<Count; i++) DigiFreq[i]=AS+StartEndDigiFreq*i;
|
xue@0
|
1660 }
|
xue@0
|
1661 else if (YScale==1) //log scale
|
xue@0
|
1662 {
|
xue@0
|
1663 if (AStartDigiFreq<WV2_MIN_LOG_FREQ) AStartDigiFreq=WV2_MIN_LOG_FREQ;
|
xue@0
|
1664 if (AnEndDigiFreq<WV2_MIN_LOG_FREQ) AnEndDigiFreq=WV2_MIN_LOG_FREQ;
|
xue@0
|
1665 double StartEndDigiFreq=pow(AnEndDigiFreq/AStartDigiFreq, 1.0/Count);
|
xue@0
|
1666 for (int i=0; i<Count; i++) DigiFreq[i]=AStartDigiFreq*pow(StartEndDigiFreq, i+0.5);
|
xue@0
|
1667 }
|
xue@0
|
1668 }
|
xue@0
|
1669
|
xue@0
|
1670 double __fastcall TWaveView::FromPixelToSample(int PaneIndex, double X)
|
xue@0
|
1671 {
|
xue@0
|
1672 if (PaneIndex<0) return 0;
|
xue@0
|
1673 if (FEndPos-FStartPos<0) return 0;
|
xue@0
|
1674 else if (FEndPos-FStartPos==0) return FStartPos;
|
xue@0
|
1675 else return FStartPos+(X-FPanes.Rect[PaneIndex].left)*(FEndPos-FStartPos)/FPanes.Rect[PaneIndex].Width();
|
xue@0
|
1676 }
|
xue@0
|
1677
|
xue@0
|
1678 double __fastcall TWaveView::FromPixelToSample(double X, int AStartPos, int AnEndPos, int X1, int X2)
|
xue@0
|
1679 {
|
xue@0
|
1680 if (AnEndPos-AStartPos<0) return 0;
|
xue@0
|
1681 else if (AnEndPos-AStartPos==0) return FStartPos;
|
xue@0
|
1682 else return AStartPos+(X-X1)*(AnEndPos-AStartPos)/(X2-X1);
|
xue@0
|
1683 }
|
xue@0
|
1684
|
xue@0
|
1685 void __fastcall TWaveView::FromPixelToSample(double* Sample, int Count, int AStartPos, int AnEndPos)
|
xue@0
|
1686 {
|
xue@0
|
1687 if (AnEndPos-AStartPos<0) memset(Sample, 0, sizeof(double)*Count);
|
xue@0
|
1688 else if (AnEndPos-AStartPos==0) for (int i=0; i<Count; i++) Sample[i]=AStartPos;
|
xue@0
|
1689 else
|
xue@0
|
1690 {
|
xue@0
|
1691 double EndStartCount=(AnEndPos-AStartPos)*1.0/Count;
|
xue@0
|
1692 double As=AStartPos+0.5*EndStartCount;
|
xue@0
|
1693 for (int i=0; i<Count; i++) Sample[i]=As+i*EndStartCount;
|
xue@0
|
1694 }
|
xue@0
|
1695 }
|
xue@0
|
1696
|
xue@0
|
1697 double __fastcall TWaveView::FromSampleToPixel(int PaneIndex, double Pos)
|
xue@0
|
1698 {
|
xue@0
|
1699 return FPanes.Rect[PaneIndex].left+(Pos-FStartPos)*1.0*FPanes.Rect[PaneIndex].Width()/(FEndPos-FStartPos);
|
xue@0
|
1700 }
|
xue@0
|
1701
|
xue@0
|
1702 double __fastcall TWaveView::FromSampleToPixel(double Pos, int X1, int X2)
|
xue@0
|
1703 {
|
xue@0
|
1704 return X1+(Pos-FStartPos)*(X2-X1)/(FEndPos-FStartPos);
|
xue@0
|
1705 }
|
xue@0
|
1706
|
xue@0
|
1707 int __fastcall TWaveView::GetCurrentChannel()
|
xue@0
|
1708 {
|
xue@0
|
1709 return FPanes.Channel[FCurrentPane];
|
xue@0
|
1710 }
|
xue@0
|
1711
|
xue@0
|
1712 double __fastcall TWaveView::GetCurrentDigiFreq()
|
xue@0
|
1713 {
|
xue@0
|
1714 double result=(FCurrentDigiFreq1+FCurrentDigiFreq2)/2;
|
xue@0
|
1715 if (result<0) return 0;
|
xue@0
|
1716 else if (result>0.5) return 0.5;
|
xue@0
|
1717 else return result;
|
xue@0
|
1718 }
|
xue@0
|
1719
|
xue@0
|
1720 QSPEC_FORMAT* __fastcall TWaveView::GetA(int Channel, int fr)
|
xue@0
|
1721 {
|
xue@0
|
1722 return FSpectrogram[Channel]->A(fr);
|
xue@0
|
1723 }
|
xue@0
|
1724
|
xue@0
|
1725 double __fastcall TWaveView::GetCurrentAmplitude()
|
xue@0
|
1726 {
|
xue@0
|
1727 return FPTA(FCurrentPane, FY);
|
xue@0
|
1728 }
|
xue@0
|
1729
|
xue@0
|
1730 //There is no SetCurrentRange() method. Use SetArea().
|
xue@0
|
1731 TWaveViewSelection __fastcall TWaveView::GetCurrentRange()
|
xue@0
|
1732 {
|
xue@0
|
1733 TWaveViewSelection sel={FStartPos, FEndPos, FStartDigiFreq, FEndDigiFreq};
|
xue@0
|
1734 return sel;
|
xue@0
|
1735 }
|
xue@0
|
1736
|
xue@0
|
1737 __int16 __fastcall TWaveView::GetCurrentSample16()
|
xue@0
|
1738 {
|
xue@0
|
1739 return Data16[FPanes.Channel[FCurrentPane]][CurrentTime];
|
xue@0
|
1740 }
|
xue@0
|
1741
|
xue@0
|
1742 int __fastcall TWaveView::GetCurrentSampleInPixel()
|
xue@0
|
1743 {
|
xue@0
|
1744 if (FBytesPerSample==1) return FATP(FCurrentPane, Data8[FPanes.Channel[FCurrentPane]][CurrentTime]);
|
xue@0
|
1745 else if (FBytesPerSample==2) return FATP(FCurrentPane, Data16[FPanes.Channel[FCurrentPane]][CurrentTime]);
|
xue@0
|
1746 else return FATP(FCurrentPane, Data24[FPanes.Channel[FCurrentPane]][CurrentTime]);
|
xue@0
|
1747 }
|
xue@0
|
1748
|
xue@0
|
1749 int __fastcall TWaveView::GetCurrentTimeEx()
|
xue@0
|
1750 {
|
xue@0
|
1751 return (FCurrentTime1+FCurrentTime2)/2;//+0.5;
|
xue@0
|
1752 }
|
xue@0
|
1753
|
xue@0
|
1754 void* __fastcall TWaveView::GetData(int Channel)
|
xue@0
|
1755 {
|
xue@0
|
1756 return FData[Channel];
|
xue@0
|
1757 }
|
xue@0
|
1758
|
xue@0
|
1759 __int16* __fastcall TWaveView::GetData16(int Channel)
|
xue@0
|
1760 {
|
xue@0
|
1761 return (__int16*)(FData[Channel]);
|
xue@0
|
1762 }
|
xue@0
|
1763
|
xue@0
|
1764 __pint24 __fastcall TWaveView::GetData24(int Channel)
|
xue@0
|
1765 {
|
xue@0
|
1766 return (__pint24)(FData[Channel]);
|
xue@0
|
1767 }
|
xue@0
|
1768
|
xue@0
|
1769 char* __fastcall TWaveView::GetData8(int Channel)
|
xue@0
|
1770 {
|
xue@0
|
1771 return (char*)(FData[Channel]);
|
xue@0
|
1772 }
|
xue@0
|
1773
|
xue@0
|
1774 double __fastcall TWaveView::GetFMask(double* mask, int t, TWaveViewPlaybackFilter Filter)
|
xue@0
|
1775 {
|
xue@0
|
1776 double result=0;
|
xue@0
|
1777
|
xue@0
|
1778 if (Filter==wvfPass) memset(mask, 0, FSpecRes*sizeof(double));
|
xue@0
|
1779 else for (int i=0; i<FSpecRes; i++) mask[i]=1;
|
xue@0
|
1780
|
xue@0
|
1781 if (Filter==wvfNone) result=1;
|
xue@0
|
1782 else
|
xue@0
|
1783 {
|
xue@0
|
1784 int LF1, LF2;
|
xue@0
|
1785 for (int i=0; i<FSelections->Count; i++)
|
xue@0
|
1786 {
|
xue@0
|
1787 TWaveViewSelection sel=FSelections->Items[i];
|
xue@0
|
1788 if (t<sel.StartPos || t>sel.EndPos) continue;
|
xue@0
|
1789 LF1=sel.StartDigiFreq*FSpecRes+0.5;
|
xue@0
|
1790 LF2=sel.EndDigiFreq*FSpecRes+0.5;
|
xue@0
|
1791 if (LF1<0) LF1=0;
|
xue@0
|
1792 if (LF2>FSpecRes/2+1) LF2=FSpecRes/2+1;
|
xue@0
|
1793 if (Filter==wvfPass) for (int j=LF1; j<=LF2; j++) mask[j]=1;
|
xue@0
|
1794 else for (int j=LF1; j<=LF2; j++) mask[j]=0;
|
xue@0
|
1795 }
|
xue@0
|
1796 for (int i=FSpecRes/2+1; i<FSpecRes; i++) mask[i]=mask[FSpecRes-i];
|
xue@0
|
1797 for (int i=0; i<FSpecRes; i++) result+=mask[i];
|
xue@0
|
1798 result/=FSpecRes;
|
xue@0
|
1799 }
|
xue@0
|
1800 return result;
|
xue@0
|
1801 }
|
xue@0
|
1802
|
xue@0
|
1803 void __fastcall TWaveView::GetObjectAtPointer(int X, int Y)
|
xue@0
|
1804 {
|
xue@0
|
1805 ObjectAtPointer=0;
|
xue@0
|
1806 for (int i=0; i<FObjects.Count; i++)
|
xue@0
|
1807 {
|
xue@0
|
1808 if (FObjects.Items[i].Options & wvoNoMouseFocus) continue;
|
xue@0
|
1809 TRect Rect=FObjects.Items[i].Rect;
|
xue@0
|
1810 if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
|
xue@0
|
1811 {
|
xue@0
|
1812 ObjectAtPointer=&FObjects.Items[i];
|
xue@0
|
1813 break;
|
xue@0
|
1814 }
|
xue@0
|
1815 }
|
xue@0
|
1816 }
|
xue@0
|
1817
|
xue@0
|
1818 //WaveView.cpp implements basic idle mode (-1), drag mode (0), select mode (1) and re-select mode (2)
|
xue@0
|
1819 //other modes are defined externally
|
xue@0
|
1820 void __fastcall TWaveView::GetOpMode(Word Key, TMouseButton Button, TShiftState Shift)
|
xue@0
|
1821 {
|
xue@0
|
1822 if (FCurrentPane>=0)
|
xue@0
|
1823 {
|
xue@0
|
1824 FOpMode=wopSelect;
|
xue@0
|
1825 if (FOnGetOpMode) FOnGetOpMode(this, Shift, FOpMode);
|
xue@0
|
1826 }
|
xue@0
|
1827 else
|
xue@0
|
1828 FOpMode=wopIdle; //Idle mode
|
xue@0
|
1829
|
xue@0
|
1830 TCursor ACursor;
|
xue@0
|
1831 if (FOpMode==wopDrag) ACursor=crHandPoint;
|
xue@0
|
1832 else if (FOpMode==wopSelect) ACursor=crArrow;
|
xue@0
|
1833 else ACursor=Cursor;
|
xue@0
|
1834 if (ACursor!=Cursor) {Cursor=ACursor;::SetCursor(Screen->Cursors[Cursor]);}
|
xue@0
|
1835 }
|
xue@0
|
1836
|
xue@0
|
1837 QSPEC_FORMAT* __fastcall TWaveView::GetPh(int Channel, int fr)
|
xue@0
|
1838 {
|
xue@0
|
1839 return FSpectrogram[Channel]->Ph(fr);
|
xue@0
|
1840 }
|
xue@0
|
1841
|
xue@0
|
1842 cmplx<QSPEC_FORMAT>* __fastcall TWaveView::GetSpec(int Channel, int fr)
|
xue@0
|
1843 {
|
xue@0
|
1844 return FSpectrogram[Channel]->Spec(fr);
|
xue@0
|
1845 }
|
xue@0
|
1846
|
xue@0
|
1847 TQuickSpectrogram* __fastcall TWaveView::GetSpectrogram(int Channel)
|
xue@0
|
1848 {
|
xue@0
|
1849 return FSpectrogram[Channel];
|
xue@0
|
1850 }
|
xue@0
|
1851
|
xue@0
|
1852 bool __fastcall TWaveView::GetPlaying()
|
xue@0
|
1853 {
|
xue@0
|
1854 return FSection->Playing;
|
xue@0
|
1855 }
|
xue@0
|
1856
|
xue@0
|
1857 double __fastcall TWaveView::GetSpecWindowParamD(int Index)
|
xue@0
|
1858 {
|
xue@0
|
1859 return FSpecWindowParamD[Index];
|
xue@0
|
1860 }
|
xue@0
|
1861
|
xue@0
|
1862 void __fastcall TWaveView::InvalidateBasic(int channel, int basic)
|
xue@0
|
1863 {
|
xue@0
|
1864 if (basic==0)
|
xue@0
|
1865 if (channel>=0) Basic0Settings[channel].Y=0;
|
xue@0
|
1866 else for (int i=0; i<WV2_MAX_CHANNEL; i++) Basic0Settings[i].Y=0;
|
xue@0
|
1867 if (basic==1)
|
xue@0
|
1868 if (channel>=0) Basic1Settings[channel].Y=0;
|
xue@0
|
1869 else for (int i=0; i<WV2_MAX_CHANNEL; i++) Basic1Settings[i].Y=0;
|
xue@0
|
1870 }
|
xue@0
|
1871
|
xue@0
|
1872 void __fastcall TWaveView::InvalidateBasics(int channel)
|
xue@0
|
1873 {
|
xue@0
|
1874 Basic0Settings[channel].Y=0;
|
xue@0
|
1875 Basic1Settings[channel].Y=0;
|
xue@0
|
1876 }
|
xue@0
|
1877
|
xue@0
|
1878 void __fastcall TWaveView::ItemExtractClick(TObject* Sender)
|
xue@0
|
1879 {
|
xue@0
|
1880 if (FLength>0)
|
xue@0
|
1881 {
|
xue@0
|
1882 bool Shift=(GetKeyState(VK_SHIFT)<0);
|
xue@0
|
1883 DoExtract(Sender);
|
xue@0
|
1884 if (!Shift) RemoveSelection(-1);
|
xue@0
|
1885 }
|
xue@0
|
1886 }
|
xue@0
|
1887
|
xue@0
|
1888 void __fastcall TWaveView::ItemPlayClick(TObject* Sender)
|
xue@0
|
1889 {
|
xue@0
|
1890 StartPlayback(Sender);
|
xue@0
|
1891 }
|
xue@0
|
1892
|
xue@0
|
1893 void __fastcall TWaveView::ItemPropertyClick(TObject* Sender)
|
xue@0
|
1894 {
|
xue@0
|
1895 if (FLength>0)
|
xue@0
|
1896 {
|
xue@0
|
1897 if (FStartSelR<FSelections->StartPos ||FStartSelR>=FSelections->EndPos
|
xue@0
|
1898 ||FPanes.HasFreqAxis[FStartPane] && (FVStartSelR<FSelections->StartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq))
|
xue@0
|
1899 {
|
xue@0
|
1900 if (DefaultPropertyItems) DefaultShowProperty(false);
|
xue@0
|
1901 else if (FCustomProperty) FCustomProperty(this, false);
|
xue@0
|
1902 }
|
xue@0
|
1903 else
|
xue@0
|
1904 {
|
xue@0
|
1905 if (DefaultPropertyItems) DefaultShowProperty(true);
|
xue@0
|
1906 else if (FCustomProperty) FCustomProperty(this, true);
|
xue@0
|
1907 }
|
xue@0
|
1908 }
|
xue@0
|
1909 }
|
xue@0
|
1910
|
xue@0
|
1911 void __fastcall TWaveView::ItemXZoomClick(TObject* Sender)
|
xue@0
|
1912 {
|
xue@0
|
1913 if (FCustomXZoomClick) FCustomXZoomClick(Sender);
|
xue@0
|
1914 else
|
xue@0
|
1915 {
|
xue@0
|
1916 if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMIN_TAG)
|
xue@0
|
1917 Zoom(FStartSelR, 0.8);
|
xue@0
|
1918 else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMOUT_TAG)
|
xue@0
|
1919 Zoom(FStartSelR, 3);
|
xue@0
|
1920 else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMRESTORE_TAG)
|
xue@0
|
1921 Zoom(FStartSelR, 0);
|
xue@0
|
1922 }
|
xue@0
|
1923 }
|
xue@0
|
1924
|
xue@0
|
1925 void __fastcall TWaveView::ItemYZoomClick(TObject* Sender)
|
xue@0
|
1926 {
|
xue@0
|
1927 if (FCustomYZoomClick) FCustomYZoomClick(Sender);
|
xue@0
|
1928 else
|
xue@0
|
1929 {
|
xue@0
|
1930 if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMYZOOMIN_TAG) YZoomRate*=1.5;
|
xue@0
|
1931 else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMYZOOMRESTORE_TAG)
|
xue@0
|
1932 {
|
xue@0
|
1933 YZoomRate=1;
|
xue@0
|
1934 FStartDigiFreq=0;
|
xue@0
|
1935 FEndDigiFreq=0.5;
|
xue@0
|
1936 }
|
xue@0
|
1937 }
|
xue@0
|
1938 }
|
xue@0
|
1939
|
xue@0
|
1940 void __fastcall TWaveView::KeyDown(Word &Key, TShiftState Shift)
|
xue@0
|
1941 {
|
xue@0
|
1942 GetOpMode(0, TMouseButton(0), Shift);
|
xue@0
|
1943 if (FLength>0)
|
xue@0
|
1944 {
|
xue@0
|
1945 if (FOpMode<=wopReselect && FCurrentPane>=0)
|
xue@0
|
1946 {
|
xue@0
|
1947 switch(Key)
|
xue@0
|
1948 {
|
xue@0
|
1949 case VK_BACK:
|
xue@0
|
1950 {
|
xue@0
|
1951 int k=Selections->Count-1;
|
xue@0
|
1952 RemoveSelection(k);
|
xue@0
|
1953 break;
|
xue@0
|
1954 }
|
xue@0
|
1955 case VK_DELETE:
|
xue@0
|
1956 RemoveSelection(-1);
|
xue@0
|
1957 break;
|
xue@0
|
1958 case VK_ESCAPE:
|
xue@0
|
1959 ClearSelections(this);
|
xue@0
|
1960 break;
|
xue@0
|
1961 case VK_NEXT:
|
xue@0
|
1962 if (Selections->Count>0)
|
xue@0
|
1963 {
|
xue@0
|
1964 int k=(Selections->Focus+1)%Selections->Count;
|
xue@0
|
1965 FocusSelection(k);
|
xue@0
|
1966 }
|
xue@0
|
1967 break;
|
xue@0
|
1968 case VK_PRIOR:
|
xue@0
|
1969 if (Selections->Count>0)
|
xue@0
|
1970 {
|
xue@0
|
1971 int k=(Selections->Focus+Selections->Count-1)%Selections->Count;
|
xue@0
|
1972 FocusSelection(k);
|
xue@0
|
1973 }
|
xue@0
|
1974 break;
|
xue@0
|
1975 }
|
xue@0
|
1976 }
|
xue@0
|
1977 else if (ObjectAtPointer && ObjectAtPointer->OnKeyDown) ObjectAtPointer->OnKeyDown(this, Key, Shift);
|
xue@0
|
1978 }
|
xue@0
|
1979
|
xue@0
|
1980 TWinControl::KeyDown(Key, Shift);
|
xue@0
|
1981 }
|
xue@0
|
1982
|
xue@0
|
1983 void __fastcall TWaveView::KeyUp(Word &Key, TShiftState Shift)
|
xue@0
|
1984 {
|
xue@0
|
1985 GetOpMode(0, TMouseButton(0), Shift);
|
xue@0
|
1986 TWinControl::KeyUp(Key, Shift);
|
xue@0
|
1987 }
|
xue@0
|
1988
|
xue@0
|
1989 void __fastcall TWaveView::MouseCursor(TShiftState Shift, int X, int Y)
|
xue@0
|
1990 {
|
xue@0
|
1991 FX=X, FY=Y, FLastShiftState=Shift;
|
xue@0
|
1992 }
|
xue@0
|
1993
|
xue@0
|
1994 void __fastcall TWaveView::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
|
xue@0
|
1995 {
|
xue@0
|
1996 WaveViewHitTest(X, Y);
|
xue@0
|
1997 GetOpMode(0, Button, Shift);
|
xue@0
|
1998
|
xue@0
|
1999 MouseCursor(Shift, X, Y);
|
xue@0
|
2000 if (Button==mbLeft && FOnMousePointer) MousePointer(Shift, X, Y);
|
xue@0
|
2001
|
xue@0
|
2002 if (Shift.Contains(ssShift) && FTools.Contains(wvtPlayNote)){double f=FSamplesPerSec*CurrentDigiFreq; if (f>0){if (FTools.Contains(wvtPitchScale)) PlayNote(f/FPitchScalePart, FPlayNoteInSemitone); else PlayNote(f, FPlayNoteInSemitone);}}
|
xue@0
|
2003
|
xue@0
|
2004 if (FLength>=1)
|
xue@0
|
2005 {
|
xue@0
|
2006 FStartSel=CurrentTime;
|
xue@0
|
2007 FVStartSel=CurrentDigiFreq;
|
xue@0
|
2008 FStartPane=FCurrentPane;
|
xue@0
|
2009 if (FStartPane>=0)
|
xue@0
|
2010 {
|
xue@0
|
2011 FStartSelR=FPTS(FCurrentPane, X);
|
xue@0
|
2012 FVStartSelR=FPTDF(FCurrentPane, Y);
|
xue@0
|
2013 }
|
xue@0
|
2014 FStartSelX=X;
|
xue@0
|
2015 FStartSelY=Y;
|
xue@0
|
2016
|
xue@0
|
2017 if (FOpMode==wopSelect)
|
xue@0
|
2018 {
|
xue@0
|
2019 if (Button==mbLeft && FCurrentPane>=0)
|
xue@0
|
2020 {
|
xue@0
|
2021 if (FMultiSelect)
|
xue@0
|
2022 {
|
xue@0
|
2023 int slp=SelectionAtPos(CurrentTime, CurrentDigiFreq);
|
xue@0
|
2024 FLastFocus=(slp>=0)?slp:FSelections->Focus;
|
xue@0
|
2025 }
|
xue@0
|
2026
|
xue@0
|
2027 if (FSelections->Count && !MultiSelect) Selections->Clear();
|
xue@0
|
2028
|
xue@0
|
2029 FStartSelX=X;
|
xue@0
|
2030 FStartSelY=Y;
|
xue@0
|
2031
|
xue@0
|
2032 TWaveViewSelection sel;
|
xue@0
|
2033 if (FSelectMode==WV2_HSELECT)
|
xue@0
|
2034 {
|
xue@0
|
2035 sel.StartPos=sel.EndPos=FStartSel;
|
xue@0
|
2036 sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq;
|
xue@0
|
2037 FSelections->Add(sel);
|
xue@0
|
2038 }
|
xue@0
|
2039 else if (FSelectMode==WV2_VSELECT)
|
xue@0
|
2040 {
|
xue@0
|
2041 sel.StartPos=FStartPos, sel.EndPos=FEndPos;
|
xue@0
|
2042 sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel;
|
xue@0
|
2043 FSelections->Add(sel);
|
xue@0
|
2044 }
|
xue@0
|
2045 else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT))
|
xue@0
|
2046 {
|
xue@0
|
2047 sel.StartPos=sel.EndPos=FStartSel;
|
xue@0
|
2048 sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel;
|
xue@0
|
2049 FSelections->Add(sel);
|
xue@0
|
2050 }
|
xue@0
|
2051 else {}
|
xue@0
|
2052 if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, 1);
|
xue@0
|
2053 }
|
xue@0
|
2054 }
|
xue@0
|
2055 else if (FOpMode==wopDrag) //drag mode
|
xue@0
|
2056 {
|
xue@0
|
2057 StartDrag(X, Y);
|
xue@0
|
2058 }
|
xue@0
|
2059 else if (FOpMode==wopReselect && Button==mbLeft && FCurrentPane>=0)
|
xue@0
|
2060 {
|
xue@0
|
2061 if (Button==mbLeft)
|
xue@0
|
2062 {
|
xue@0
|
2063 FStartSelHitTest=SelHitTest(X, Y);
|
xue@0
|
2064 FStartSelSel=(*FSelections)[FSelections->Focus];
|
xue@0
|
2065 }
|
xue@0
|
2066 }
|
xue@0
|
2067 else //external mode
|
xue@0
|
2068 {
|
xue@0
|
2069 if (ObjectAtPointer && ObjectAtPointer->OnMouseDown)
|
xue@0
|
2070 {
|
xue@0
|
2071 StartObject=ObjectAtPointer;
|
xue@0
|
2072 ObjectAtPointer->OnMouseDown(this, Button, Shift, X, Y);
|
xue@0
|
2073 }
|
xue@0
|
2074 else
|
xue@0
|
2075 {
|
xue@0
|
2076 StartObject=0;
|
xue@0
|
2077 }
|
xue@0
|
2078 }
|
xue@0
|
2079 }
|
xue@0
|
2080 TControl::MouseDown(Button, Shift, X, Y);
|
xue@0
|
2081 FLastX=X, FLastY=Y;
|
xue@0
|
2082 Invalidate();
|
xue@0
|
2083 }
|
xue@0
|
2084
|
xue@0
|
2085 //Down=1: mouse down; -1, -2: mouse move pair; -3: mouse up
|
xue@0
|
2086 void __fastcall TWaveView::MouseLocalData(int X, int Y, int Down)
|
xue@0
|
2087 {
|
xue@0
|
2088 int t=CurrentTime, Wid=FSpecRes, HWid=Wid/2;
|
xue@0
|
2089 int FLength_Wid=FLength-Wid;
|
xue@0
|
2090
|
xue@0
|
2091 int t0=t-HWid, tp=t, tn=t-Wid;
|
xue@0
|
2092
|
xue@0
|
2093 if (FLocalDataTimeGrid)
|
xue@0
|
2094 {
|
xue@0
|
2095 int hoffst=FSpecOffst/2;
|
xue@0
|
2096 t0=(t0+hoffst)/FSpecOffst*FSpecOffst;
|
xue@0
|
2097 tp=(tp+hoffst)/FSpecOffst*FSpecOffst;
|
xue@0
|
2098 tn=(tn+hoffst)/FSpecOffst*FSpecOffst;
|
xue@0
|
2099 t=(t+hoffst)/FSpecOffst*FSpecOffst;
|
xue@0
|
2100 }
|
xue@0
|
2101
|
xue@0
|
2102 if (t0<0) t0=0;
|
xue@0
|
2103 else if (t0>FLength_Wid) t0=FLength_Wid;
|
xue@0
|
2104 if (tp<0) tp=0;
|
xue@0
|
2105 else if (tp>FLength_Wid) tp=FLength_Wid;
|
xue@0
|
2106 if (tn<0) tn=0;
|
xue@0
|
2107 else if (tn>FLength_Wid) tn=FLength_Wid;
|
xue@0
|
2108
|
xue@0
|
2109 FLocalDataOn=true;
|
xue@0
|
2110 FOnMouseLocalData(this, &Data8[0][t0*FBytesPerSample], &Data8[0][tp*FBytesPerSample], &Data8[0][tn*FBytesPerSample], Wid, FBytesPerSample, CurrentTime, CurrentDigiFreq, Down);
|
xue@0
|
2111 FLocalDataOn=false;
|
xue@0
|
2112 }
|
xue@0
|
2113
|
xue@0
|
2114 void __fastcall TWaveView::MousePointer(TShiftState Shift, int X, int Y)
|
xue@0
|
2115 {
|
xue@0
|
2116 FOnMousePointer(this, FCurrentPane, CurrentTime, CurrentDigiFreq);
|
xue@0
|
2117 }
|
xue@0
|
2118
|
xue@0
|
2119 void __fastcall TWaveView::MouseMove(TShiftState Shift, int X, int Y)
|
xue@0
|
2120 {
|
xue@0
|
2121 WaveViewHitTest(X, Y);
|
xue@0
|
2122 MouseCursor(Shift, X, Y);
|
xue@0
|
2123 if (Shift.Contains(ssLeft) && FOnMousePointer) if (X!=FLastX || Y!=FLastY) MousePointer(Shift, X, Y);
|
xue@0
|
2124
|
xue@0
|
2125 if (!Shift.Contains(ssLeft)) GetOpMode(0, (TMouseButton)0, Shift);
|
xue@0
|
2126
|
xue@0
|
2127 if (FLength>=1)
|
xue@0
|
2128 {
|
xue@0
|
2129 if (FOpMode==wopSelect && FStartPane>=0) //select mode
|
xue@0
|
2130 {
|
xue@0
|
2131 if ((X!=FLastX || Y!=FLastY) && Shift.Contains(ssLeft))
|
xue@0
|
2132 {
|
xue@0
|
2133 TWaveViewSelection sel;
|
xue@0
|
2134 int ACurrentTime=FPTS(FStartPane, X+0.5)+0.5; if (ACurrentTime<0) ACurrentTime=0; else if (ACurrentTime>FLength) ACurrentTime=FLength;
|
xue@0
|
2135 double ACurrentDigiFreq=FPTDF(FStartPane, Y+0.5); if (ACurrentDigiFreq<0) ACurrentDigiFreq=0; else if (ACurrentDigiFreq>0.5) ACurrentDigiFreq=0.5;
|
xue@0
|
2136 if (FSelectMode==WV2_HSELECT)
|
xue@0
|
2137 {
|
xue@0
|
2138 if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime;
|
xue@0
|
2139 else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel;
|
xue@0
|
2140 sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq;
|
xue@0
|
2141 FSelections->Items[FSelections->Focus]=sel;
|
xue@0
|
2142 }
|
xue@0
|
2143 else if (FSelectMode==WV2_VSELECT)
|
xue@0
|
2144 {
|
xue@0
|
2145 sel.StartPos=FStartPos, sel.EndPos=FEndPos;
|
xue@0
|
2146 if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq;
|
xue@0
|
2147 else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel;
|
xue@0
|
2148 FSelections->Items[FSelections->Focus]=sel;
|
xue@0
|
2149 }
|
xue@0
|
2150 else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT))
|
xue@0
|
2151 {
|
xue@0
|
2152 if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime;
|
xue@0
|
2153 else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel;
|
xue@0
|
2154 if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq;
|
xue@0
|
2155 else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel;
|
xue@0
|
2156 FSelections->Items[FSelections->Focus]=sel;
|
xue@0
|
2157 }
|
xue@0
|
2158 if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, -2);
|
xue@0
|
2159 }
|
xue@0
|
2160 }
|
xue@0
|
2161 else if (FOpMode==wopDrag && FStartPane>=0) //drag mode
|
xue@0
|
2162 {
|
xue@0
|
2163 if ((Shift.Contains(ssLeft)||true) && (X!=FLastX || Y!=FLastY))
|
xue@0
|
2164 {
|
xue@0
|
2165 double lLength=FStartSelSel.EndPos-FStartSelSel.StartPos;
|
xue@0
|
2166 if (lLength>0)
|
xue@0
|
2167 {
|
xue@0
|
2168 double lWidth=FPanes.Rect[FStartPane].Width();
|
xue@0
|
2169 FStartPos=FStartSelSel.StartPos-(X-FStartSelX)*lLength/lWidth;
|
xue@0
|
2170 if (FStartPos<0) FStartPos=0;
|
xue@0
|
2171 FEndPos=FStartPos+lLength;
|
xue@0
|
2172 if (FEndPos>FLength) {FEndPos=FLength; FStartPos=FEndPos-lLength;}
|
xue@0
|
2173 if (!FPanes.HasFreqAxis[FStartPane]) {}//waveform
|
xue@0
|
2174 else
|
xue@0
|
2175 {
|
xue@0
|
2176 if (FPanes.YScale[FStartPane]==0) //linear scale
|
xue@0
|
2177 {
|
xue@0
|
2178 lLength=FStartSelSel.EndDigiFreq-FStartSelSel.StartDigiFreq;
|
xue@0
|
2179 lWidth=FPanes.Rect[FStartPane].Height();
|
xue@0
|
2180 FStartDigiFreq=FStartSelSel.StartDigiFreq-(FStartSelY-Y)*lLength/lWidth;
|
xue@0
|
2181 if (FStartDigiFreq<0) FStartDigiFreq=0;
|
xue@0
|
2182 FEndDigiFreq=FStartDigiFreq+lLength;
|
xue@0
|
2183 if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq-lLength;}
|
xue@0
|
2184 }
|
xue@0
|
2185 else //log scale
|
xue@0
|
2186 {
|
xue@0
|
2187 lLength=WV2_LOG_FREQ(FStartSelSel.EndDigiFreq)/WV2_LOG_FREQ(FStartSelSel.StartDigiFreq);
|
xue@0
|
2188 lWidth=FPanes.Rect[FStartPane].Height();
|
xue@0
|
2189 FStartDigiFreq=WV2_LOG_FREQ(FStartSelSel.StartDigiFreq)*pow(lLength, (Y-FStartSelY)/lWidth);
|
xue@0
|
2190 FEndDigiFreq=FStartDigiFreq*lLength;
|
xue@0
|
2191 if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq/lLength;}
|
xue@0
|
2192 }
|
xue@0
|
2193 }
|
xue@0
|
2194 PageChange();
|
xue@0
|
2195 }
|
xue@0
|
2196 }
|
xue@0
|
2197 }
|
xue@0
|
2198 else if (FOpMode==wopReselect && FStartPane>=0) //re-selecting mode
|
xue@0
|
2199 {
|
xue@0
|
2200 if (Shift.Contains(ssLeft) && FStartSelHitTest!=selOuter)
|
xue@0
|
2201 {
|
xue@0
|
2202 int NewStartPos, NewEndPos;
|
xue@0
|
2203 double NewStartDigiFreq, NewEndDigiFreq;
|
xue@0
|
2204
|
xue@0
|
2205 if ((FStartSelHitTest & WV2_LEFT) && FStartSelX!=X) NewStartPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.StartPos)+X-FStartSelX)+0.5;
|
xue@0
|
2206 else NewStartPos=FStartSelSel.StartPos;
|
xue@0
|
2207 if ((FStartSelHitTest & WV2_RIGHT) && FStartSelX!=X) NewEndPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.EndPos)+X-FStartSelX)+0.5;
|
xue@0
|
2208 else NewEndPos=FStartSelSel.EndPos;
|
xue@0
|
2209 if ((FStartSelHitTest & WV2_TOP) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewEndDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.EndDigiFreq)+Y-FStartSelY);
|
xue@0
|
2210 else NewEndDigiFreq=FStartSelSel.EndDigiFreq;
|
xue@0
|
2211 if ((FStartSelHitTest & WV2_BOTTOM) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewStartDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.StartDigiFreq)+Y-FStartSelY);
|
xue@0
|
2212 else NewStartDigiFreq=FStartSelSel.StartDigiFreq;
|
xue@0
|
2213
|
xue@0
|
2214 TWaveViewSelection sel={NewStartPos, NewEndPos, NewStartDigiFreq, NewEndDigiFreq};
|
xue@0
|
2215 if (NewStartPos>NewEndPos) sel.StartPos=NewEndPos, sel.EndPos=NewStartPos;
|
xue@0
|
2216 if (NewStartDigiFreq>NewEndDigiFreq) sel.StartDigiFreq=NewEndDigiFreq, sel.EndDigiFreq=NewStartDigiFreq;
|
xue@0
|
2217 if (sel.StartPos<0) sel.StartPos=0; else if (sel.EndPos>FLength) sel.EndPos=FLength;
|
xue@0
|
2218 if (sel.StartDigiFreq<0) sel.StartDigiFreq=0; else if (sel.EndDigiFreq>0.5) sel.EndDigiFreq=0.5;
|
xue@0
|
2219 FSelections->Items[FSelections->Focus]=sel;
|
xue@0
|
2220 }
|
xue@0
|
2221 else
|
xue@0
|
2222 {
|
xue@0
|
2223 TCursor ACursor=ControlCursorAtPos(X, Y);;
|
xue@0
|
2224 if (Cursor!=ACursor)
|
xue@0
|
2225 {
|
xue@0
|
2226 Cursor=ACursor;
|
xue@0
|
2227 ::SetCursor(Screen->Cursors[Cursor]);
|
xue@0
|
2228 }
|
xue@0
|
2229 }
|
xue@0
|
2230 }
|
xue@0
|
2231 else //external mode
|
xue@0
|
2232 {
|
xue@0
|
2233 if (Shift.Contains(ssLeft) && StartObject)
|
xue@0
|
2234 {
|
xue@0
|
2235 if (StartObject->OnMouseMove) StartObject->OnMouseMove(this, Shift, X, Y);
|
xue@0
|
2236 }
|
xue@0
|
2237 else if (ObjectAtPointer && ObjectAtPointer->OnMouseMove)
|
xue@0
|
2238 ObjectAtPointer->OnMouseMove(this, Shift, X, Y);
|
xue@0
|
2239 }
|
xue@0
|
2240
|
xue@0
|
2241 if (Shift.Contains(ssLeft) || Shift.Contains(ssRight)) FLastX=X, FLastY=Y;
|
xue@0
|
2242 }
|
xue@0
|
2243 if (FClickFocus && !Focused()) SetFocus();
|
xue@0
|
2244 TControl::MouseMove(Shift, X, Y);
|
xue@0
|
2245 Invalidate();
|
xue@0
|
2246 }
|
xue@0
|
2247
|
xue@0
|
2248 void __fastcall TWaveView::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
|
xue@0
|
2249 {
|
xue@0
|
2250 WaveViewHitTest(X, Y);
|
xue@0
|
2251 MouseCursor(Shift, X, Y);
|
xue@0
|
2252 if (FLength>=1)
|
xue@0
|
2253 {
|
xue@0
|
2254 if (FOpMode==wopSelect && FStartPane>=0)
|
xue@0
|
2255 {
|
xue@0
|
2256 if (Button==mbLeft)
|
xue@0
|
2257 {
|
xue@0
|
2258 if (FSelections->Focus>=0)
|
xue@0
|
2259 {
|
xue@0
|
2260 TWaveViewSelection sel=FSelections->Items[FSelections->Focus];
|
xue@0
|
2261 if (sel.StartPos==sel.EndPos || sel.StartDigiFreq==sel.EndDigiFreq)
|
xue@0
|
2262 {
|
xue@0
|
2263 FSelections->Delete(FSelections->Focus);
|
xue@0
|
2264 if (FMultiSelect) FSelections->Focus=FLastFocus;
|
xue@0
|
2265 }
|
xue@0
|
2266 }
|
xue@0
|
2267 }
|
xue@0
|
2268 }
|
xue@0
|
2269 else if (FOpMode==wopReselect && FStartPane>=0)
|
xue@0
|
2270 {
|
xue@0
|
2271 if (FSelections->Focus>=0 && FStartSelHitTest!=selOuter)
|
xue@0
|
2272 {
|
xue@0
|
2273 TWaveViewSelection sel=FSelections->Items[FSelections->Focus];
|
xue@0
|
2274 if (FSTP(FStartPane, sel.EndPos)-FSTP(FStartPane, sel.StartPos)<0.01
|
xue@0
|
2275 || FPanes.HasFreqAxis[FStartPane] && FDFTP(FStartPane, sel.StartDigiFreq)-FDFTP(FStartPane, sel.EndDigiFreq)<0.01)
|
xue@0
|
2276 {
|
xue@0
|
2277 FSelections->Delete(FSelections->Focus);
|
xue@0
|
2278 }
|
xue@0
|
2279 }
|
xue@0
|
2280 }
|
xue@0
|
2281 else //external mode
|
xue@0
|
2282 {
|
xue@0
|
2283 if (StartObject)
|
xue@0
|
2284 {
|
xue@0
|
2285 if (StartObject->OnMouseUp) StartObject->OnMouseUp(this, Button, Shift, X, Y);
|
xue@0
|
2286 StartObject=0;
|
xue@0
|
2287 }
|
xue@0
|
2288 else if (ObjectAtPointer && ObjectAtPointer->OnMouseUp)
|
xue@0
|
2289 ObjectAtPointer->OnMouseUp(this, Button, Shift, X, Y);
|
xue@0
|
2290 }
|
xue@0
|
2291 }
|
xue@0
|
2292
|
xue@0
|
2293 if (Button==mbLeft || Button==mbRight) FLastX=X, FLastY=Y;
|
xue@0
|
2294 TControl::MouseUp(Button, Shift, X, Y);
|
xue@0
|
2295 Invalidate();
|
xue@0
|
2296 }
|
xue@0
|
2297
|
xue@0
|
2298 void __fastcall TWaveView::MouseWheelHandler(TMessage& Msg)
|
xue@0
|
2299 {
|
xue@0
|
2300 TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg;
|
xue@0
|
2301
|
xue@0
|
2302 bool Handled=false; TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1);
|
xue@0
|
2303 if (ObjectAtPointer && ObjectAtPointer->OnMouseWheel) ObjectAtPointer->OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled);
|
xue@0
|
2304 else if (FCurrentPane>=0 && !DisableMouseWheelZoom)
|
xue@0
|
2305 {
|
xue@0
|
2306 if (Shift.Empty())
|
xue@0
|
2307 {
|
xue@0
|
2308 int X=CurrentTime;
|
xue@0
|
2309
|
xue@0
|
2310 if (X>=FStartPos && X<=FEndPos)
|
xue@0
|
2311 {
|
xue@0
|
2312 if (WMsg->WheelDelta<0) Zoom(X, 0.9);
|
xue@0
|
2313 else Zoom(X, 10.0/9);
|
xue@0
|
2314 }
|
xue@0
|
2315 }
|
xue@0
|
2316 else
|
xue@0
|
2317 {
|
xue@0
|
2318 if (!FPanes.HasFreqAxis[FCurrentPane])
|
xue@0
|
2319 {
|
xue@0
|
2320 if (WMsg->WheelDelta>0) ZoomY(0.9);
|
xue@0
|
2321 else ZoomY(10.0/9);
|
xue@0
|
2322 }
|
xue@0
|
2323 else
|
xue@0
|
2324 {
|
xue@0
|
2325 double Y=CurrentDigiFreq;
|
xue@0
|
2326 if (Y>=FStartDigiFreq && Y<=FEndDigiFreq)
|
xue@0
|
2327 {
|
xue@0
|
2328 if (WMsg->WheelDelta<0) ZoomF(Y, 0.9, FPanes.YScale[FCurrentPane]);
|
xue@0
|
2329 else ZoomF(Y, 10.0/9, FPanes.YScale[FCurrentPane]);
|
xue@0
|
2330 }
|
xue@0
|
2331 }
|
xue@0
|
2332 }
|
xue@0
|
2333 }
|
xue@0
|
2334 if (OnMouseWheel) OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled);
|
xue@0
|
2335 if (!Handled) TCustomControl::MouseWheelHandler(Msg);
|
xue@0
|
2336 }
|
xue@0
|
2337
|
xue@0
|
2338 void __fastcall TWaveView::PageChange(bool updatescrollbar)
|
xue@0
|
2339 {
|
xue@0
|
2340 if (FScrollBar && updatescrollbar) UpdateScrollBar(this);
|
xue@0
|
2341 if (FOnPageChange) FOnPageChange(this);
|
xue@0
|
2342 }
|
xue@0
|
2343
|
xue@0
|
2344 //The Paint() methos draws form StartPos to EndPos in the
|
xue@0
|
2345 //WaveAudio stream, stretching it to fit the whole width
|
xue@0
|
2346 //Selected area is highlighted.
|
xue@0
|
2347 void __fastcall TWaveView::Paint()
|
xue@0
|
2348 {
|
xue@0
|
2349 if (FOnCustomPaint)
|
xue@0
|
2350 {
|
xue@0
|
2351 bool Done;
|
xue@0
|
2352 FOnCustomPaint(this, Done);
|
xue@0
|
2353 if (Done)
|
xue@0
|
2354 {
|
xue@0
|
2355 if (FOnPaint) FOnPaint(this);
|
xue@0
|
2356 return;
|
xue@0
|
2357 }
|
xue@0
|
2358 }
|
xue@0
|
2359
|
xue@0
|
2360 if (FLength>0)
|
xue@0
|
2361 {
|
xue@0
|
2362 Canvas->Brush->Color=FBackColor; Canvas->FillRect(ClientRect);
|
xue@0
|
2363 DrawPanes();
|
xue@0
|
2364 if (FOnPaint) FOnPaint(this);
|
xue@0
|
2365 if (FShowInfo) DrawInfo();
|
xue@0
|
2366 }
|
xue@0
|
2367 if (FObjects.Count>0) for (int i=0; i<FObjects.Count; i++) if (FObjects.Items[i].DrawObject) FObjects.Items[i].DrawObject(this, FObjects.Items[i]);
|
xue@0
|
2368
|
xue@0
|
2369 if (FShowCursor && FCurrentPane>=0) DrawCursor(FCurrentPane, FX, FY);
|
xue@0
|
2370 }
|
xue@0
|
2371
|
xue@0
|
2372 void __fastcall TWaveView::PausePlayback(TObject* Sender)
|
xue@0
|
2373 {
|
xue@0
|
2374 if (FSection && FSection->Playing) FSection->PausePlayback(this);
|
xue@0
|
2375 }
|
xue@0
|
2376
|
xue@0
|
2377 void __fastcall TWaveView::Post(int Mode)
|
xue@0
|
2378 {
|
xue@0
|
2379 if (!FWaveAudio) return;
|
xue@0
|
2380 FWaveAudio->OnAudioChange=NULL;
|
xue@0
|
2381
|
xue@0
|
2382 //for a waveaudio using file stream, set file mode to RW
|
xue@0
|
2383 if (!FWaveAudio->UseMemoryStream)
|
xue@0
|
2384 {
|
xue@0
|
2385 int pos=FWaveAudio->FFileStream->Position;
|
xue@0
|
2386 delete FWaveAudio->FFileStream->File;
|
xue@0
|
2387 FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenReadWrite);
|
xue@0
|
2388 FWaveAudio->FFileStream->Position=pos;
|
xue@0
|
2389 }
|
xue@0
|
2390
|
xue@0
|
2391 int Channels=FWaveAudio->Channels;
|
xue@0
|
2392
|
xue@0
|
2393 int writefrom, writelength;
|
xue@0
|
2394 if (Mode==0)
|
xue@0
|
2395 {
|
xue@0
|
2396 writefrom=0;
|
xue@0
|
2397 writelength=FLength;
|
xue@0
|
2398 }
|
xue@0
|
2399 else if (Mode==1)
|
xue@0
|
2400 {
|
xue@0
|
2401 writefrom=FStartPos;
|
xue@0
|
2402 writelength=FEndPos-FStartPos;
|
xue@0
|
2403 }
|
xue@0
|
2404 int writefrombytes=writefrom*FBytesPerSample*Channels;
|
xue@0
|
2405
|
xue@0
|
2406 if (Channels==1)
|
xue@0
|
2407 {
|
xue@0
|
2408 FWaveAudio->Seek(writefrombytes, soFromBeginning);
|
xue@0
|
2409 FWaveAudio->Write(&Data8[0][writefrombytes], writelength*FBytesPerSample);
|
xue@0
|
2410 }
|
xue@0
|
2411 else
|
xue@0
|
2412 {
|
xue@0
|
2413 //-------------------------
|
xue@0
|
2414 {
|
xue@0
|
2415 if (FWaveAudio->UseMemoryStream)
|
xue@0
|
2416 {
|
xue@0
|
2417 char* databuf=&((unsigned char*)((TMemoryStream*)FWaveAudio->WaveStream)->Memory)[writefrombytes];
|
xue@0
|
2418 char* data=&((char*)FData)[writefrom*FBytesPerSample];
|
xue@0
|
2419 for (int k=0; k<writelength; k++)
|
xue@0
|
2420 {
|
xue@0
|
2421 memcpy(data, databuf, FBytesPerSample);
|
xue@0
|
2422 data+=FBytesPerSample;
|
xue@0
|
2423 databuf+=FBytesPerSample*Channels;
|
xue@0
|
2424 }
|
xue@0
|
2425 }
|
xue@0
|
2426 else
|
xue@0
|
2427 {
|
xue@0
|
2428 FWaveAudio->Seek(writefrombytes, soFromCurrent);
|
xue@0
|
2429 char* data=&((char*)FData)[writefrom*FBytesPerSample];
|
xue@0
|
2430 for (int k=0; k<writelength; k++)
|
xue@0
|
2431 {
|
xue@0
|
2432 FWaveAudio->WaveStream->Read(data, FBytesPerSample);
|
xue@0
|
2433 data+=FBytesPerSample;
|
xue@0
|
2434 FWaveAudio->Seek(FBytesPerSample*(Channels-1), soFromCurrent);
|
xue@0
|
2435 }
|
xue@0
|
2436 }
|
xue@0
|
2437 }
|
xue@0
|
2438 //---------------------------
|
xue@0
|
2439 }
|
xue@0
|
2440
|
xue@0
|
2441 //for a waveaudio using file stream, set file mode to back to R after posting
|
xue@0
|
2442 if (!FWaveAudio->UseMemoryStream)
|
xue@0
|
2443 {
|
xue@0
|
2444 int pos=FWaveAudio->FFileStream->Position;
|
xue@0
|
2445 delete FWaveAudio->FFileStream->File;
|
xue@0
|
2446 FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenRead);
|
xue@0
|
2447 FWaveAudio->FFileStream->Position=pos;
|
xue@0
|
2448 }
|
xue@0
|
2449 FWaveAudio->OnAudioChange=WaveViewAudioChange;
|
xue@0
|
2450 }
|
xue@0
|
2451
|
xue@0
|
2452 void __fastcall TWaveView::RemoveSelection(int Index)
|
xue@0
|
2453 {
|
xue@0
|
2454 if (Index==-1) Index=FSelections->Focus;
|
xue@0
|
2455 if (Index<0 || Index>=FSelections->Count) return;
|
xue@0
|
2456 if (Index==FSelections->Focus)
|
xue@0
|
2457 {
|
xue@0
|
2458 FSelections->Delete(Index);
|
xue@0
|
2459 if (FOnSelectedChange) FOnSelectedChange(this);
|
xue@0
|
2460 }
|
xue@0
|
2461 else
|
xue@0
|
2462 {
|
xue@0
|
2463 FSelections->Delete(Index);
|
xue@0
|
2464 }
|
xue@0
|
2465 Invalidate();
|
xue@0
|
2466 }
|
xue@0
|
2467
|
xue@0
|
2468 void __fastcall TWaveView::Resize()
|
xue@0
|
2469 {
|
xue@0
|
2470 FPanes.ResizePanes(ClientRect);
|
xue@0
|
2471 TControl::Resize();
|
xue@0
|
2472 }
|
xue@0
|
2473
|
xue@0
|
2474 void __fastcall TWaveView::Retrieve(int Mode, int from, int length)
|
xue@0
|
2475 {
|
xue@0
|
2476 if (!FWaveAudio || FWaveAudio->Length==0) return;
|
xue@0
|
2477
|
xue@0
|
2478 int readfrom, readlength;
|
xue@0
|
2479 if (Mode==0)
|
xue@0
|
2480 {
|
xue@0
|
2481 readfrom=0;
|
xue@0
|
2482 readlength=FLength;
|
xue@0
|
2483 }
|
xue@0
|
2484 else if (Mode==1)
|
xue@0
|
2485 {
|
xue@0
|
2486 readfrom=FStartPos;
|
xue@0
|
2487 readlength=FEndPos-FStartPos;
|
xue@0
|
2488 }
|
xue@0
|
2489 else if (Mode==2)
|
xue@0
|
2490 {
|
xue@0
|
2491 readfrom=from;
|
xue@0
|
2492 readlength=length;
|
xue@0
|
2493 }
|
xue@0
|
2494 int readfrombytes=readfrom*FBytesPerSample*FChannels;
|
xue@0
|
2495 FWaveAudio->Seek(readfrombytes, soFromBeginning);
|
xue@0
|
2496
|
xue@0
|
2497 if (FChannels==1)
|
xue@0
|
2498 {
|
xue@0
|
2499 FWaveAudio->Read(&Data8[0][readfrombytes], readlength*FBytesPerSample);
|
xue@0
|
2500 ExtDataChange(this, 0, readfrom, readfrom+readlength);
|
xue@0
|
2501 }
|
xue@0
|
2502 else if (FChannels==2)
|
xue@0
|
2503 {
|
xue@0
|
2504 void *FFData0=&Data8[0][readfrom*FBytesPerSample],
|
xue@0
|
2505 *FFData1=&Data8[1][readfrom*FBytesPerSample];
|
xue@0
|
2506 FWaveAudio->ReadSamplesInterleave(FFData0, FFData1, readlength);
|
xue@0
|
2507 ExtDataChange(this, 0, readfrom, readfrom+readlength);
|
xue@0
|
2508 ExtDataChange(this, 1, readfrom, readfrom+readlength);
|
xue@0
|
2509 }
|
xue@0
|
2510 else
|
xue@0
|
2511 {
|
xue@0
|
2512 void* FFData[WV2_MAX_CHANNEL];
|
xue@0
|
2513 for (int i=0; i<FChannels; i++) FFData[i]=&Data8[i][readfrom*FBytesPerSample];
|
xue@0
|
2514 FWaveAudio->ReadSamplesMultiChannel(FChannels, FFData, readlength);
|
xue@0
|
2515 for (int i=0; i<FChannels; i++) ExtDataChange(this, i, readfrom, readfrom+readlength);
|
xue@0
|
2516 }
|
xue@0
|
2517 }
|
xue@0
|
2518
|
xue@0
|
2519 #define MyRGB(R, G, B) RGB(B, G, R)
|
xue@0
|
2520 //#define MyRGB(R, G, B) RGB(R, G, B)
|
xue@0
|
2521
|
xue@0
|
2522 void SampleImageLine(double* vyy, int dY, double* yy, TQuickSpectrogram* Spectrogram, int fr)
|
xue@0
|
2523 {
|
xue@0
|
2524 QSPEC_FORMAT* Spec=Spectrogram->A(fr);
|
xue@0
|
2525 if (!Spec) {memset(vyy, 0, sizeof(double)*dY); return;}
|
xue@0
|
2526 else
|
xue@0
|
2527 {
|
xue@0
|
2528 int yyd, oldyyd=-2, hWid=Spectrogram->Wid/2;
|
xue@0
|
2529 double yyr, v0, v1, v2, v3, a, b, c;
|
xue@0
|
2530 for (int y=0; y<dY; y++)
|
xue@0
|
2531 {
|
xue@0
|
2532 if (yy[y]<0 || yy[y]>hWid) vyy[y]=0;
|
xue@0
|
2533 else
|
xue@0
|
2534 {
|
xue@0
|
2535 yyd=floor(yy[y]); yyr=yy[y]-yyd;
|
xue@0
|
2536 if (yyr==0) vyy[y]=Spec[yyd];
|
xue@0
|
2537 else
|
xue@0
|
2538 {
|
xue@0
|
2539 if (yyd!=oldyyd)
|
xue@0
|
2540 {
|
xue@0
|
2541 oldyyd=yyd; v1=Spec[yyd], v2=Spec[yyd+1];
|
xue@0
|
2542 if (yyd==0) v0=Spec[1]; else v0=Spec[yyd-1];
|
xue@0
|
2543 if (yyd==hWid-1) v3=Spec[hWid-1]; else v3=Spec[yyd+2];
|
xue@0
|
2544
|
xue@0
|
2545 if (v1>v0 && v1>v3 && v2>v0 && v2>v3) //a local peak -> use quadratic interpolation
|
xue@0
|
2546 {
|
xue@0
|
2547 if (v0<v3) //use v1, v2, v3
|
xue@0
|
2548 {
|
xue@0
|
2549 c=v1; a=(v3+c)/2-v2; b=v2-a-c;
|
xue@0
|
2550 }
|
xue@0
|
2551 else //use v0, v1, v2
|
xue@0
|
2552 {
|
xue@0
|
2553 b=(v2-v0)/2; c=v1; a=v2-b-c;
|
xue@0
|
2554 }
|
xue@0
|
2555 }
|
xue@0
|
2556 else //use linear interpolation
|
xue@0
|
2557 {
|
xue@0
|
2558 a=0; b=v2-v1; c=v1;
|
xue@0
|
2559 }
|
xue@0
|
2560 }
|
xue@0
|
2561 vyy[y]=(a*yyr+b)*yyr+c;
|
xue@0
|
2562 }
|
xue@0
|
2563 }
|
xue@0
|
2564 }
|
xue@0
|
2565 }
|
xue@0
|
2566 }
|
xue@0
|
2567
|
xue@0
|
2568 QSPEC_FORMAT __fastcall SampleImageX(TQuickSpectrogram* Spectrogram, Graphics::TBitmap* ABmp, int dX, int dY, double* xx, double* yy, double amp, bool interpolate)
|
xue@0
|
2569 {
|
xue@0
|
2570 BITMAPFILEHEADER bh;
|
xue@0
|
2571 bh.bfType=0x4d42;
|
xue@0
|
2572 bh.bfSize=0x36+4*dX*dY;
|
xue@0
|
2573 bh.bfReserved1=bh.bfReserved2=0;
|
xue@0
|
2574 bh.bfOffBits=0x36;
|
xue@0
|
2575
|
xue@0
|
2576 BITMAPINFOHEADER bi;
|
xue@0
|
2577 memset(&bi, 0, sizeof(bi));
|
xue@0
|
2578 bi.biSize=0x28;
|
xue@0
|
2579 bi.biWidth=dX;
|
xue@0
|
2580 bi.biHeight=dY;
|
xue@0
|
2581 bi.biPlanes=1;
|
xue@0
|
2582 bi.biBitCount=0x20;
|
xue@0
|
2583 bi.biSizeImage=4*dX*dY;
|
xue@0
|
2584
|
xue@0
|
2585 TMemoryStream* AS=new TMemoryStream;
|
xue@0
|
2586 AS->Size=bh.bfSize;
|
xue@0
|
2587 char* ASM=(char*)AS->Memory;
|
xue@0
|
2588 memcpy(ASM, &bh, sizeof(bh));
|
xue@0
|
2589 memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
|
xue@0
|
2590 int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
|
xue@0
|
2591
|
xue@0
|
2592 double xxr, maxv=0;
|
xue@0
|
2593 int xxd, sampr, sampg, sampb;
|
xue@0
|
2594
|
xue@0
|
2595 double *vyys0=(double*)malloc8(sizeof(double)*(dY+dY)), *vyys1=&vyys0[dY];
|
xue@0
|
2596
|
xue@0
|
2597 int oldxxd=-3;
|
xue@0
|
2598
|
xue@0
|
2599 if (interpolate)
|
xue@0
|
2600 {
|
xue@0
|
2601 for (int x=0; x<dX; x++)
|
xue@0
|
2602 {
|
xue@0
|
2603 xxd=floor(xx[x]);
|
xue@0
|
2604 xxr=xx[x]-xxd;
|
xue@0
|
2605 if (xxd<-1 || xxd>=Spectrogram->Capacity)
|
xue@0
|
2606 {
|
xue@0
|
2607 for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
|
xue@0
|
2608 continue;
|
xue@0
|
2609 }
|
xue@0
|
2610
|
xue@0
|
2611 if (xxd==oldxxd) {}
|
xue@0
|
2612 else if (xxd==oldxxd+1)
|
xue@0
|
2613 {
|
xue@0
|
2614 memcpy(vyys0, vyys1, sizeof(double)*dY);
|
xue@0
|
2615 for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
|
xue@0
|
2616 if (xxd+1<Spectrogram->Capacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1);
|
xue@0
|
2617 else memset(vyys1, 0, sizeof(double)*dY);
|
xue@0
|
2618 }
|
xue@0
|
2619 else
|
xue@0
|
2620 {
|
xue@0
|
2621 if (xxd>=0 && xxd<Spectrogram->Capacity)
|
xue@0
|
2622 {
|
xue@0
|
2623 SampleImageLine(vyys0, dY, yy, Spectrogram, xxd);
|
xue@0
|
2624 for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
|
xue@0
|
2625 }
|
xue@0
|
2626 else memset(vyys0, 0, sizeof(double)*dY);
|
xue@0
|
2627 if (xxd+1<Spectrogram->Capacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1);
|
xue@0
|
2628 else memset(vyys1, 0, sizeof(double)*dY);
|
xue@0
|
2629 }
|
xue@0
|
2630
|
xue@0
|
2631 for (int y=0; y<dY; y++)
|
xue@0
|
2632 {
|
xue@0
|
2633 double vyy=vyys0[y]+(vyys1[y]-vyys0[y])*xxr;
|
xue@0
|
2634 double samp=amp*vyy;
|
xue@0
|
2635 if (samp>=1)
|
xue@0
|
2636 sampr=255, sampg=samp*32, sampb=0;
|
xue@0
|
2637 else
|
xue@0
|
2638 sampg=0, sampr=255*samp, sampb=0;
|
xue@0
|
2639 pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
|
xue@0
|
2640 }
|
xue@0
|
2641 oldxxd=xxd;
|
xue@0
|
2642 }
|
xue@0
|
2643 }
|
xue@0
|
2644 else
|
xue@0
|
2645 {
|
xue@0
|
2646 for (int x=0; x<dX; x++)
|
xue@0
|
2647 {
|
xue@0
|
2648 xxd=floor(xx[x]+0.5);
|
xue@0
|
2649 if (xxd<-1 || xxd>=Spectrogram->Capacity)
|
xue@0
|
2650 {
|
xue@0
|
2651 for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
|
xue@0
|
2652 continue;
|
xue@0
|
2653 }
|
xue@0
|
2654
|
xue@0
|
2655 if (xxd==oldxxd)
|
xue@0
|
2656 {
|
xue@0
|
2657 for (int y=0; y<dY; y++) pixs[x+y*dX]=pixs[x-1+y*dX]; //this shall rarely be executed
|
xue@0
|
2658 continue;
|
xue@0
|
2659 }
|
xue@0
|
2660 else
|
xue@0
|
2661 {
|
xue@0
|
2662 if (xxd>=0 && xxd<Spectrogram->Capacity)
|
xue@0
|
2663 {
|
xue@0
|
2664 SampleImageLine(vyys0, dY, yy, Spectrogram, xxd);
|
xue@0
|
2665 for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
|
xue@0
|
2666 }
|
xue@0
|
2667 else memset(vyys0, 0, sizeof(double)*dY); //this shall be never executed
|
xue@0
|
2668 for (int y=0; y<dY; y++)
|
xue@0
|
2669 {
|
xue@0
|
2670 double samp=amp*vyys0[y];
|
xue@0
|
2671 if (samp>=1)
|
xue@0
|
2672 sampr=255, sampg=samp*32, sampb=0;
|
xue@0
|
2673 else
|
xue@0
|
2674 sampg=0, sampr=255*samp, sampb=0;
|
xue@0
|
2675 pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
|
xue@0
|
2676 }
|
xue@0
|
2677 }
|
xue@0
|
2678 oldxxd=xxd;
|
xue@0
|
2679 }
|
xue@0
|
2680 }
|
xue@0
|
2681
|
xue@0
|
2682 AS->Position=0;
|
xue@0
|
2683 ABmp->LoadFromStream(AS);
|
xue@0
|
2684 delete AS;
|
xue@0
|
2685
|
xue@0
|
2686 free8(vyys0);
|
xue@0
|
2687 return maxv;
|
xue@0
|
2688 }
|
xue@0
|
2689
|
xue@0
|
2690 QSPEC_FORMAT __fastcall TWaveView::SampleSpectrogramX(int channel, Graphics::TBitmap* ABmp, double* xx, double* yy, int dX, int dY, double amp, bool interpolate)
|
xue@0
|
2691 {
|
xue@0
|
2692 return SampleImageX(FSpectrogram[channel], ABmp, dX, dY, xx, yy, amp, interpolate);
|
xue@0
|
2693 }
|
xue@0
|
2694
|
xue@0
|
2695 QSPEC_FORMAT __fastcall TWaveView::SamplePeakSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp)
|
xue@0
|
2696 {
|
xue@0
|
2697 TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
|
xue@0
|
2698
|
xue@0
|
2699 BITMAPFILEHEADER bh;
|
xue@0
|
2700 bh.bfType=0x4d42;
|
xue@0
|
2701 bh.bfSize=0x36+4*dX*dY;
|
xue@0
|
2702 bh.bfReserved1=bh.bfReserved2=0;
|
xue@0
|
2703 bh.bfOffBits=0x36;
|
xue@0
|
2704
|
xue@0
|
2705 BITMAPINFOHEADER bi;
|
xue@0
|
2706 memset(&bi, 0, sizeof(bi));
|
xue@0
|
2707 bi.biSize=0x28;
|
xue@0
|
2708 bi.biWidth=dX;
|
xue@0
|
2709 bi.biHeight=dY;
|
xue@0
|
2710 bi.biPlanes=1;
|
xue@0
|
2711 bi.biBitCount=0x20;
|
xue@0
|
2712 bi.biSizeImage=4*dX*dY;
|
xue@0
|
2713
|
xue@0
|
2714 TMemoryStream* AS=new TMemoryStream;
|
xue@0
|
2715 AS->Size=bh.bfSize;
|
xue@0
|
2716 char* ASM=(char*)AS->Memory;
|
xue@0
|
2717 memcpy(ASM, &bh, sizeof(bh));
|
xue@0
|
2718 memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
|
xue@0
|
2719 int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
|
xue@0
|
2720
|
xue@0
|
2721 int xxd, sampr, sampg, sampb;
|
xue@0
|
2722
|
xue@0
|
2723 double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0;
|
xue@0
|
2724
|
xue@0
|
2725 int oldxxd=-3;
|
xue@0
|
2726
|
xue@0
|
2727 for (int x=0; x<dX; x++)
|
xue@0
|
2728 {
|
xue@0
|
2729 xxd=floor(xx[x]+0.5);
|
xue@0
|
2730 if (xxd<0 || xxd>=Spectrogram->Capacity)
|
xue@0
|
2731 {
|
xue@0
|
2732 for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
|
xue@0
|
2733 continue;
|
xue@0
|
2734 }
|
xue@0
|
2735
|
xue@0
|
2736 if (xxd==oldxxd) {}
|
xue@0
|
2737 else
|
xue@0
|
2738 {
|
xue@0
|
2739 memset(vyys0, 0, sizeof(double)*dY);
|
xue@0
|
2740 QSPEC_FORMAT* spec=Spectrogram->A(xxd);
|
xue@0
|
2741 int istart=AStartDigiFreq*FSpecRes-1;
|
xue@0
|
2742 int iend=AnEndDigiFreq*FSpecRes+1;
|
xue@0
|
2743 if (istart<1) istart=1;
|
xue@0
|
2744 if (iend>FSpecRes/2) iend=FSpecRes/2;
|
xue@0
|
2745 for (int i=istart; i<iend; i++)
|
xue@0
|
2746 {
|
xue@0
|
2747 if (spec[i]>spec[i-1] && spec[i]>spec[i+1])
|
xue@0
|
2748 {
|
xue@0
|
2749 if (maxv<spec[i]) maxv=spec[i];
|
xue@0
|
2750 double digif=(i+0.5*(spec[i-1]-spec[i+1])/(spec[i-1]+spec[i+1]-2*spec[i]))/FSpecRes;
|
xue@0
|
2751 int p=FDFTP(digif, AStartDigiFreq, AnEndDigiFreq, dY, 0, yscale);
|
xue@0
|
2752 if (p>=0 && p<dY) vyys0[p]=spec[i];
|
xue@0
|
2753 }
|
xue@0
|
2754 }
|
xue@0
|
2755 }
|
xue@0
|
2756
|
xue@0
|
2757 for (int y=0; y<dY; y++)
|
xue@0
|
2758 {
|
xue@0
|
2759 double samp=amp*vyys0[y];
|
xue@0
|
2760 if (samp>=1) sampr=255, sampg=samp*32, sampb=0;
|
xue@0
|
2761 else sampg=0, sampr=255*samp, sampb=0;
|
xue@0
|
2762 pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
|
xue@0
|
2763 }
|
xue@0
|
2764 oldxxd=xxd;
|
xue@0
|
2765 }
|
xue@0
|
2766
|
xue@0
|
2767 AS->Position=0;
|
xue@0
|
2768 ABmp->LoadFromStream(AS);
|
xue@0
|
2769 delete AS;
|
xue@0
|
2770
|
xue@0
|
2771 free8(vyys0);
|
xue@0
|
2772 return maxv;
|
xue@0
|
2773 }
|
xue@0
|
2774
|
xue@0
|
2775 QSPEC_FORMAT __fastcall TWaveView::SampleSinuSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp)
|
xue@0
|
2776 {
|
xue@0
|
2777 TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
|
xue@0
|
2778
|
xue@0
|
2779 BITMAPFILEHEADER bh;
|
xue@0
|
2780 bh.bfType=0x4d42;
|
xue@0
|
2781 bh.bfSize=0x36+4*dX*dY;
|
xue@0
|
2782 bh.bfReserved1=bh.bfReserved2=0;
|
xue@0
|
2783 bh.bfOffBits=0x36;
|
xue@0
|
2784
|
xue@0
|
2785 BITMAPINFOHEADER bi;
|
xue@0
|
2786 memset(&bi, 0, sizeof(bi));
|
xue@0
|
2787 bi.biSize=0x28;
|
xue@0
|
2788 bi.biWidth=dX;
|
xue@0
|
2789 bi.biHeight=dY;
|
xue@0
|
2790 bi.biPlanes=1;
|
xue@0
|
2791 bi.biBitCount=0x20;
|
xue@0
|
2792 bi.biSizeImage=4*dX*dY;
|
xue@0
|
2793
|
xue@0
|
2794 TMemoryStream* AS=new TMemoryStream;
|
xue@0
|
2795 AS->Size=bh.bfSize;
|
xue@0
|
2796 char* ASM=(char*)AS->Memory;
|
xue@0
|
2797 memcpy(ASM, &bh, sizeof(bh));
|
xue@0
|
2798 memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
|
xue@0
|
2799 int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
|
xue@0
|
2800
|
xue@0
|
2801 int xxd, sampr, sampg, sampb;
|
xue@0
|
2802
|
xue@0
|
2803 double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0;
|
xue@0
|
2804
|
xue@0
|
2805 int oldxxd=-3;
|
xue@0
|
2806
|
xue@0
|
2807 for (int x=0; x<dX; x++)
|
xue@0
|
2808 {
|
xue@0
|
2809 xxd=floor(xx[x]+0.5);
|
xue@0
|
2810 if (xxd<0 || xxd>=Spectrogram->Capacity)
|
xue@0
|
2811 {
|
xue@0
|
2812 for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
|
xue@0
|
2813 continue;
|
xue@0
|
2814 }
|
xue@0
|
2815
|
xue@0
|
2816 if (xxd==oldxxd) {}
|
xue@0
|
2817 else
|
xue@0
|
2818 {
|
xue@0
|
2819 memset(vyys0, 0, sizeof(double)*dY);
|
xue@0
|
2820 QSPEC_FORMAT* spec=Spectrogram->A(xxd);
|
xue@0
|
2821 int istart=AStartDigiFreq*FSpecRes-1;
|
xue@0
|
2822 int iend=AnEndDigiFreq*FSpecRes+1;
|
xue@0
|
2823 if (istart<1) istart=1;
|
xue@0
|
2824 if (iend>FSpecRes/2) iend=FSpecRes/2;
|
xue@0
|
2825 for (int i=istart; i<iend; i++)
|
xue@0
|
2826 {
|
xue@0
|
2827 if (spec[i]>spec[i-1] && spec[i]>spec[i+1])
|
xue@0
|
2828 {
|
xue@0
|
2829 if (maxv<spec[i]) maxv=spec[i];
|
xue@0
|
2830 double digif=(i+0.5*(spec[i-1]-spec[i+1])/(spec[i-1]+spec[i+1]-2*spec[i]))/FSpecRes;
|
xue@0
|
2831 int p=FDFTP(digif, AStartDigiFreq, AnEndDigiFreq, dY, 0, yscale);
|
xue@0
|
2832 if (p>=0 && p<dY) vyys0[p]=spec[i];
|
xue@0
|
2833 }
|
xue@0
|
2834 }
|
xue@0
|
2835 }
|
xue@0
|
2836
|
xue@0
|
2837 for (int y=0; y<dY; y++)
|
xue@0
|
2838 {
|
xue@0
|
2839 double samp=amp*vyys0[y];
|
xue@0
|
2840 if (samp>=1) sampr=255, sampg=samp*32, sampb=0;
|
xue@0
|
2841 else sampg=0, sampr=255*samp, sampb=0;
|
xue@0
|
2842 pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
|
xue@0
|
2843 }
|
xue@0
|
2844 oldxxd=xxd;
|
xue@0
|
2845 }
|
xue@0
|
2846
|
xue@0
|
2847 AS->Position=0;
|
xue@0
|
2848 ABmp->LoadFromStream(AS);
|
xue@0
|
2849 delete AS;
|
xue@0
|
2850
|
xue@0
|
2851 free8(vyys0);
|
xue@0
|
2852 return maxv;
|
xue@0
|
2853 }
|
xue@0
|
2854
|
xue@0
|
2855 void __fastcall TWaveView::ScrollBarChange(TObject* Sender)
|
xue@0
|
2856 {
|
xue@0
|
2857 int ALength=FEndPos-FStartPos;
|
xue@0
|
2858 if (ALength==0) return;
|
xue@0
|
2859 if (FScrollBar->Position>FScrollBar->Max-FScrollBar->PageSize)
|
xue@0
|
2860 FScrollBar->Position=FScrollBar->Max-FScrollBar->PageSize;
|
xue@0
|
2861 int startpos=FScrollBar->Position;
|
xue@0
|
2862 bool willdozoom=true;
|
xue@0
|
2863 if (willdozoom)
|
xue@0
|
2864 {
|
xue@0
|
2865 FStartPos=startpos;
|
xue@0
|
2866 FEndPos=FStartPos+ALength;
|
xue@0
|
2867 Invalidate();
|
xue@0
|
2868 PageChange(false);
|
xue@0
|
2869 }
|
xue@0
|
2870 else UpdateScrollBar(this);
|
xue@0
|
2871 }
|
xue@0
|
2872
|
xue@0
|
2873 int __fastcall TWaveView::SelectionAtPos(int Pos, double DigiFreq)
|
xue@0
|
2874 {
|
xue@0
|
2875 int result=-1;
|
xue@0
|
2876 double marea;
|
xue@0
|
2877 for (int i=0; i<FSelections->Count; i++)
|
xue@0
|
2878 {
|
xue@0
|
2879 TWaveViewSelection sel=FSelections->Items[i];
|
xue@0
|
2880 if (Pos>=sel.StartPos && Pos<sel.EndPos && DigiFreq>=sel.StartDigiFreq && DigiFreq<sel.EndDigiFreq)
|
xue@0
|
2881 {
|
xue@0
|
2882 if (result==-1) result=i, marea=(sel.EndDigiFreq-sel.StartDigiFreq)*(sel.EndPos-sel.StartPos);
|
xue@0
|
2883 else
|
xue@0
|
2884 {
|
xue@0
|
2885 double area=(sel.EndDigiFreq-sel.StartDigiFreq)*(sel.EndPos-sel.StartPos);
|
xue@0
|
2886 if (area<marea) result=i, marea=area;
|
xue@0
|
2887 }
|
xue@0
|
2888 }
|
xue@0
|
2889 }
|
xue@0
|
2890 return result;
|
xue@0
|
2891 }
|
xue@0
|
2892
|
xue@0
|
2893 TWaveViewSelHitTest __fastcall TWaveView::SelHitTest(int X, int Y)
|
xue@0
|
2894 {
|
xue@0
|
2895 TWaveViewSelHitTest result=selNone;
|
xue@0
|
2896 int BW=FSelectionBorderWidth;
|
xue@0
|
2897
|
xue@0
|
2898 if (FSelections->Count==0) result=selOuter;
|
xue@0
|
2899 else
|
xue@0
|
2900 {
|
xue@0
|
2901 int lleft=FSTP(FCurrentPane, FSelections->StartPos);
|
xue@0
|
2902 int lright=FSTP(FCurrentPane, FSelections->EndPos), ltop, lbottom;
|
xue@0
|
2903 if (FPanes.HasFreqAxis[FCurrentPane])
|
xue@0
|
2904 {
|
xue@0
|
2905 ltop=FDFTP(FCurrentPane, FSelections->EndDigiFreq);
|
xue@0
|
2906 lbottom=FDFTP(FCurrentPane, FSelections->StartDigiFreq);
|
xue@0
|
2907 }
|
xue@0
|
2908 else
|
xue@0
|
2909 {
|
xue@0
|
2910 ltop=FPanes.Rect[FCurrentPane].top-2*BW-1, lbottom=FPanes.Rect[FCurrentPane].bottom+2*BW+1;
|
xue@0
|
2911 }
|
xue@0
|
2912
|
xue@0
|
2913 enum {sOuter, sIBorder, sInner, sSBorder} sx, sy;
|
xue@0
|
2914 if (X<lleft-BW || X>lright+BW) sx=sOuter;
|
xue@0
|
2915 else if (X<=lleft+BW) sx=sIBorder;
|
xue@0
|
2916 else if (X<lright-BW) sx=sInner;
|
xue@0
|
2917 else sx=sSBorder;
|
xue@0
|
2918 if (Y<ltop-BW || Y>lbottom+BW) sy=sOuter;
|
xue@0
|
2919 else if (Y<=ltop+BW) sy=sIBorder;
|
xue@0
|
2920 else if (Y<lbottom-BW) sy=sInner;
|
xue@0
|
2921 else sy=sSBorder;
|
xue@0
|
2922
|
xue@0
|
2923 if (sx==sOuter || sy==sOuter) result=selOuter;
|
xue@0
|
2924 else if (sx==sInner)
|
xue@0
|
2925 {
|
xue@0
|
2926 if (sy==sInner) result=selInner;
|
xue@0
|
2927 else if (sy==sIBorder) result=selTop;
|
xue@0
|
2928 else result=selBottom;
|
xue@0
|
2929 }
|
xue@0
|
2930 else if (sx==sIBorder)
|
xue@0
|
2931 {
|
xue@0
|
2932 if (sy==sInner) result=selLeft;
|
xue@0
|
2933 else if (sy==sIBorder) result=selTopLeft;
|
xue@0
|
2934 else result=selBottomLeft;
|
xue@0
|
2935 }
|
xue@0
|
2936 else
|
xue@0
|
2937 {
|
xue@0
|
2938 if (sy==sInner) result=selRight;
|
xue@0
|
2939 else if (sy==sIBorder) result=selTopRight;
|
xue@0
|
2940 else result=selBottomRight;
|
xue@0
|
2941 }
|
xue@0
|
2942 }
|
xue@0
|
2943 return result;
|
xue@0
|
2944 }
|
xue@0
|
2945
|
xue@0
|
2946 void __fastcall TWaveView::SetArea(int AStartPos, int AnEndPos, double AStartDigiFreq, double AnEndDigiFreq)
|
xue@0
|
2947 {
|
xue@0
|
2948 if (FStartPos==AStartPos && FEndPos==AnEndPos && FStartDigiFreq==AStartDigiFreq && FEndDigiFreq==AnEndDigiFreq) return;
|
xue@0
|
2949 if (AStartPos>AnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
|
xue@0
|
2950 bool willdozoom=true;
|
xue@0
|
2951 if (willdozoom)
|
xue@0
|
2952 {
|
xue@0
|
2953 FStartPos=AStartPos;
|
xue@0
|
2954 FEndPos=AnEndPos;
|
xue@0
|
2955 if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
|
xue@0
|
2956 FStartDigiFreq=AStartDigiFreq;
|
xue@0
|
2957 FEndDigiFreq=AnEndDigiFreq;
|
xue@0
|
2958
|
xue@0
|
2959 Invalidate();
|
xue@0
|
2960 PageChange();
|
xue@0
|
2961 }
|
xue@0
|
2962 }
|
xue@0
|
2963
|
xue@0
|
2964 void __fastcall TWaveView::SetAutoExtractMode(bool AnAutoExtractMode)
|
xue@0
|
2965 {
|
xue@0
|
2966 if (FAutoExtractMode!=AnAutoExtractMode)
|
xue@0
|
2967 {
|
xue@0
|
2968 FAutoExtractMode=AnAutoExtractMode;
|
xue@0
|
2969 if (AnAutoExtractMode) FExtractMode=FSelectMode;
|
xue@0
|
2970 }
|
xue@0
|
2971 }
|
xue@0
|
2972
|
xue@0
|
2973 void __fastcall TWaveView::SetAutomaticSpecAmp(int channel, double* xx, double AStartDigiFreq, double AnEndDigiFreq, int dX, int dY)
|
xue@0
|
2974 {
|
xue@0
|
2975 if (maxv_specamp<=0) return;
|
xue@0
|
2976 TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
|
xue@0
|
2977
|
xue@0
|
2978 int xxd, sampr, sampg, sampb;
|
xue@0
|
2979 int oldxxd=-3;
|
xue@0
|
2980 double maxv=0;
|
xue@0
|
2981 for (int x=0; x<dX; x++)
|
xue@0
|
2982 {
|
xue@0
|
2983 xxd=floor(xx[x]+0.5);
|
xue@0
|
2984 if (xxd<0 || xxd>=Spectrogram->Capacity) continue;
|
xue@0
|
2985
|
xue@0
|
2986 if (xxd==oldxxd) {}
|
xue@0
|
2987 else
|
xue@0
|
2988 {
|
xue@0
|
2989 QSPEC_FORMAT* spec=Spectrogram->A(xxd);
|
xue@0
|
2990 int istart=AStartDigiFreq*FSpecRes-1;
|
xue@0
|
2991 int iend=AnEndDigiFreq*FSpecRes+1;
|
xue@0
|
2992 if (istart<1) istart=1;
|
xue@0
|
2993 if (iend>FSpecRes/2) iend=FSpecRes/2;
|
xue@0
|
2994 for (int i=istart; i<iend; i++)
|
xue@0
|
2995 {
|
xue@0
|
2996 if (maxv<spec[i]) maxv=spec[i];
|
xue@0
|
2997 }
|
xue@0
|
2998 }
|
xue@0
|
2999 oldxxd=xxd;
|
xue@0
|
3000 }
|
xue@0
|
3001 if (maxv>0) FSpecAmp=maxv_specamp/maxv;
|
xue@0
|
3002 }
|
xue@0
|
3003
|
xue@0
|
3004
|
xue@0
|
3005 void __fastcall TWaveView::SetAutoSpecAmp(bool AnAutoSpecAmp)
|
xue@0
|
3006 {
|
xue@0
|
3007 if (FAutoSpecAmp!=AnAutoSpecAmp)
|
xue@0
|
3008 FAutoSpecAmp=AnAutoSpecAmp;
|
xue@0
|
3009 }
|
xue@0
|
3010
|
xue@0
|
3011 void __fastcall TWaveView::SetAxisColor(TColor AnAxisColor)
|
xue@0
|
3012 {
|
xue@0
|
3013 FAxisColor=AnAxisColor;
|
xue@0
|
3014 }
|
xue@0
|
3015
|
xue@0
|
3016 void __fastcall TWaveView::SetBackColor(TColor ABackColor)
|
xue@0
|
3017 {
|
xue@0
|
3018 if (FBackColor!=ABackColor)
|
xue@0
|
3019 {
|
xue@0
|
3020 FBackColor=ABackColor;
|
xue@0
|
3021 Invalidate();
|
xue@0
|
3022 }
|
xue@0
|
3023 }
|
xue@0
|
3024
|
xue@0
|
3025 void __fastcall TWaveView::SetCaption(AnsiString ACaption)
|
xue@0
|
3026 {
|
xue@0
|
3027 if (ACaption!=FCaption)
|
xue@0
|
3028 {
|
xue@0
|
3029 FCaption=ACaption;
|
xue@0
|
3030 Invalidate();
|
xue@0
|
3031 }
|
xue@0
|
3032 }
|
xue@0
|
3033
|
xue@0
|
3034 void __fastcall TWaveView::SetClickFocus(bool AClickFocus)
|
xue@0
|
3035 {
|
xue@0
|
3036 FClickFocus=AClickFocus;
|
xue@0
|
3037 }
|
xue@0
|
3038
|
xue@0
|
3039 void __fastcall TWaveView::SetContent(int index, int channel, int type)
|
xue@0
|
3040 {
|
xue@0
|
3041 FPanes.Content[index]=type*WV2_MAX_CHANNEL+channel;
|
xue@0
|
3042 if (Visible) Invalidate();
|
xue@0
|
3043 }
|
xue@0
|
3044
|
xue@0
|
3045 void __fastcall TWaveView::SetContent(int X, int Y, int channel, int type)
|
xue@0
|
3046 {
|
xue@0
|
3047 FPanes.Content[Y*FPanes.FX+X]=type*WV2_MAX_CHANNEL+channel;
|
xue@0
|
3048 if (Visible) Invalidate();
|
xue@0
|
3049 }
|
xue@0
|
3050
|
xue@0
|
3051 void __fastcall TWaveView::SetCursorTF(int PaneIndex, int t, double digif)
|
xue@0
|
3052 {
|
xue@0
|
3053 int X=FSTP(PaneIndex, t);
|
xue@0
|
3054 int Y=FDFTP(PaneIndex, digif);
|
xue@0
|
3055 TPoint P=ClientToScreen(TPoint(X, Y));
|
xue@0
|
3056 SetCursorPos(P.x, P.y);
|
xue@0
|
3057 }
|
xue@0
|
3058
|
xue@0
|
3059 void __fastcall TWaveView::SetData(int index, void* AData)
|
xue@0
|
3060 {
|
xue@0
|
3061 if (FData[index] && FData[index]!=AData) delete[] FData[index];
|
xue@0
|
3062 FData[index]=AData;
|
xue@0
|
3063 FSpectrogram[index]->Data=AData;
|
xue@0
|
3064 FSpectrogram[index]->FreeBuffers();
|
xue@0
|
3065 }
|
xue@0
|
3066
|
xue@0
|
3067 void __fastcall TWaveView::SetDefaultPopupMenu(bool ADefaultPopupMenu)
|
xue@0
|
3068 {
|
xue@0
|
3069 FDefaultPopupMenu=ADefaultPopupMenu;
|
xue@0
|
3070 if (FLength>0 && ADefaultPopupMenu) PopupMenu=FMenu;
|
xue@0
|
3071 }
|
xue@0
|
3072
|
xue@0
|
3073 void __fastcall TWaveView::SetEndPos(int AnEndPos)
|
xue@0
|
3074 {
|
xue@0
|
3075 if (FEndPos==AnEndPos) return;
|
xue@0
|
3076 if (AnEndPos<FStartPos) throw(EWriteError("TWaveView err: EndPos must be no smaller than StartPos"));
|
xue@0
|
3077 bool willdozoom=true;
|
xue@0
|
3078 if (willdozoom)
|
xue@0
|
3079 {
|
xue@0
|
3080 FEndPos=AnEndPos;
|
xue@0
|
3081 Invalidate();
|
xue@0
|
3082 PageChange();
|
xue@0
|
3083 }
|
xue@0
|
3084 }
|
xue@0
|
3085
|
xue@0
|
3086 void __fastcall TWaveView::SetExtractMode(int AnExtractMode)
|
xue@0
|
3087 {
|
xue@0
|
3088 FExtractMode=AnExtractMode;
|
xue@0
|
3089 }
|
xue@0
|
3090
|
xue@0
|
3091 void __fastcall TWaveView::SetForceHamming(bool AForceHamming)
|
xue@0
|
3092 {
|
xue@0
|
3093 FForceHamming=AForceHamming;
|
xue@0
|
3094 }
|
xue@0
|
3095
|
xue@0
|
3096 void __fastcall TWaveView::SetMultiSelect(bool AMultiSelect)
|
xue@0
|
3097 {
|
xue@0
|
3098 FMultiSelect=AMultiSelect;
|
xue@0
|
3099 }
|
xue@0
|
3100
|
xue@0
|
3101 void __fastcall TWaveView::SetPitchScalePart(int APart)
|
xue@0
|
3102 {
|
xue@0
|
3103 if (APart<1) APart=1;
|
xue@0
|
3104 FPitchScalePart=APart;
|
xue@0
|
3105 }
|
xue@0
|
3106
|
xue@0
|
3107 void __fastcall TWaveView::SetPlaybackFilter(TWaveViewPlaybackFilter APlaybackFilter)
|
xue@0
|
3108 {
|
xue@0
|
3109 FPlaybackFilter=APlaybackFilter;
|
xue@0
|
3110 }
|
xue@0
|
3111
|
xue@0
|
3112 void __fastcall TWaveView::SetRulers(int PaneIndex, int Rulers)
|
xue@0
|
3113 {
|
xue@0
|
3114 if (FPanes.Rulers[PaneIndex]!=Rulers)
|
xue@0
|
3115 FPanes.Rulers[PaneIndex]=Rulers;
|
xue@0
|
3116 if (FPanes.Type[PaneIndex]==0) {Basic0Settings[FPanes.Channel[PaneIndex]].Y=0;}
|
xue@0
|
3117 }
|
xue@0
|
3118
|
xue@0
|
3119 void __fastcall TWaveView::SetRulerUnit(int UnitTime, int UnitFreq, int UnitAmp)
|
xue@0
|
3120 {
|
xue@0
|
3121 if (FRulerUnitTime!=UnitTime || FRulerUnitFreq!=UnitFreq || FRulerUnitAmp!=UnitAmp)
|
xue@0
|
3122 {
|
xue@0
|
3123 FRulerUnitTime=UnitTime;
|
xue@0
|
3124 FRulerUnitFreq=UnitFreq;
|
xue@0
|
3125 FRulerUnitAmp=UnitAmp;
|
xue@0
|
3126 }
|
xue@0
|
3127 }
|
xue@0
|
3128
|
xue@0
|
3129 void __fastcall TWaveView::SetSamplesPerSec(int ASamplesPerSec)
|
xue@0
|
3130 {
|
xue@0
|
3131 FSamplesPerSec=ASamplesPerSec;
|
xue@0
|
3132 }
|
xue@0
|
3133
|
xue@0
|
3134 void __fastcall TWaveView::SetScrollBar(TScrollBar* AScrollBar)
|
xue@0
|
3135 {
|
xue@0
|
3136 if (!AScrollBar)
|
xue@0
|
3137 FScrollBar=0;
|
xue@0
|
3138 else
|
xue@0
|
3139 {
|
xue@0
|
3140 FScrollBar=AScrollBar;
|
xue@0
|
3141 FScrollBar->TabStop=false;
|
xue@0
|
3142 if (FLength>0)
|
xue@0
|
3143 {
|
xue@0
|
3144 FScrollBar->OnChange=ScrollBarChange;
|
xue@0
|
3145 UpdateScrollBar(this);
|
xue@0
|
3146 }
|
xue@0
|
3147 }
|
xue@0
|
3148 }
|
xue@0
|
3149
|
xue@0
|
3150 void __fastcall TWaveView::SetSelection(int Start, int End, double VStart, double VEnd)
|
xue@0
|
3151 {
|
xue@0
|
3152 TWaveViewSelection sel={Start, End, VStart, VEnd};
|
xue@0
|
3153 if (!FMultiSelect) FSelections->Clear();
|
xue@0
|
3154 FSelections->Add(sel);
|
xue@0
|
3155 Invalidate();
|
xue@0
|
3156 if (FOnSelectedChange) FOnSelectedChange(this);
|
xue@0
|
3157 }
|
xue@0
|
3158
|
xue@0
|
3159 void __fastcall TWaveView::SetSelectedAreaColorX(TColor ASelectedAreaColorX)
|
xue@0
|
3160 {
|
xue@0
|
3161 if (FSelectedAreaColorX!=ASelectedAreaColorX)
|
xue@0
|
3162 {
|
xue@0
|
3163 FSelectedAreaColorX=ASelectedAreaColorX;
|
xue@0
|
3164 Invalidate();
|
xue@0
|
3165 }
|
xue@0
|
3166 }
|
xue@0
|
3167
|
xue@0
|
3168 void __fastcall TWaveView::SetSelectedFrameColorX(TColor ASelectedFrameColorX)
|
xue@0
|
3169 {
|
xue@0
|
3170 if (FSelectedFrameColorX!=ASelectedFrameColorX)
|
xue@0
|
3171 {
|
xue@0
|
3172 FSelectedFrameColorX=ASelectedFrameColorX;
|
xue@0
|
3173 Invalidate();
|
xue@0
|
3174 }
|
xue@0
|
3175 }
|
xue@0
|
3176
|
xue@0
|
3177 void __fastcall TWaveView::SetSelectingFrameColorX(TColor ASelectingFrameColorX)
|
xue@0
|
3178 {
|
xue@0
|
3179 FSelectingFrameColorX=ASelectingFrameColorX;
|
xue@0
|
3180 }
|
xue@0
|
3181
|
xue@0
|
3182 void __fastcall TWaveView::SetSelectMode(int ASelectMode)
|
xue@0
|
3183 {
|
xue@0
|
3184 FSelectMode=ASelectMode;
|
xue@0
|
3185 if (FAutoExtractMode) FExtractMode=ASelectMode;
|
xue@0
|
3186 }
|
xue@0
|
3187
|
xue@0
|
3188 void __fastcall TWaveView::SetSpecOffst(int ASpecOffst)
|
xue@0
|
3189 {
|
xue@0
|
3190 if (FSpecOffst!=ASpecOffst)
|
xue@0
|
3191 {
|
xue@0
|
3192 FSpecOffst=ASpecOffst;
|
xue@0
|
3193 ClearSpectrograms();
|
xue@0
|
3194 Invalidate();
|
xue@0
|
3195 for (int i=0; i<FChannels; i++) FSpectrogram[i]->Offst=ASpecOffst;
|
xue@0
|
3196 }
|
xue@0
|
3197 }
|
xue@0
|
3198
|
xue@0
|
3199 void __fastcall TWaveView::SetSpecRes(int ASpecRes)
|
xue@0
|
3200 {
|
xue@0
|
3201 if (FSpecRes!=ASpecRes)
|
xue@0
|
3202 {
|
xue@0
|
3203 FSpecOffst=FSpecOffst*ASpecRes/FSpecRes;
|
xue@0
|
3204 FSpecRes=ASpecRes;
|
xue@0
|
3205 ClearSpectrograms();
|
xue@0
|
3206 free8(fw); free(fhbi); free8(fwin);
|
xue@0
|
3207
|
xue@0
|
3208 fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); SetTwiddleFactors(FSpecRes, fw);
|
xue@0
|
3209 fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes];
|
xue@0
|
3210
|
xue@0
|
3211 fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
|
xue@0
|
3212 fhbi=CreateBitInvTable(Log2(FSpecRes)-1);
|
xue@0
|
3213
|
xue@0
|
3214 for (int i=0; i<FChannels; i++) FSpectrogram[i]->Wid=ASpecRes, FSpectrogram[i]->Offst=FSpecOffst;
|
xue@0
|
3215
|
xue@0
|
3216 Invalidate();
|
xue@0
|
3217 }
|
xue@0
|
3218 }
|
xue@0
|
3219
|
xue@0
|
3220 void __fastcall TWaveView::SetSpecWindowParamD(int Index, double AParamD)
|
xue@0
|
3221 {
|
xue@0
|
3222 if (FSpecWindowParamD[Index]!=AParamD)
|
xue@0
|
3223 {
|
xue@0
|
3224 FSpecWindowParamD[Index]=AParamD;
|
xue@0
|
3225 ClearSpectrograms();
|
xue@0
|
3226 if (Index==0) for (int i=0; i<Channels; i++) FSpectrogram[i]->WinParam=AParamD;
|
xue@0
|
3227 fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin);
|
xue@0
|
3228 Invalidate();
|
xue@0
|
3229 }
|
xue@0
|
3230 }
|
xue@0
|
3231
|
xue@0
|
3232 void __fastcall TWaveView::SetSpecWindowType(WindowType ASpecWindowType)
|
xue@0
|
3233 {
|
xue@0
|
3234 if (FSpecWindowType!=ASpecWindowType)
|
xue@0
|
3235 {
|
xue@0
|
3236 FSpecWindowType=ASpecWindowType;
|
xue@0
|
3237 ClearSpectrograms();
|
xue@0
|
3238 for (int i=0; i<Channels; i++) FSpectrogram[i]->WinType=ASpecWindowType;
|
xue@0
|
3239 fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin);
|
xue@0
|
3240 Invalidate();
|
xue@0
|
3241 }
|
xue@0
|
3242 }
|
xue@0
|
3243
|
xue@0
|
3244 void __fastcall TWaveView::SetSpecAmp(double ASpecAmp)
|
xue@0
|
3245 {
|
xue@0
|
3246 if (FSpecAmp!=ASpecAmp)
|
xue@0
|
3247 {
|
xue@0
|
3248 FSpecAmp=ASpecAmp;
|
xue@0
|
3249 Invalidate();
|
xue@0
|
3250 }
|
xue@0
|
3251 }
|
xue@0
|
3252
|
xue@0
|
3253 void __fastcall TWaveView::SetStartPos(int AStartPos)
|
xue@0
|
3254 {
|
xue@0
|
3255 if (FStartPos==AStartPos) return;
|
xue@0
|
3256 if (AStartPos>FEndPos) throw(EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
|
xue@0
|
3257 bool willdozoom=true;
|
xue@0
|
3258 if (willdozoom)
|
xue@0
|
3259 {
|
xue@0
|
3260 FStartPos=AStartPos;
|
xue@0
|
3261 Invalidate();
|
xue@0
|
3262 PageChange();
|
xue@0
|
3263 }
|
xue@0
|
3264 }
|
xue@0
|
3265
|
xue@0
|
3266 void __fastcall TWaveView::SetStartAndEndPos(int AStartPos, int AnEndPos)
|
xue@0
|
3267 {
|
xue@0
|
3268 if (FStartPos==AStartPos && FEndPos==AnEndPos) return;
|
xue@0
|
3269 if (AStartPos>AnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
|
xue@0
|
3270 bool willdozoom=true;
|
xue@0
|
3271 if (willdozoom)
|
xue@0
|
3272 {
|
xue@0
|
3273 FStartPos=AStartPos;
|
xue@0
|
3274 FEndPos=AnEndPos;
|
xue@0
|
3275 Invalidate();
|
xue@0
|
3276 PageChange();
|
xue@0
|
3277 }
|
xue@0
|
3278 }
|
xue@0
|
3279
|
xue@0
|
3280 void __fastcall TWaveView::SetTools(TWaveViewTools ATools)
|
xue@0
|
3281 {
|
xue@0
|
3282 FTools=ATools;
|
xue@0
|
3283 }
|
xue@0
|
3284
|
xue@0
|
3285 void __fastcall TWaveView::SetStartAndEndDigiFreq(double AStartDigiFreq, double AnEndDigiFreq)
|
xue@0
|
3286 {
|
xue@0
|
3287 if (FStartDigiFreq==AStartDigiFreq && FEndDigiFreq==AnEndDigiFreq) return;
|
xue@0
|
3288 if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartDigiFreq must be no bigger than EndDigiFreq."));
|
xue@0
|
3289 FStartDigiFreq=AStartDigiFreq;
|
xue@0
|
3290 FEndDigiFreq=AnEndDigiFreq;
|
xue@0
|
3291 Invalidate();
|
xue@0
|
3292 }
|
xue@0
|
3293
|
xue@0
|
3294 void __fastcall TWaveView::SetWaveAudio(TWaveAudio* AWaveAudio)
|
xue@0
|
3295 {
|
xue@0
|
3296 //* tends to cause comfliction, use only when FWaveAudio!=AWaveAudio
|
xue@0
|
3297 if (FWaveAudio) FWaveAudio->OnAudioChange=NULL;
|
xue@0
|
3298
|
xue@0
|
3299 FWaveAudio=AWaveAudio;
|
xue@0
|
3300
|
xue@0
|
3301 if (FWaveAudio)
|
xue@0
|
3302 {
|
xue@0
|
3303 if (FStartDigiFreq<0) FStartDigiFreq=0, FEndDigiFreq=0.5;
|
xue@0
|
3304 FWaveAudio->OnAudioChange=WaveViewAudioChange;
|
xue@0
|
3305
|
xue@0
|
3306 FreeData(FChannels);
|
xue@0
|
3307 FreeInternalBitmaps(FChannels);
|
xue@0
|
3308 ClearSpectrograms();
|
xue@0
|
3309
|
xue@0
|
3310 FChannels=FWaveAudio->Channels;
|
xue@0
|
3311 FBytesPerSample=FWaveAudio->BitsPerSample/8;
|
xue@0
|
3312 FLength=FWaveAudio->WaveStream->Size/FChannels/FBytesPerSample;
|
xue@0
|
3313 FBlockSize=FWaveAudio->BlockSize;
|
xue@0
|
3314 SamplesPerSec=FWaveAudio->SamplesPerSec;
|
xue@0
|
3315
|
xue@0
|
3316 if (FLength)
|
xue@0
|
3317 {
|
xue@0
|
3318 for (int i=0; i<FChannels; i++)
|
xue@0
|
3319 {
|
xue@0
|
3320 FData[i]=new unsigned char[FLength*FBytesPerSample];
|
xue@0
|
3321 FSpectrogram[i]->Data=FData[i];
|
xue@0
|
3322 FSpectrogram[i]->WinType=FSpecWindowType;
|
xue@0
|
3323 FSpectrogram[i]->Wid=FSpecRes;
|
xue@0
|
3324 FSpectrogram[i]->Offst=FSpecOffst;
|
xue@0
|
3325 FSpectrogram[i]->WinParam=FSpecWindowParamD[0];
|
xue@0
|
3326 FSpectrogram[i]->BytesPerSample=FBytesPerSample;
|
xue@0
|
3327 FSpectrogram[i]->DataLength=FLength;
|
xue@0
|
3328 }
|
xue@0
|
3329 }
|
xue@0
|
3330
|
xue@0
|
3331 Retrieve();
|
xue@0
|
3332
|
xue@0
|
3333 FStartPos=0;
|
xue@0
|
3334 FEndPos=FLength;
|
xue@0
|
3335 FSelections->Clear();
|
xue@0
|
3336
|
xue@0
|
3337 if (FScrollBar)
|
xue@0
|
3338 {
|
xue@0
|
3339 FScrollBar->PageSize=0;
|
xue@0
|
3340 FScrollBar->OnChange=NULL;
|
xue@0
|
3341 FScrollBar->SetParams(0, 0, (FLength-1>0)?FLength-1:1);
|
xue@0
|
3342 FScrollBar->OnChange=ScrollBarChange;
|
xue@0
|
3343 FScrollBar->LargeChange=FLength/10;
|
xue@0
|
3344 }
|
xue@0
|
3345 }
|
xue@0
|
3346 UndoExtractSelection.EndPos=-1;
|
xue@0
|
3347 PageChange();
|
xue@0
|
3348 Invalidate();
|
xue@0
|
3349 }
|
xue@0
|
3350
|
xue@0
|
3351 void __fastcall TWaveView::SetWaveBackColor(TColor AWaveBackColor)
|
xue@0
|
3352 {
|
xue@0
|
3353 if (FWaveBackColor!=AWaveBackColor)
|
xue@0
|
3354 {
|
xue@0
|
3355 FWaveBackColor=AWaveBackColor;
|
xue@0
|
3356 FWaveColor2=TColor((AWaveBackColor+FWaveColor)/2);
|
xue@0
|
3357 Invalidate();
|
xue@0
|
3358 }
|
xue@0
|
3359 }
|
xue@0
|
3360
|
xue@0
|
3361 void __fastcall TWaveView::SetWaveColor(TColor AWaveColor)
|
xue@0
|
3362 {
|
xue@0
|
3363 if (FWaveColor!=AWaveColor)
|
xue@0
|
3364 {
|
xue@0
|
3365 FWaveColor=AWaveColor;
|
xue@0
|
3366 FWaveColor2=TColor((AWaveColor+FWaveBackColor)/2);
|
xue@0
|
3367 }
|
xue@0
|
3368 }
|
xue@0
|
3369
|
xue@0
|
3370 void __fastcall TWaveView::SetYScale(int index, int yscale)
|
xue@0
|
3371 {
|
xue@0
|
3372 FPanes.YScale[index]=yscale;
|
xue@0
|
3373 if (Visible) Invalidate();
|
xue@0
|
3374 }
|
xue@0
|
3375
|
xue@0
|
3376 void __fastcall TWaveView::SetYZoomRate(double AYZoomRate)
|
xue@0
|
3377 {
|
xue@0
|
3378 FYZoomRate=AYZoomRate;
|
xue@0
|
3379 Invalidate();
|
xue@0
|
3380 if (FOnScaleChange) FOnScaleChange(this);
|
xue@0
|
3381 }
|
xue@0
|
3382
|
xue@0
|
3383 void TWaveView::StartDrag(int aX, int aY)
|
xue@0
|
3384 {
|
xue@0
|
3385 FStartSelX=aX;
|
xue@0
|
3386 FStartSelY=aY;
|
xue@0
|
3387 FStartSelSel=CurrentRange;
|
xue@0
|
3388 }
|
xue@0
|
3389
|
xue@0
|
3390 void __fastcall TWaveView::StartPlayback(TObject* Sender)
|
xue@0
|
3391 {
|
xue@0
|
3392 if (FBeforePlayback) FBeforePlayback(this);
|
xue@0
|
3393 if (FLength<1) return;
|
xue@0
|
3394
|
xue@0
|
3395 if (!FSection->Playing)
|
xue@0
|
3396 {
|
xue@0
|
3397 int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2;
|
xue@0
|
3398
|
xue@0
|
3399 loopframe0=0;
|
xue@0
|
3400 loopframe1=0;
|
xue@0
|
3401 prevk=-1;
|
xue@0
|
3402
|
xue@0
|
3403 FSection->CustomFillBlock=FillBlock;
|
xue@0
|
3404 FSectionBlocks=0;
|
xue@0
|
3405
|
xue@0
|
3406 FSection->Clear(this);
|
xue@0
|
3407 FSection->Channels=FChannels;
|
xue@0
|
3408 FSection->BlockSize=FBlockSize;
|
xue@0
|
3409 FSection->BitsPerSample=PlayBytesPerSample*8;
|
xue@0
|
3410 FSection->SamplesPerSec=FSamplesPerSec;
|
xue@0
|
3411 if (FSamplesPerSec>0) FSection->SamplesPerSec=FSamplesPerSec;
|
xue@0
|
3412 if (FStereoMode==wvpLeft || FStereoMode==wvpRight) FSection->Channels=1;
|
xue@0
|
3413 if (FSection->Channels>2) FSection->Channels=2;
|
xue@0
|
3414 FSection->OnPlaybackProg=WaveViewSectionPlaybackProg;
|
xue@0
|
3415 FSectionProgress=-1;
|
xue@0
|
3416
|
xue@0
|
3417 //if the playback starts from outside the focused selection according to mouse pointer
|
xue@0
|
3418 if (FStartSelR<FSelections->StartPos||FStartSelR>=FSelections->EndPos||
|
xue@0
|
3419 FPanes.HasFreqAxis[FStartPane] && (FVStartSelR<FSelections->StartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq))
|
xue@0
|
3420 {
|
xue@0
|
3421 if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, false);
|
xue@0
|
3422 else FSectionStartPos=FStartPos, FSectionEndPos=FLength;
|
xue@0
|
3423 if (LoopPlay) LoopMode=1;
|
xue@0
|
3424 }
|
xue@0
|
3425 else //the playback starts from inside the focused selection
|
xue@0
|
3426 {
|
xue@0
|
3427 if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, true);
|
xue@0
|
3428 else
|
xue@0
|
3429 {
|
xue@0
|
3430 FSectionStartPos=FSelections->StartPos; if (FSectionStartPos<0) FSectionStartPos=0;
|
xue@0
|
3431 FSectionEndPos=FSelections->EndPos; if (FSectionEndPos>FLength) FSectionEndPos=FLength;
|
xue@0
|
3432 }
|
xue@0
|
3433 if (LoopPlay) LoopMode=2;
|
xue@0
|
3434 }
|
xue@0
|
3435
|
xue@0
|
3436 if (FSectionEndPos>FSectionStartPos)
|
xue@0
|
3437 {
|
xue@0
|
3438 int PlayBufferSize=FSection->BlockSize/PlayBytesPerSample+FSpecRes;
|
xue@0
|
3439 if (FSection->Channels!=2)
|
xue@0
|
3440 {
|
xue@0
|
3441 PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize); PlayBuffer1=0;
|
xue@0
|
3442 memset(PlayBuffer0, 0, sizeof(double)*FSpecRes);
|
xue@0
|
3443 }
|
xue@0
|
3444 else
|
xue@0
|
3445 {
|
xue@0
|
3446 PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize*2); PlayBuffer1=&PlayBuffer0[PlayBufferSize];
|
xue@0
|
3447 memset(PlayBuffer0, 0, sizeof(double)*FSpecRes); memset(PlayBuffer1, 0, sizeof(double)*FSpecRes);
|
xue@0
|
3448 }
|
xue@0
|
3449 PBPR=FSectionStartPos, PBPA=0, PBPW=0;
|
xue@0
|
3450 if (FForceHamming) fw1=NewWindow8(wtHamming, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
|
xue@0
|
3451 else fw1=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
|
xue@0
|
3452 fw2=NewWindow8(wtHann, FSpecRes, NULL, NULL, 0); fw2_fw1=(double*)malloc8(sizeof(double)*FSpecRes*2); ifw1=&fw2_fw1[FSpecRes];
|
xue@0
|
3453 if (fw1[0]==0) ifw1[0]=fw2_fw1[0]=0; else {ifw1[0]=1.0/fw1[0]; fw2_fw1[0]=fw2[0]*ifw1[0];}
|
xue@0
|
3454 for (int i=1; i<FSpecRes; i++) {ifw1[i]=1.0/fw1[i]; fw2_fw1[i]=fw2[i]*ifw1[i];}
|
xue@0
|
3455
|
xue@0
|
3456 FSection->Play(&WaveViewSectionPlaybackDone);
|
xue@0
|
3457 ItemPlay->Caption=WV2_STRINGS_Stop_playback;
|
xue@0
|
3458 if (FOnPlaybackStart) FOnPlaybackStart(this);
|
xue@0
|
3459 }
|
xue@0
|
3460 }
|
xue@0
|
3461 else
|
xue@0
|
3462 {
|
xue@0
|
3463 PausePlayback(this);
|
xue@0
|
3464 }
|
xue@0
|
3465 }
|
xue@0
|
3466
|
xue@0
|
3467 void __fastcall TWaveView::TFFilter(int channel, bool pass, bool wholelength)
|
xue@0
|
3468 {
|
xue@0
|
3469 ::TFFilter(this, channel, FSelections, pass, wholelength);
|
xue@0
|
3470 }
|
xue@0
|
3471
|
xue@0
|
3472 void __fastcall TWaveView::UndoExtract(TObject* Sender)
|
xue@0
|
3473 {
|
xue@0
|
3474 SetArea(UndoExtractSelection.StartPos, UndoExtractSelection.EndPos, UndoExtractSelection.StartDigiFreq, UndoExtractSelection.EndDigiFreq);
|
xue@0
|
3475 UndoExtractSelection.EndPos=-1;
|
xue@0
|
3476 }
|
xue@0
|
3477
|
xue@0
|
3478 void __fastcall TWaveView::UpdateScrollBar(TObject* Sender)
|
xue@0
|
3479 {
|
xue@0
|
3480 TNotifyEvent SBChange=FScrollBar->OnChange;
|
xue@0
|
3481 FScrollBar->OnChange=NULL;
|
xue@0
|
3482 if (FEndPos-FStartPos>=FLength)
|
xue@0
|
3483 {
|
xue@0
|
3484 FScrollBar->PageSize=FLength;
|
xue@0
|
3485 FScrollBar->SetParams(FStartPos, 0, FLength);
|
xue@0
|
3486 ScrollBar->Visible=false;
|
xue@0
|
3487 }
|
xue@0
|
3488 else
|
xue@0
|
3489 {
|
xue@0
|
3490 FScrollBar->SetParams(FStartPos, 0, FLength);
|
xue@0
|
3491 FScrollBar->PageSize=FEndPos-FStartPos;
|
xue@0
|
3492 int change=FScrollBar->PageSize/10;
|
xue@0
|
3493 if (change>FSamplesPerSec/2) change=FSamplesPerSec/2;
|
xue@0
|
3494 FScrollBar->SmallChange=change;
|
xue@0
|
3495 change=FScrollBar->PageSize*0.9;
|
xue@0
|
3496 if (change>FSamplesPerSec) change=FSamplesPerSec;
|
xue@0
|
3497 FScrollBar->LargeChange=change;
|
xue@0
|
3498 FScrollBar->Visible=true;
|
xue@0
|
3499 }
|
xue@0
|
3500 FScrollBar->OnChange=SBChange;
|
xue@0
|
3501 }
|
xue@0
|
3502
|
xue@0
|
3503 void __fastcall TWaveView::WaveViewAudioChange(TObject* Sender)
|
xue@0
|
3504 {
|
xue@0
|
3505 WaveAudio=FWaveAudio;
|
xue@0
|
3506 if (WaveAudio==FWaveAudio && FSection->Playing && true)
|
xue@0
|
3507 {
|
xue@0
|
3508 FSectionStartPos=FStartPos;
|
xue@0
|
3509 FSectionEndPos=FEndPos;
|
xue@0
|
3510 }
|
xue@0
|
3511 }
|
xue@0
|
3512
|
xue@0
|
3513 void __fastcall TWaveView::WaveViewHitTest(int X, int Y)
|
xue@0
|
3514 {
|
xue@0
|
3515 FCurrentPane=-1;
|
xue@0
|
3516 for (int i=0; i<FPanes.Count; i++)
|
xue@0
|
3517 {
|
xue@0
|
3518 TRect Rect=FPanes.Rect[i];
|
xue@0
|
3519 if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
|
xue@0
|
3520 {
|
xue@0
|
3521 FCurrentPane=i;
|
xue@0
|
3522 FCurrentTime1=FPTS(i, X); FCurrentTime2=FPTS(i, X+1);
|
xue@0
|
3523 FCurrentDigiFreq2=FPTDF(i, Y); FCurrentDigiFreq1=FPTDF(i, Y+1);
|
xue@0
|
3524 break;
|
xue@0
|
3525 }
|
xue@0
|
3526 }
|
xue@0
|
3527
|
xue@0
|
3528 InfoRectAtPointer=-1;
|
xue@0
|
3529 if (FShowInfo)
|
xue@0
|
3530 {
|
xue@0
|
3531 for (int i=0; i<InfoRectCount; i++)
|
xue@0
|
3532 {
|
xue@0
|
3533 TRect Rect=InfoRect[i];
|
xue@0
|
3534 if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
|
xue@0
|
3535 {
|
xue@0
|
3536 InfoRectAtPointer=i;
|
xue@0
|
3537 break;
|
xue@0
|
3538 }
|
xue@0
|
3539 }
|
xue@0
|
3540 }
|
xue@0
|
3541
|
xue@0
|
3542 GetObjectAtPointer(X, Y);
|
xue@0
|
3543 }
|
xue@0
|
3544
|
xue@0
|
3545 void __fastcall TWaveView::WaveViewSectionPlaybackDone(TObject* Sender)
|
xue@0
|
3546 {
|
xue@0
|
3547 ItemPlay->Caption=WV2_STRINGS_Play;
|
xue@0
|
3548
|
xue@0
|
3549 if (PlayBuffer0)
|
xue@0
|
3550 {
|
xue@0
|
3551 free8(PlayBuffer0);
|
xue@0
|
3552 PlayBuffer0=0;
|
xue@0
|
3553 free8(fw1); free8(fw2); free8(fw2_fw1);
|
xue@0
|
3554 }
|
xue@0
|
3555
|
xue@0
|
3556 FSectionProgress=-1;
|
xue@0
|
3557 free8(loopframe0);
|
xue@0
|
3558 free8(loopframe1);
|
xue@0
|
3559 if (FOnPlaybackDone) FOnPlaybackDone(this);
|
xue@0
|
3560 }
|
xue@0
|
3561
|
xue@0
|
3562 void __fastcall TWaveView::WaveViewSectionPlaybackProg(TObject* Sender, double Progress)
|
xue@0
|
3563 {
|
xue@0
|
3564 if (FProgressCursor)
|
xue@0
|
3565 {
|
xue@0
|
3566 FSectionProgress=PBPR-FSpecRes/2;
|
xue@0
|
3567 if (AutoScroll && PBPR>FEndPos)
|
xue@0
|
3568 {
|
xue@0
|
3569 int len=FEndPos-FStartPos;
|
xue@0
|
3570 int newen=FEndPos+len;
|
xue@0
|
3571 if (newen>FLength) newen=FLength;
|
xue@0
|
3572 SetStartAndEndPos(newen-len, newen);
|
xue@0
|
3573 }
|
xue@0
|
3574 Invalidate();
|
xue@0
|
3575 }
|
xue@0
|
3576 }
|
xue@0
|
3577
|
xue@0
|
3578 void __fastcall TWaveView::Zoom(int X, double Rate)
|
xue@0
|
3579 {
|
xue@0
|
3580 int X1,X2;
|
xue@0
|
3581 bool pagechange=false;
|
xue@0
|
3582
|
xue@0
|
3583 if (Rate<=0){X1=0; X2=FLength;}
|
xue@0
|
3584 else
|
xue@0
|
3585 {
|
xue@0
|
3586 X1=FStartPos-X; X2=FEndPos-X;
|
xue@0
|
3587 X1=floor(X1*Rate); X2=ceil(X2*Rate);
|
xue@0
|
3588 X1+=X; X2+=X;
|
xue@0
|
3589 if (X1<0) X1=0; if (X2>Length) X2=Length;
|
xue@0
|
3590 if (X1>=X2) X1=X2-1;
|
xue@0
|
3591 }
|
xue@0
|
3592
|
xue@0
|
3593 if (FStartPos!=X1) FStartPos=X1, pagechange=true;
|
xue@0
|
3594 if (FEndPos!=X2) FEndPos=X2, pagechange=true;
|
xue@0
|
3595 if (pagechange)
|
xue@0
|
3596 {
|
xue@0
|
3597 Invalidate();
|
xue@0
|
3598 PageChange();
|
xue@0
|
3599 }
|
xue@0
|
3600 }
|
xue@0
|
3601
|
xue@0
|
3602 void __fastcall TWaveView::ZoomF(double Y, double Rate, int yscale)
|
xue@0
|
3603 {
|
xue@0
|
3604 double Y1, Y2;
|
xue@0
|
3605
|
xue@0
|
3606 if (Rate<=0) {Y1=0; Y2=0.5;}
|
xue@0
|
3607 else
|
xue@0
|
3608 {
|
xue@0
|
3609 if (yscale==0) //linear scale
|
xue@0
|
3610 {
|
xue@0
|
3611 Y1=FStartDigiFreq-Y; Y2=FEndDigiFreq-Y;
|
xue@0
|
3612 Y1=Y1*Rate; Y2=Y2*Rate;
|
xue@0
|
3613 Y1+=Y; Y2+=Y;
|
xue@0
|
3614 if (Y1<0) Y1=0; if (Y2>0.5) Y2=0.5;
|
xue@0
|
3615 }
|
xue@0
|
3616 else //log scale
|
xue@0
|
3617 {
|
xue@0
|
3618 double AStartDigiFreq=(FStartDigiFreq>WV2_MIN_LOG_FREQ)?FStartDigiFreq:WV2_MIN_LOG_FREQ;
|
xue@0
|
3619 double AnEndDigiFreq=(FEndDigiFreq>WV2_MIN_LOG_FREQ)?FEndDigiFreq:WV2_MIN_LOG_FREQ;
|
xue@0
|
3620 if (Y<WV2_MIN_LOG_FREQ) Y=WV2_MIN_LOG_FREQ;
|
xue@0
|
3621 Y1=AStartDigiFreq/Y; Y2=AnEndDigiFreq/Y;
|
xue@0
|
3622 Y1=pow(Y1, Rate); Y2=pow(Y2, Rate);
|
xue@0
|
3623 Y1*=Y; Y2*=Y;
|
xue@0
|
3624 if (Y1<0) Y1=0; if (Y2>0.5) Y2=0.5;
|
xue@0
|
3625 }
|
xue@0
|
3626 }
|
xue@0
|
3627
|
xue@0
|
3628 if (FStartDigiFreq!=Y1 || FEndDigiFreq!=Y2)
|
xue@0
|
3629 {
|
xue@0
|
3630 FStartDigiFreq=Y1, FEndDigiFreq=Y2;
|
xue@0
|
3631 Invalidate();
|
xue@0
|
3632 }
|
xue@0
|
3633 }
|
xue@0
|
3634
|
xue@0
|
3635 void __fastcall TWaveView::ZoomY(double Rate)
|
xue@0
|
3636 {
|
xue@0
|
3637 FYZoomRate*=Rate;
|
xue@0
|
3638 Invalidate();
|
xue@0
|
3639 }
|
xue@0
|
3640
|
xue@0
|
3641 //---------------------------------------------------------------------------
|
xue@0
|
3642 //---------------------------------------------------------------------------
|
xue@0
|
3643 // ValidCtrCheck is used to assure that the components created do not have
|
xue@0
|
3644 // any pure virtual functions.
|
xue@0
|
3645 //
|
xue@0
|
3646 namespace Waveview
|
xue@0
|
3647 {
|
xue@0
|
3648 void __fastcall PACKAGE Register()
|
xue@0
|
3649 {
|
xue@0
|
3650 TComponentClass classes[1] = {__classid(TWaveView)};
|
xue@0
|
3651 RegisterComponents("Samples", classes, 0);
|
xue@0
|
3652 }
|
xue@0
|
3653 }
|
xue@0
|
3654 //---------------------------------------------------------------------------
|
xue@0
|
3655
|
xue@0
|
3656 #undef USE_ASM
|