annotate WaveView.cpp @ 1:f3fd4e19cec0 tip

first binary upload
author wenx <xue.wen@eecs.qmul.ac.uk>
date Wed, 10 Aug 2011 14:56:28 +0100
parents a6a46af64546
children
rev   line source
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