xue@0: /* xue@0: Harmonic Visualiser xue@0: xue@0: An audio file viewer and editor. xue@0: Centre for Digital Music, Queen Mary, University of London. xue@0: This file copyright 2011 Wen Xue. xue@0: xue@0: This program is free software; you can redistribute it and/or xue@0: modify it under the terms of the GNU General Public License as xue@0: published by the Free Software Foundation; either version 2 of the xue@0: License, or (at your option) any later version. xue@0: */ xue@0: //--------------------------------------------------------------------------- xue@0: #include xue@0: #include xue@0: #pragma hdrstop xue@0: xue@0: #include "WaveView.h" xue@0: #include xue@0: #include xue@0: #pragma package(smart_init) xue@0: #define HEIGHT (Height) xue@0: #define WIDTH (Width) xue@0: #define FATP FromAmplitudeToPixel xue@0: #define FPTA FromPixelToAmplitude xue@0: #define FDFTP FromDigiFreqToPixel xue@0: #define FPTDF FromPixelToDigiFreq xue@0: #define FPTS FromPixelToSample xue@0: #define FSTP FromSampleToPixel xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void DoubleToInt(void* out, int BytesPerSample, double* in, int Count) xue@0: { xue@0: if (BytesPerSample==1){unsigned char* out8=(unsigned char*)out; for (int k=0; k>8;} xue@0: } xue@0: xue@0: //dest-=src*amp xue@0: void MultiSub(void* dest, void* src, int BytesPerSample, double* amp, int Count) xue@0: { xue@0: if (BytesPerSample==1){unsigned char *dest8=(unsigned char*)dest, *src8=(unsigned char*)src; for (int k=0; kSamplesPerSec; xue@0: double Sps25=Sps/4.0; __int16 data[48000]; int amp=2048, har=3; xue@0: if (semitone) f=440*pow(2.0l, floor(Log2(f/440)*12+0.5)/12.0); xue@0: if (f<200) har=600/f, amp*=pow(200/f, 0.7); xue@0: for (int i=0; iWriteSamples(data, Sps); xue@0: AnsiString FileName=ExtractFilePath(Application->ExeName)+"temp0"; xue@0: WV->SaveToFile(FileName); delete WV; xue@0: PlaySound(FileName.c_str(), 0, SND_FILENAME|SND_ASYNC); xue@0: } xue@0: xue@0: AnsiString SemitoneToPitch(double f) xue@0: { xue@0: static char* notename[]={"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; xue@0: int fd=floor(f+0.5); xue@0: double fr=f-fd; xue@0: int oct=floor(fd/12.0); xue@0: int note=fd-oct*12; xue@0: int fr2=floor(fr*100+0.5); xue@0: if (fr2==0) return AnsiString().sprintf("%s%d", notename[note], oct+4, fr2); xue@0: else if (fr2>0) xue@0: { xue@0: if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d+.%d", notename[note], oct+4, fr2);} xue@0: else return AnsiString().sprintf("%s%d+.%02d", notename[note], oct+4, fr2); xue@0: } xue@0: else xue@0: { xue@0: fr2=-fr2; xue@0: if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d-.%d", notename[note], oct+4, fr2);} xue@0: else return AnsiString().sprintf("%s%d-.%02d", notename[note], oct+4, fr2); xue@0: } xue@0: } xue@0: xue@0: void TextOutline(TCanvas* Canv, AnsiString Text, int X, int Y, TColor FC, TColor BC) xue@0: { xue@0: Canv->Font->Color=BC; Canv->TextOut(X-1, Y, Text); Canv->TextOut(X+1, Y, Text); Canv->TextOut(X, Y-1, Text); xue@0: Canv->TextOut(X, Y+1, Text); Canv->Font->Color=FC; Canv->TextOut(X, Y, Text); xue@0: } xue@0: xue@0: //* xue@0: //TFFilter: TF-filtering with cosinal interpolation xue@0: //Identical data and dataout allowed. xue@0: void TFFilter(TWaveView* WV, int Channel, TWaveViewSelections* Selections, bool Pass, bool allduration=false) xue@0: { xue@0: int Count=WV->Length, Wid=WV->SpecRes, Offst=WV->SpecOffst; xue@0: int hWid=Wid/2, Order=Log2(Wid), frst, fren; xue@0: { xue@0: int Fr=(Count-Wid)/Offst+1; xue@0: if (allduration) frst=0, fren=Fr; xue@0: else xue@0: { xue@0: frst=floor((WV->StartPos-hWid)*1.0/Offst+0.5); if (frst<0) frst=0; xue@0: fren=floor((WV->EndPos-hWid)*1.0/Offst+0.5); if (fren>Fr) fren=Fr; xue@0: } xue@0: } xue@0: int frcount=fren-frst; xue@0: int** filter=new int*[frcount]; //signals if man atom is kept or discarded xue@0: filter[0]=new int[frcount*Wid]; for (int i=1; iCount; i++) xue@0: { xue@0: int lx1, lx2, ly1, ly2; xue@0: lx1=floor((Selections->Items[i].StartPos-hWid)*1.0/Offst+0.5)-frst; xue@0: lx2=floor((Selections->Items[i].EndPos-hWid)*1.0/Offst+0.5)-frst; xue@0: ly1=Selections->Items[i].StartDigiFreq*Wid; xue@0: ly2=Selections->Items[i].EndDigiFreq*Wid; xue@0: if (lx1<0) lx1=0; if (lx2>=frcount) lx2=frcount-1; xue@0: if (ly1<0) ly1=0; if (ly1>hWid) ly1=hWid; xue@0: if (Pass) for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=1; xue@0: else for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=0; xue@0: } xue@0: double* lxfr=new double[frcount]; //the ratio of kept atoms of each frame xue@0: for (int i=0; ifwin; //this is the one used to compute Spec xue@0: double* wini=NewWindow8(wtHann, Wid, NULL, NULL, 0); //this is an idea COLA window xue@0: if (hWid!=Offst){double tmp=Offst*1.0/hWid; for (int i=0; iSpecWindowType==wtHann) winrec=0; xue@0: else xue@0: { xue@0: winrec=new double[Wid]; xue@0: for (int i=0; iBytesPerSample; xue@0: char* data8=&WV->Data8[Channel][frst*Offst*bps]; xue@0: xue@0: for (int fr=0; frSpec[Channel][frst+fr]; xue@0: } xue@0: xue@0: int prefetchcount=Wid/Offst; xue@0: char** prefetch=new char*[prefetchcount]; prefetch[0]=new char[prefetchcount*bps*Wid]; for (int i=1; i* spec=WV->Spec[Channel][frst+fr]; xue@0: for (int i=0; i<=hWid; i++) xue@0: if (filter[fr][i]==0) x[i]=spec[i]; xue@0: else x[i]=0; xue@0: CIFFTR(x, Order, w, ldata, hbitinv); xue@0: if (winrec) for (int i=0; ifw; xue@0: x=WV->fx; xue@0: win=WV->fwin; xue@0: hbi=WV->fhbi; xue@0: } xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: static inline void ValidCtrCheck(TWaveView *) xue@0: { xue@0: new TWaveView(NULL); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: __fastcall TWaveView::TWaveView(TComponent* Owner, bool usex, bool usep) xue@0: : TCustomControl(Owner) xue@0: { xue@0: if (!dynamic_cast(Owner)) xue@0: Parent=dynamic_cast(Owner); xue@0: xue@0: DisableMouseWheelZoom=false; xue@0: xue@0: FTools.Clear(); xue@0: FPitchScalePart=1; xue@0: FSectionProgress=-1; xue@0: xue@0: FShowCursor=true; xue@0: FShowCursorText=true; xue@0: FShowInfo=true; xue@0: FShowPaneInfo=true; xue@0: FPlayNoteInSemitone=true; xue@0: xue@0: FAutoSpecAmp=false; xue@0: FSpecAmp=1; xue@0: xue@0: for (int i=0; iColor=FBackColor; xue@0: xue@0: FSelectedAreaColorX=clWhite; xue@0: FSelectedFrameColorX=clWhite; xue@0: FSelectingFrameColorX=clWhite; xue@0: xue@0: Height=150; xue@0: Width=150; xue@0: FWaveAudio=0; xue@0: xue@0: InfoLeft=0; xue@0: InfoTop=0; xue@0: xue@0: FExtractMode=WV2_HSELECT; xue@0: FSelectMode=WV2_HSELECT; xue@0: FOpMode=wopIdle; xue@0: FAutoExtractMode=true; xue@0: FRulerAlignX=alTop; xue@0: FRulerAlignY=alLeft; xue@0: xue@0: FLocalDataOn=false; xue@0: FClickFocus=false; xue@0: FMultiSelect=false; xue@0: FDefaultPopupMenu=true; xue@0: FDefaultPropertyItems=true; xue@0: FProgressCursor=true; xue@0: FYZoomRate=1; xue@0: FStartDigiFreq=0; xue@0: FEndDigiFreq=0.5; xue@0: xue@0: FSelections=new TWaveViewSelections; xue@0: xue@0: FFonts[0]=new TFont; FFonts[0]->Color=clBlue; FFonts[0]->Height=12; FFonts[0]->Name="Ariel"; xue@0: FFonts[1]=new TFont; FFonts[1]->Color=clYellow; FFonts[1]->Height=12; FFonts[1]->Name="Ariel"; xue@0: FFonts[2]=new TFont; FFonts[2]->Color=clYellow; FFonts[2]->Height=12; FFonts[2]->Name="Ariel"; xue@0: FFonts[3]=new TFont; FFonts[3]->Color=clWhite; FFonts[3]->Height=12; FFonts[3]->Name="Ariel"; xue@0: FFonts[4]=new TFont; FFonts[4]->Color=clBlack; FFonts[4]->Height=12; FFonts[4]->Name="Ariel"; xue@0: FFonts[5]=new TFont; FFonts[5]->Color=clBlack; FFonts[5]->Height=12; FFonts[5]->Name="Ariel"; xue@0: xue@0: TWaveViewRulerSetting ASetting={clRed, clWhite, clBlack, TColor(clGray/2), clSilver, 4, 3, FFonts[0], true}; xue@0: DefaultRulerSetting[0]=ASetting; xue@0: TWaveViewRulerSetting ASetting1={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[1], false}; xue@0: DefaultRulerSetting[1]=ASetting1; xue@0: TWaveViewRulerSetting ASetting2={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[2], false}; xue@0: DefaultRulerSetting[2]=ASetting2; xue@0: TWaveViewRulerSetting ASetting3={clRed, clBlack, clYellow, clRed, clBlack, 4, 3, FFonts[3], false}; xue@0: DefaultRulerSetting[3]=ASetting3; xue@0: FRulerUnitTime=0; xue@0: FRulerUnitFreq=0; xue@0: FRulerUnitAmp=0; xue@0: xue@0: DefaultPaneInfoFont=FFonts[4]; xue@0: DefaultInfoFont=FFonts[5]; xue@0: xue@0: ItemExtract=NewItem(WV2_STRINGS_Extract,NULL,false,true,NULL,NULL,"ItemExtract"); xue@0: ItemPlay=NewItem(WV2_STRINGS_Play, NULL,false,true,NULL,NULL,"ItemPlay"); xue@0: ItemProperty=NewItem(WV2_STRINGS_Properties,NULL,false, true,NULL,NULL,"ItemProperty"); xue@0: ItemSeparator1=NewItem("-",NULL,false,false,NULL,NULL,"ItemSeparator1"); xue@0: ItemXZoomRestore=NewItem(WV2_STRINGS_X_zoom_all,NULL,false,true,NULL,NULL,"ItemXZoomRestore"); xue@0: ItemYZoomRestore=NewItem(WV2_STRINGS_Y_zoom_all,NULL,false,true,NULL,NULL,"ItemYZoomRestore"); xue@0: xue@0: TMenuItem** Items=new TMenuItem*[6]; xue@0: Items[0]=ItemExtract; xue@0: Items[1]=ItemPlay; xue@0: Items[2]=ItemProperty; xue@0: Items[3]=ItemSeparator1; xue@0: Items[4]=ItemXZoomRestore; xue@0: Items[5]=ItemYZoomRestore; xue@0: FMenu=NewPopupMenu(this, "FMenu", paLeft, true, Items, 5); xue@0: FMenu->AutoHotkeys=maManual; xue@0: FMenu->OnPopup=FMenuPopup; xue@0: delete[] Items; xue@0: PopupMenu=FMenu; xue@0: xue@0: ItemExtract->OnClick=ItemExtractClick; xue@0: ItemPlay->OnClick=ItemPlayClick; xue@0: ItemProperty->OnClick=ItemPropertyClick; xue@0: ItemXZoomRestore->OnClick=ItemXZoomClick; xue@0: ItemYZoomRestore->OnClick=ItemYZoomClick; xue@0: ItemXZoomRestore->Tag=ITEMXZOOMRESTORE_TAG; xue@0: ItemYZoomRestore->Tag=ITEMYZOOMRESTORE_TAG; xue@0: FScrollBar=0; xue@0: xue@0: CheckWaveOutDevCaps(this); xue@0: xue@0: DoubleBuffered=true; xue@0: xue@0: fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); //fft buffer xue@0: fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes]; //fft buffer xue@0: SetTwiddleFactors(FSpecRes, fw); xue@0: fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); //window function xue@0: fhbi=CreateBitInvTable(Log2(FSpecRes)-1); xue@0: xue@0: memset(Basic0, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL); xue@0: memset(Basic1, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL); xue@0: xue@0: xue@0: xue@0: AutoScroll=false; xue@0: ForceOLA=false; xue@0: LoopPlay=false; xue@0: LoopMode=0; xue@0: } xue@0: xue@0: __fastcall TWaveView::~TWaveView() xue@0: { xue@0: delete FSelections; xue@0: xue@0: FreeData(FChannels); xue@0: FreeInternalBitmaps(FChannels); xue@0: FreeSpectrograms(); xue@0: xue@0: free8(fwin); xue@0: free8(fw); xue@0: free(fhbi); xue@0: xue@0: for (int i=0; iCapacity==0) FS->SetFrCapacity((FLength-FSpecRes)/FSpecOffst+2); xue@0: int calculatefrcount=0; xue@0: for (int x=0; x=0 && frCapacity && (interpolate || ffr-fr<=0.5)) xue@0: { xue@0: if (FS->Frame[fr]<0 || FS->Valid[fr]==0) calculatefrcount++; xue@0: } xue@0: if (fr+1>=0 && fr+1Capacity && (interpolate || ffr-fr>=0.5)) xue@0: { xue@0: if (FS->Frame[fr+1]<0 || FS->Valid[fr+1]==0) calculatefrcount++; xue@0: } xue@0: } xue@0: return calculatefrcount; xue@0: } xue@0: xue@0: //Set the state of Play menuitem according to device capacity xue@0: void __fastcall TWaveView::CheckWaveOutDevCaps(TObject* Sender) xue@0: { xue@0: WAVEOUTCAPS woc; xue@0: if (waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc))==MMSYSERR_NOERROR) xue@0: ItemPlay->Enabled=true; xue@0: else xue@0: ItemPlay->Enabled=false; xue@0: } xue@0: xue@0: void __fastcall TWaveView::ClearSelections(TObject* Sender) xue@0: { xue@0: FSelections->Clear(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::Click() xue@0: { xue@0: if (ObjectAtPointer && ObjectAtPointer->OnClick) ObjectAtPointer->OnClick(this); xue@0: TControl::Click(); xue@0: } xue@0: xue@0: void TWaveView::ClearSpectrogram(int index) xue@0: { xue@0: FSpectrogram[index]->FreeBuffers(); xue@0: } xue@0: xue@0: void TWaveView::ClearSpectrograms() xue@0: { xue@0: for (int i=0; iFreeBuffers(); xue@0: } xue@0: xue@0: TCursor __fastcall TWaveView::ControlCursorAtPos(int X, int Y) xue@0: { xue@0: TWaveViewSelHitTest ht=SelHitTest(X, Y); xue@0: if (ht==selInner) xue@0: return crSizeAll; xue@0: if (ht==selLeft || ht==selRight) xue@0: return crSizeWE; xue@0: if (ht==selTop || ht==selBottom) xue@0: return crSizeNS; xue@0: if (ht==selTopLeft || ht==selBottomRight) xue@0: return crSizeNWSE; xue@0: if (ht==selTopRight || ht==selBottomLeft) xue@0: return crSizeNESW; xue@0: return crArrow; xue@0: } xue@0: xue@0: int __fastcall TWaveView::CreatePanes(int X, int Y) xue@0: { xue@0: return FPanes.CreatePanes(ClientRect, X, Y); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DblClick() xue@0: { xue@0: if (FShowInfo && InfoRectAtPointer>=0 && FOnInfoDblClick) FOnInfoDblClick(this); xue@0: if (ObjectAtPointer && ObjectAtPointer->OnDblClick) ObjectAtPointer->OnDblClick(this); xue@0: TControl::DblClick(); xue@0: } xue@0: xue@0: xue@0: void __fastcall TWaveView::DefaultShowProperty(bool selection) xue@0: { xue@0: if (!selection) xue@0: ShowMessage(AnsiString().sprintf(WV2_STRINGS_1, xue@0: WV2_STRINGS_Properties_current_audio, xue@0: WV2_STRINGS_Time, FEndPos-FStartPos, (FEndPos-FStartPos)*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_From, FStartPos, FStartPos*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_To, FEndPos, FEndPos*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_Frequency, FEndDigiFreq-FStartDigiFreq, xue@0: WV2_STRINGS_From, FStartDigiFreq, xue@0: WV2_STRINGS_To, FEndDigiFreq, xue@0: WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_Samples_per_second, FSamplesPerSec, xue@0: WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample xue@0: )); xue@0: else xue@0: ShowMessage(AnsiString().sprintf(WV2_STRINGS_1, xue@0: WV2_STRINGS_Properties_selection, xue@0: WV2_STRINGS_Time, FSelections->Length, (FSelections->Length)*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_From, FSelections->StartPos, FSelections->StartPos*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_To, FSelections->EndPos, FSelections->EndPos*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_Frequency, FSelections->EndDigiFreq-FSelections->StartDigiFreq, xue@0: WV2_STRINGS_From, FSelections->StartDigiFreq, xue@0: WV2_STRINGS_To, FSelections->EndDigiFreq, xue@0: WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec, xue@0: WV2_STRINGS_Samples_per_second, FSamplesPerSec, xue@0: WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample xue@0: )); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DoExtract(TObject* Sender) xue@0: { xue@0: if (FCustomItemExtractClick) FCustomItemExtractClick(Sender); xue@0: else xue@0: { xue@0: UndoExtractSelection=GetCurrentRange(); xue@0: bool pagechange=false; xue@0: bool spanchange=false; xue@0: if (FExtractMode & WV2_HSELECT) xue@0: { xue@0: if (FEndPos!=FSelections->EndPos) FEndPos=FSelections->EndPos, pagechange=spanchange=true; xue@0: if (FStartPos!=FSelections->StartPos) FStartPos=FSelections->StartPos, pagechange=spanchange=true; xue@0: } xue@0: if (FExtractMode & WV2_VSELECT) xue@0: { xue@0: if (FEndDigiFreq!=FSelections->EndDigiFreq) FEndDigiFreq=FSelections->EndDigiFreq, spanchange=true; xue@0: if (FStartDigiFreq!=FSelections->StartDigiFreq) FStartDigiFreq=FSelections->StartDigiFreq, spanchange=true; xue@0: } xue@0: if (spanchange) Invalidate(); xue@0: if (pagechange) PageChange(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawBitmap(TObject* Sender) xue@0: { xue@0: Graphics::TBitmap* bmp=(Graphics::TBitmap*)Sender; xue@0: Canvas->Draw(0, 0, bmp); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawCaption(AnsiString ACaption) xue@0: { xue@0: TSize ASize=Canvas->TextExtent(ACaption); xue@0: SetBkMode(Canvas->Handle, TRANSPARENT); xue@0: Canvas->TextOut(Width-ASize.cx-4, 2, ACaption); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawCursor(int PaneIndex, int X, int Y) xue@0: { xue@0: int m=FPanes.Margin; xue@0: TRect Rect=FPanes.Rect[PaneIndex]; xue@0: Canvas->Brush->Style=bsSolid; Canvas->Pen->Mode=pmCopy; xue@0: TColor AColor=(FPanes.Type[PaneIndex]==0)?FCursorColorDim:FCursorColorBright; xue@0: Canvas->Brush->Color=AColor; Canvas->Pen->Color=AColor; xue@0: xue@0: int xtip, xbott, ytip, ybott; xue@0: TPoint Points[3]; xue@0: if (FRulerAlignX==alTop) xtip=Rect.top+2, xbott=Rect.top-m+1; xue@0: else xtip=Rect.bottom-2, xbott=Rect.bottom+m-1; xue@0: Points[0]=Point(X, xtip); Points[1]=Point(X-m/2, xbott); Points[2]=Point(X+m/2, xbott); xue@0: Canvas->Polygon(Points, 2); xue@0: if (FRulerAlignY==alLeft) ytip=Rect.left+2, ybott=Rect.left-m+1; xue@0: else ytip=Rect.right-2, ybott=Rect.right+m-1; xue@0: Points[0]=Point(ytip, Y); Points[1]=Point(ybott, Y-m/2); Points[2]=Point(ybott, Y+m/2); xue@0: Canvas->Polygon(Points, 2); xue@0: xue@0: Canvas->Brush->Style=bsClear; xue@0: if (FShowCursorText) xue@0: { xue@0: int type=FPanes.Type[PaneIndex]; xue@0: TWaveViewRulerSetting RS=DefaultRulerSetting[type]; xue@0: Canvas->Font=RS.UnitFont; xue@0: TColor FC=RS.FrontColor, BC=RS.BackColor; xue@0: int textheight=Canvas->TextHeight("0")-2; xue@0: xue@0: TStringList* List; xue@0: if (FCustomCursorText) List=(TStringList*)FCustomCursorText(this); xue@0: else xue@0: { xue@0: List=new TStringList; xue@0: List->Add(CurrentTime); xue@0: List->Add(AnsiString().sprintf("%.4gs", CurrentTime*1.0/FSamplesPerSec)); xue@0: if (FPanes.HasFreqAxis[PaneIndex]) xue@0: { xue@0: List->Add(AnsiString().sprintf("%.1ffr", (this->CurrentTime-FSpecRes/2)*1.0/FSpecOffst)); xue@0: } xue@0: List->Add(""); xue@0: if (FPanes.HasFreqAxis[PaneIndex]) xue@0: { xue@0: double f=CurrentDigiFreq*FSamplesPerSec; xue@0: List->Add(AnsiString().sprintf("%.6ghz", f)); xue@0: List->Add(AnsiString().sprintf("%.5gbin", CurrentDigiFreq*FSpecRes)); xue@0: if (fAdd(SemitoneToPitch(12*Log2(f/C4))); xue@0: } xue@0: else if (FPanes.Type[PaneIndex]==0) xue@0: { xue@0: int a=floor(FPTA(PaneIndex, Y)+0.5); xue@0: List->Add(AnsiString().sprintf("%d", a)); xue@0: } xue@0: } xue@0: xue@0: int i=0, y=(FRulerAlignX==alTop)?xtip:(xtip-textheight), dtextheight=(FRulerAlignX==alTop)?textheight:-textheight; xue@0: while (iCount && List->Strings[i]!="") xue@0: { xue@0: TextOutline(Canvas, List->Strings[i], X-Canvas->TextWidth(List->Strings[i])/2+1, y, FC, BC); xue@0: y+=dtextheight; i++; xue@0: } xue@0: while (iCount && List->Strings[i]=="") i++; xue@0: y=Y-textheight*(List->Count-i)*0.5; xue@0: while (iCount) xue@0: { xue@0: if (FRulerAlignY==alLeft) TextOutline(Canvas, List->Strings[i], ytip, y, FC, BC); xue@0: else TextOutline(Canvas, List->Strings[i], ytip-Canvas->TextWidth(List->Strings[i]), y, FC, BC); xue@0: y+=textheight; i++; xue@0: } xue@0: xue@0: delete List; xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawInfo() xue@0: { xue@0: TStringList* List; xue@0: if (FCustomInfo) List=(TStringList*)FCustomInfo(this); xue@0: else xue@0: { xue@0: List=new TStringList; xue@0: List->Add(AnsiString().sprintf(" %d-channel, %dhz, %dbit. ", FChannels, FSamplesPerSec, FBytesPerSample*8)); xue@0: double fs=FStartPos*1.0/FSamplesPerSec, fe=FEndPos*1.0/FSamplesPerSec; xue@0: List->Add(AnsiString().sprintf(" Time(%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe)); xue@0: List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", FStartDigiFreq*FSamplesPerSec, FEndDigiFreq*FSamplesPerSec)); xue@0: } xue@0: InfoRectCount=List->Count; xue@0: Canvas->Font=DefaultInfoFont; xue@0: Canvas->Brush->Style=bsSolid; Canvas->Font->Color=FInfoColor0; xue@0: int textheight=Canvas->TextHeight("0"); xue@0: int left=InfoLeft, right, top=InfoTop, bottom=top+textheight; xue@0: for (int i=0; iBrush->Color=FInfoColor2; xue@0: Canvas->TextOut(left, top, List->Strings[i]); xue@0: } xue@0: else xue@0: { xue@0: Canvas->Brush->Color=FInfoColor1; xue@0: Canvas->TextOut(left, top, List->Strings[i]); xue@0: } xue@0: right=left+Canvas->TextWidth(List->Strings[i]); xue@0: if (iPen->Color=RS.GridColor; xue@0: int u1=ceil(t1/tick), u2=floor(t2/tick); xue@0: if (u1>=u2) {int u3=u1; u1=u2; u2=u3;} xue@0: for (int u=u1; u<=u2; u++) xue@0: { xue@0: double t=(u*tick-t1)/(t2-t1); xue@0: int pos=Rect.left+(Rect.right-Rect.left)*t; xue@0: Canv->MoveTo(pos, Y0); xue@0: Canv->LineTo(pos, Y1); xue@0: } xue@0: } xue@0: else xue@0: { xue@0: Canv->Brush->Style=bsClear; xue@0: Canv->Font=RS.UnitFont; xue@0: int Y0, Y1tick, Y1unit, YText; xue@0: if (Align==alTop) Y0=Rect.top, Y1tick=Rect.top+RS.TickSize, Y1unit=Rect.top+RS.UnitTickSize, YText=Y1unit; xue@0: else Y0=Rect.bottom, Y1tick=Rect.bottom-RS.TickSize, Y1unit=Rect.bottom-RS.UnitTickSize, YText=Y1unit-Canv->TextHeight("0"); xue@0: xue@0: int u1=ceil(t1/tick), u2=floor(t2/tick); xue@0: if (u1>=u2) {int u3=u1; u1=u2; u2=u3;} xue@0: for (int u=u1; u<=u2; u++) xue@0: { xue@0: double t=(u*tick-t1)/(t2-t1); xue@0: int pos=Rect.left+(Rect.right-Rect.left)*t; xue@0: Canv->MoveTo(pos, Y0); xue@0: if (u%tickperunit==0) xue@0: { xue@0: Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(pos, Y1unit); xue@0: AnsiString text=u*tick; xue@0: TextOutline(Canv, text, pos-Canv->TextWidth(text)/2+1, YText, RS.UnitFont->Color, RS.BackColor); xue@0: } xue@0: else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(pos, Y1tick);} xue@0: } xue@0: } xue@0: } xue@0: xue@0: 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: { xue@0: double trange=fabs(t2-t1); xue@0: if (trange<=0) return; xue@0: double unit=pow(10, floor(Log10(trange))); xue@0: int tickperunit; xue@0: xue@0: trange/=unit; xue@0: if (CustomUnit) CustomUnit(trange, unit, tickperunit); xue@0: else xue@0: { xue@0: if (trange<2) {unit*=0.2; tickperunit=4;} xue@0: else if (trange<5) {unit*=0.5; tickperunit=5;} xue@0: else {tickperunit=5;} xue@0: } xue@0: xue@0: double tick=unit/tickperunit; xue@0: if (!ticking) xue@0: { xue@0: int X0=Rect.left, X1=Rect.right; xue@0: Canv->Pen->Color=RS.GridColor; xue@0: int u1=ceil(t1/tick), u2=floor(t2/tick); xue@0: if (u1>=u2) {int u3=u1; u1=u2; u2=u3;} xue@0: for (int u=u1; u<=u2; u++) xue@0: { xue@0: double t=(u*tick-t1)/(t2-t1); xue@0: int pos=Rect.top+(Rect.bottom-Rect.top)*t; xue@0: Canv->MoveTo(X0, pos); xue@0: Canv->LineTo(X1, pos); xue@0: } xue@0: } xue@0: else xue@0: { xue@0: Canv->Brush->Style=bsClear; xue@0: Canv->Font=RS.UnitFont; xue@0: int X0, X1tick, X1unit, XText; xue@0: if (Align==alLeft) X0=Rect.left, X1tick=Rect.left+RS.TickSize, X1unit=Rect.left+RS.UnitTickSize, XText=X1unit; xue@0: else X0=Rect.right, X1tick=Rect.right-RS.TickSize, X1unit=Rect.right-RS.UnitTickSize, XText=X1unit; xue@0: xue@0: int u1=ceil(t1/tick), u2=floor(t2/tick); xue@0: if (u1>=u2) {int u3=u1; u1=u2; u2=u3;} xue@0: for (int u=u1; u<=u2; u++) xue@0: { xue@0: double t=(u*tick-t1)/(t2-t1); xue@0: int pos=Rect.top+(Rect.bottom-Rect.top)*t; xue@0: Canv->MoveTo(X0, pos); xue@0: if (u%tickperunit==0) xue@0: { xue@0: Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(X1unit, pos); xue@0: AnsiString text=CustomText?CustomText(u*tick):AnsiString(u*tick); xue@0: TextOutline(Canv, text, (Align==alLeft)?XText:XText-Canv->TextWidth(text), pos-Canv->TextHeight(text)/2, RS.UnitFont->Color, RS.BackColor); xue@0: } xue@0: else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(X1tick, pos);} xue@0: } xue@0: } xue@0: } xue@0: xue@0: AnsiString SemitoneToHz(double f) xue@0: { xue@0: return AnsiString().sprintf("%.1f", 440*pow(2, f/12)); xue@0: } xue@0: xue@0: void SemitoneUnit(double range, double& unit, int& tickperunit) xue@0: { xue@0: if (range<2) {unit*=0.2; tickperunit=4;} xue@0: else if (range<5) {unit*=0.5; tickperunit=5;} xue@0: else {tickperunit=5;} xue@0: xue@0: if (unit>2) xue@0: { xue@0: if (unit<6) unit=6, tickperunit=6; xue@0: else if (unit<12) unit=12, tickperunit=6; xue@0: else if (unit<24) unit=24, tickperunit=6; xue@0: else if (unit<36) unit=36, tickperunit=6; xue@0: else if (unit<48) unit=48, tickperunit=4; xue@0: else unit=60, tickperunit=5; xue@0: } xue@0: else if (unit<0.01) xue@0: { xue@0: unit=0.01; xue@0: tickperunit=5; xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawPane(int Channel, int Type, int YScale, int Rulers, TCanvas* Canv, TRect& Rect) xue@0: { xue@0: if (Channel>=FChannels) return; xue@0: xue@0: Canv->Pen->Mode=pmCopy; Canv->Pen->Style=psSolid; Canv->Brush->Style=bsSolid; xue@0: xue@0: if (Type==0) {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(Rect);} xue@0: xue@0: HRGN Rgn=CreateRectRgn(Rect.left, Rect.top, Rect.right, Rect.bottom); xue@0: SelectClipRgn(Canv->Handle, Rgn); xue@0: xue@0: double TStart, TEnd; xue@0: if (FRulerUnitTime==0) TStart=FStartPos, TEnd=FEndPos; xue@0: else TStart=FStartPos*1.0/FSamplesPerSec, TEnd=FEndPos*1.0/FSamplesPerSec; xue@0: double AStart, AEnd; xue@0: if (FRulerUnitAmp==0) {AStart=-1.0/YZoomRate; AEnd=-AStart;} xue@0: else {AStart=-(1<<(FBytesPerSample*8-1))/YZoomRate; AEnd=-AStart;} xue@0: double FStart, FEnd; AnsiString (*ATranslateFreq)(double); void (*AUnit)(double, double&, int&); xue@0: if (YScale==0) xue@0: { xue@0: if (FRulerUnitFreq==0) FStart=FStartDigiFreq*FSamplesPerSec, FEnd=FEndDigiFreq*FSamplesPerSec; xue@0: else if (FRulerUnitFreq==1) FStart=FStartDigiFreq*FSpecRes, FEnd=FEndDigiFreq*FSpecRes; xue@0: ATranslateFreq=0; AUnit=0; xue@0: } xue@0: else xue@0: { xue@0: FStart=12*Log2(WV2_LOG_FREQ(FStartDigiFreq)*FSamplesPerSec/C4), FEnd=12*Log2(WV2_LOG_FREQ(FEndDigiFreq)*FSamplesPerSec/C4); xue@0: if (FRulerUnitFreq==0) ATranslateFreq=SemitoneToHz; xue@0: else ATranslateFreq=SemitoneToPitch; xue@0: AUnit=SemitoneUnit; xue@0: } xue@0: xue@0: if (DefaultRulerSetting[Type].pre_drawing) xue@0: { xue@0: if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, false); xue@0: if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) {} xue@0: if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, false); xue@0: } xue@0: switch(Type) xue@0: { xue@0: case 0: xue@0: DrawWaveForm(Channel, Canv, Rect, FStartPos, FEndPos, FYZoomRate, true); xue@0: break; xue@0: case 1: xue@0: case 2: xue@0: DrawSpectrogramX(Channel, CurrentRange, YScale, Canv, Rect, FSpecAmp, false, true, Type); xue@0: break; xue@0: } xue@0: xue@0: if (FSelections->Count) DrawSelections(Type, Canv, Rect, YScale); xue@0: if (TWaveViewPanes::FreqAxis(Type) && FTools.Contains(wvtPitchScale)) DrawPitchScale(Type, Canv, Rect, YScale); xue@0: if (FSectionProgress>0 && FProgressCursor) DrawPlaybackCursor(FSectionProgress, Canv, Rect, Type); xue@0: { xue@0: if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, true); xue@0: if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) DrawRulerV(FEnd, FStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true, ATranslateFreq, AUnit); xue@0: if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true); xue@0: } xue@0: xue@0: SelectClipRgn(Canv->Handle, NULL); xue@0: DeleteObject(Rgn); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawPaneInfo(int Channel, int Type, int YScale, TCanvas* Canv, TRect& Rect) xue@0: { xue@0: TStringList* List; xue@0: if (FCustomPaneInfo) List=(TStringList*)FCustomPaneInfo(this); xue@0: else xue@0: { xue@0: List=new TStringList; xue@0: if (FSelections->Count>0 && FSelections->Focus>=0) xue@0: { xue@0: List->Add("Current Selection"); xue@0: List->Add(AnsiString().sprintf("Time: from %d to %d", FSelections->StartPos, FSelections->EndPos)); xue@0: List->Add(AnsiString().sprintf("Frequency: from %.1fhz to %.1fhz", FSelections->StartDigiFreq*FSamplesPerSec, FSelections->EndDigiFreq*FSamplesPerSec)); xue@0: } xue@0: } xue@0: xue@0: if (List->Count>0) xue@0: { xue@0: Canvas->Font=DefaultPaneInfoFont; xue@0: int textheight=Canvas->TextHeight("0"), textwidth=Canvas->TextWidth("0"); xue@0: int height=textheight*List->Count+textheight; xue@0: int width=Canvas->TextWidth(List->Strings[0]); for (int i=1; iCount; i++) {int AW=Canvas->TextWidth(List->Strings[i]); if (widthPen->Style=psClear; Canvas->Pen->Mode=pmMerge; Canvas->Brush->Style=bsSolid; xue@0: if (Type==0) Canvas->Brush->Color=(TColor)RGB(224, 224, 224); xue@0: else Canvas->Brush->Color=TColor(clGray/2); xue@0: Canvas->Rectangle(left, top, right, bottom); xue@0: xue@0: Canvas->Brush->Style=bsClear; xue@0: if (Type==0) Canvas->Font->Color=FCursorColorDim; xue@0: else Canvas->Font->Color=FCursorColorBright; xue@0: for (int i=0; iCount; i++) xue@0: { xue@0: if (FRulerAlignY==alLeft) Canvas->TextOut(right-textwidth-Canvas->TextWidth(List->Strings[i]), top+(i+0.5)*textheight, List->Strings[i]); xue@0: else Canvas->TextOut(left+textwidth, top+(i+0.5)*textheight, List->Strings[i]); xue@0: } xue@0: } xue@0: delete List; xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawPanes(int Type) xue@0: { xue@0: for (int i=0; iBrush->Color=FBackColor; Canvas->FillRect(FPanes.Rect[i]);} xue@0: else xue@0: { xue@0: int type=Content/WV2_MAX_CHANNEL, channel=Content%WV2_MAX_CHANNEL; xue@0: if (Type<0 || Type==type) DrawPane(channel, type, FPanes.YScale[i], FPanes.Rulers[i], Canvas, FPanes.Rect[i]); xue@0: } xue@0: } xue@0: if (FCurrentPane>=0 && FShowPaneInfo) DrawPaneInfo(FCurrentPane, FPanes.Type[FCurrentPane], FPanes.YScale[FCurrentPane], Canvas, FPanes.Rect[FCurrentPane]); xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawPitchScale(int Type, TCanvas* Canv, TRect& Rect, int yscale) xue@0: { xue@0: int pswidth=100; xue@0: int NumberOfTicks=25; xue@0: double endl=0.7; xue@0: int X=FSTP(CurrentTime, Rect.left, Rect.right); xue@0: int X1=X-pswidth, X2=X+pswidth; xue@0: if (X1-Rect.left<(X-Rect.left)*2/3) X1=Rect.left+(X-Rect.left)*2/3; xue@0: if (Rect.right-X2<(Rect.right-X)*2/3) X2=Rect.right-(Rect.right-X)*2/3; xue@0: int psl=X1-X; xue@0: int psr=X2-X; xue@0: xue@0: double f0=CurrentDigiFreq/FPitchScalePart; xue@0: int Y0=FDFTP(f0, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale); xue@0: xue@0: double f6=f0*(NumberOfTicks+3); xue@0: int Y6=FDFTP(f6, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale); xue@0: xue@0: Canvas->Pen->Color=TColor(clGray/2); xue@0: Canvas->Pen->Style=psDot; xue@0: Canvas->MoveTo(X, Y0+5); xue@0: Canvas->LineTo(X, Y6); xue@0: Canvas->MoveTo(X1, Y0); xue@0: Canvas->LineTo(X2, Y0); xue@0: Canvas->Pen->Color=clGray; xue@0: xue@0: for (int k=2; k<=NumberOfTicks; k++) xue@0: { xue@0: f6=(NumberOfTicks-k*endl+1.0)/NumberOfTicks; xue@0: X1=X+psl*f6; xue@0: X2=X+psr*f6; xue@0: Y6=FDFTP(f0*k, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale); xue@0: Canvas->MoveTo(X1, Y6); xue@0: Canvas->LineTo(X2, Y6); xue@0: } xue@0: xue@0: Canvas->Pen->Style=psSolid; xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawPlaybackCursor(int Position, TCanvas* Canv, TRect& Rect, int Type) xue@0: { xue@0: int X=FSTP(Position, Rect.left, Rect.right); xue@0: if (X>=Rect.left && XPen->Mode=pmCopy; xue@0: Canv->Pen->Style=psSolid; xue@0: Canv->Pen->Color=clGreen; xue@0: if (TWaveViewPanes::FreqAxis(Type)) xue@0: { xue@0: Canv->MoveTo(X, Rect.top*0.5+Rect.bottom*0.5); xue@0: Canv->LineTo(X, Rect.bottom); xue@0: } xue@0: else xue@0: { xue@0: Canv->MoveTo(X, Rect.top*0.75+Rect.bottom*0.25); xue@0: Canv->LineTo(X, Rect.top*0.25+Rect.bottom*0.75); xue@0: } xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawSelection(int Type, TCanvas* Canv, TRect& Rect, int yscale, int Index, TColor FrameColorX) xue@0: { xue@0: if (Index<0 || Index>=FSelections->Count) return; xue@0: TWaveViewSelection sel=FSelections->Items[Index]; xue@0: xue@0: double x1=FSTP(sel.StartPos, Rect.left, Rect.right); xue@0: double x2=FSTP(sel.EndPos, Rect.left, Rect.right); xue@0: xue@0: if (!TWaveViewPanes::FreqAxis(Type)) xue@0: { xue@0: Canvas->Pen->Mode=pmCopy; xue@0: // Canvas->Pen->Style=psSolid; xue@0: Canvas->Pen->Color=FrameColorX; xue@0: Canvas->MoveTo(x1, Rect.top); Canvas->LineTo(x1, Rect.bottom); xue@0: Canvas->MoveTo(x2, Rect.top); Canvas->LineTo(x2, Rect.bottom); xue@0: } xue@0: else xue@0: { xue@0: int y2=ceil(FDFTP(sel.StartDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale)); xue@0: int y1=floor(FDFTP(sel.EndDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale)); xue@0: Canvas->Pen->Mode=pmCopy; xue@0: // Canvas->Pen->Style=psSolid; xue@0: Canvas->Pen->Color=FrameColorX; xue@0: Canvas->Brush->Style=bsClear; xue@0: if (x1==x2 || y1==y2) {Canvas->MoveTo(x1, y1); Canvas->LineTo(x2, y2);} xue@0: else Canvas->Rectangle(x1, y1, x2+1, y2+1); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawSelections(int Type, TCanvas* Canv, TRect& Rect, int yscale) xue@0: { xue@0: for (int i=0; iCount; i++) xue@0: { xue@0: if (i==FSelections->Focus && FOpMode<=wopReselect) xue@0: Canvas->Pen->Style=psSolid; xue@0: else xue@0: Canvas->Pen->Style=psDot; xue@0: DrawSelection(Type, Canv, Rect, yscale, i, FSelectedFrameColorX); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawSemitones(int start, int end, TCanvas* Canv, TRect& Rect, int yscale) xue@0: { xue@0: for (int i=start; iPen->Mode=pmXor; xue@0: Canv->Pen->Style=psSolid; xue@0: if (i%12==0) xue@0: Canv->Pen->Color=clGray; xue@0: else xue@0: Canv->Pen->Color=TColor(clGray/2); xue@0: Canv->MoveTo(0, f); xue@0: Canv->LineTo(Width, f); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::DrawSpectrogramX(int channel, TWaveViewSelection Sel, int yscale, TCanvas* ACanvas, TRect ARect, double amp, bool forceresample, bool basic, int specstyle) xue@0: { xue@0: int dX=ARect.Width(), dY=ARect.Height(), HWid=FSpecRes/2; xue@0: double *xx=(double*)malloc8(sizeof(double)*(dX+dY)), *yy=&xx[dX]; xue@0: FPTS(xx, dX, Sel.StartPos, Sel.EndPos); for (int x=0; x0); xue@0: if (!Basic1[channel]) xue@0: { xue@0: Graphics::TBitmap* NewBmp=new Graphics::TBitmap; xue@0: NewBmp->PixelFormat=pf32bit; xue@0: NewBmp->Transparent=true; xue@0: NewBmp->TransparentMode=tmAuto; xue@0: Basic1[channel]=NewBmp; xue@0: resample=true; xue@0: } xue@0: sBasic1Settings BS; BS.X=ARect.Width(), BS.Y=ARect.Height(), BS.Sel=Sel, BS.amp=amp, BS.yscale=yscale, BS.specstyle=specstyle; xue@0: if (Basic1Settings[channel]!=BS) {Basic1Settings[channel]=BS; Basic1[channel]->Width=BS.X; Basic1[channel]->Height=BS.Y; resample=true;} xue@0: xue@0: //resample records sampled range change and picture size change xue@0: if (resample) xue@0: { xue@0: if (FAutoSpecAmp) SetAutomaticSpecAmp(channel, xx, Sel.StartDigiFreq, Sel.EndDigiFreq, BS.X, BS.Y); xue@0: QSPEC_FORMAT maxvisiblespec; xue@0: if (specstyle==1) xue@0: { xue@0: FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; yCopyRect(ARect, Basic1[channel]->Canvas, TRect(0, 0, BS.X, BS.Y)); xue@0: } xue@0: else xue@0: { xue@0: Graphics::TBitmap* bmp=new Graphics::TBitmap; xue@0: bmp->PixelFormat=pf32bit; bmp->Width=ARect.Width(); bmp->Height=ARect.Height(); xue@0: if (specstyle==1) xue@0: { xue@0: FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; yWidth, bmp->Height, amp*ampnorm, interpolate); xue@0: } xue@0: else if (specstyle==2) SamplePeakSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm); xue@0: else if (specstyle==3) SampleSinuSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm); xue@0: ACanvas->CopyRect(ARect, bmp->Canvas, TRect(0, 0, bmp->Width, bmp->Height)); xue@0: delete bmp; xue@0: } xue@0: free8(xx); xue@0: } xue@0: xue@0: void __fastcall DrawWaveForm(TCanvas* Canv, TRect ARect, void* data, int BytesPerSample, int startpos, int endpos, double amp, TColor Color1, TColor Color2) xue@0: { xue@0: int i, j, X=ARect.Width(), Y=ARect.Height(), Xs=ARect.left, Ys=ARect.top, Y0=Y/2, hundred=100; xue@0: double Ymax, Ymin; xue@0: int LengthRatio=(endpos-startpos)/X; xue@0: Canv->Pen->Color=Color1; xue@0: xue@0: amp=Y*amp/(1<<(BytesPerSample*8)); xue@0: xue@0: bool b8=(BytesPerSample==1), b16=(BytesPerSample==2), b24=(BytesPerSample==3); xue@0: xue@0: if (false) xue@0: { xue@0: unsigned char* Data8=(unsigned char*)data; xue@0: Canv->MoveTo(Xs+0, Ys+Y0-(Data8[startpos]-0x80)*amp); xue@0: if (LengthRatio<4) xue@0: for (i=1; iLineTo(Xs+i, Ys+Y0-(Data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp); xue@0: else xue@0: { xue@0: for (i=0; ivlocalmax) vlocalmax=vlocal; xue@0: } xue@0: Ymax=Y0-(vlocalmin-0x80)*amp; xue@0: Ymin=Y0-(vlocalmax-0x80)*amp; xue@0: if (Canv->PenPos.y*2>Ymin+Ymax) xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: } xue@0: else xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: } xue@0: } xue@0: } xue@0: } xue@0: else xue@0: { xue@0: unsigned __int8* data8; __int16* data16; __pint24 data24; xue@0: xue@0: if (b16) {data16=(__int16*)data; Canv->MoveTo(Xs, Ys+Y0-data16[startpos]*amp);} xue@0: else if (b24) {data24=(__pint24)data; Canv->MoveTo(Xs, Ys+Y0-data24[startpos]*amp);} xue@0: else if (b8) {data8=(unsigned __int8*)data; Canv->MoveTo(Xs, Ys+Y0-(data8[startpos]-0x80)*amp);} xue@0: xue@0: if (LengthRatio<1) xue@0: for (i=1; iLineTo(Xs+i, Ys+Y0-data16[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp); xue@0: else if (b24) Canv->LineTo(Xs+i, Ys+Y0-data24[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp); xue@0: else if (b8) Canv->LineTo(Xs+i, Ys+Y0-(data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp); xue@0: } xue@0: else xue@0: { xue@0: for (i=0; i0; j-=jump) xue@0: { xue@0: if (b16) vlocal=data16[localstart+j]; xue@0: else if (b24) vlocal=data24[localstart+j]; //(*data24)[localstart+j]; xue@0: else if (b8) vlocal=data8[localstart+j]-0x80; xue@0: if (vlocalvlocalmax) vlocalmax=vlocal; xue@0: } xue@0: double rmin=vlocalmin*amp, rmax=vlocalmax*amp; xue@0: Ymax=Y0-rmin, Ymin=Y0-rmax; xue@0: if (rmin<0 && rmax>0) xue@0: { xue@0: int Y1=(rmax-rmin)/4; xue@0: int Y2=Y0+Y1; xue@0: Y1=Y0-Y1; xue@0: if (Canv->PenPos.y*2>Ymin+Ymax) xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: Canv->LineTo(Xs+i, Ys+Y2); xue@0: Canv->Pen->Color=Color2; xue@0: Canv->LineTo(Xs+i, Ys+Y1); xue@0: Canv->Pen->Color=Color1; xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: } xue@0: else xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: Canv->LineTo(Xs+i, Ys+Y1); xue@0: Canv->Pen->Color=Color2; xue@0: Canv->LineTo(Xs+i, Ys+Y2); xue@0: Canv->Pen->Color=Color1; xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: } xue@0: } xue@0: else xue@0: { xue@0: if (Canv->PenPos.y*2>Ymin+Ymax) xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: } xue@0: else xue@0: { xue@0: Canv->LineTo(Xs+i, Ys+Ymin); xue@0: Canv->LineTo(Xs+i, Ys+Ymax); xue@0: } xue@0: } xue@0: } xue@0: } xue@0: } xue@0: } xue@0: xue@0: /* xue@0: The internal bitmap Basic0 is used to contain the default waveform bitmap. xue@0: Whenever this method is called with FCanvas assigned to ACanvas, it draws the xue@0: waveform of the current section to Basic1, regardless of AStartPos or AnEndPos. xue@0: */ xue@0: void __fastcall TWaveView::DrawWaveForm(int channel, TCanvas* ACanvas, TRect ARect, int AStartPos, int AnEndPos, double amp, bool basic) xue@0: { xue@0: if (AnEndPos<=AStartPos) return; xue@0: TRect bmpRect; xue@0: Graphics::TBitmap* bmp; xue@0: if (basic) xue@0: { xue@0: bool resample=false; xue@0: if (!Basic0[channel]) xue@0: { xue@0: Graphics::TBitmap* NewBmp=new Graphics::TBitmap; xue@0: NewBmp->PixelFormat=pf32bit; xue@0: NewBmp->Transparent=true; xue@0: NewBmp->TransparentMode=tmFixed; xue@0: Basic0[channel]=NewBmp; xue@0: resample=true; xue@0: } xue@0: sBasic0Settings BS={ARect.Width(), ARect.Height(), FStartPos, FEndPos, FYZoomRate}; xue@0: if (Basic0Settings[channel]!=BS) xue@0: { xue@0: Basic0Settings[channel]=BS; xue@0: Basic0[channel]->Width=BS.X; xue@0: Basic0[channel]->Height=BS.Y; xue@0: resample=true; xue@0: } xue@0: if (!resample) xue@0: { xue@0: ACanvas->CopyRect(ARect, Basic0[channel]->Canvas, TRect(0, 0, BS.X, BS.Y)); xue@0: // ACanvas->Draw(ARect.left, ARect.top, Basic0[channel]); xue@0: return; xue@0: } xue@0: AStartPos=FStartPos, AnEndPos=FEndPos; xue@0: bmp=Basic0[channel]; xue@0: bmpRect=TRect(0, 0, BS.X, BS.Y); xue@0: } xue@0: else xue@0: { xue@0: bmp=new Graphics::TBitmap; xue@0: bmp->PixelFormat=pf32bit; xue@0: bmp->Width=ARect.Width(); xue@0: bmp->Height=ARect.Height(); xue@0: bmpRect=TRect(0, 0, bmp->Width, bmp->Height); xue@0: } xue@0: xue@0: TCanvas* Canv=bmp->Canvas; xue@0: if (ACanvas==Canvas) Canv->CopyRect(bmpRect, ACanvas, ARect); xue@0: else {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(bmpRect);} xue@0: Canv->Pen->Mode=pmCopy; xue@0: Canv->Pen->Style=psSolid; xue@0: int Y=bmpRect.Height(), X=bmpRect.Width(), Y0=Y/2; xue@0: Canv->Pen->Color=FAxisColor; Canv->MoveTo(0, Y0); Canv->LineTo(X, Y0); xue@0: ::DrawWaveForm(Canv, bmpRect, FData[channel], FBytesPerSample, AStartPos, AnEndPos, FYZoomRate, FWaveColor, FWaveColor2); xue@0: xue@0: ACanvas->CopyRect(ARect, Canv, bmpRect); xue@0: if (!basic) delete bmp; xue@0: } xue@0: xue@0: //Call this when the waveview data buffer is updated externally xue@0: void __fastcall TWaveView::ExtDataChange(TObject* Sender) xue@0: { xue@0: ClearSpectrograms(); xue@0: InvalidateBasic(-1, 0); xue@0: } xue@0: xue@0: void __fastcall TWaveView::ExtDataChange(TObject* Sender, int Channel, int From, int To) xue@0: { xue@0: FSpectrogram[Channel]->Invalidate(From, To); xue@0: InvalidateBasic(Channel, 0); xue@0: Invalidate(); xue@0: } xue@0: xue@0: 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: { xue@0: int hn=n/2; xue@0: if (readfrom+ndataen-hn) xue@0: { xue@0: if (!loop) xue@0: { xue@0: xue@0: if (readfrom>dataen-hn) xue@0: { xue@0: double* lwin=&win[n-(dataen-readfrom)]; xue@0: for (int i=0; idataen-n) xue@0: { xue@0: double* lwin=&win[n-(dataen-readfrom)]; xue@0: for (int i=dataen-hn-readfrom; idataen-hn/2) //notice it is during looped playback xue@0: { xue@0: if (readfrom>dataen-hn/2 && loopframe) xue@0: { xue@0: memcpy(frame, &loopframe[readfrom-(dataen-hn/2)], sizeof(double)*(hn-readfrom+dataen-hn/2)); xue@0: IntToDouble2416(&frame[dataen-readfrom+hn/2], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2); xue@0: } xue@0: else if (readfrom+hn>dataen-hn/2 && loopframe) xue@0: { xue@0: memcpy(&frame[dataen-hn/2-readfrom], loopframe, sizeof(double)*hn); xue@0: IntToDouble2416(&frame[dataen+hn/2-readfrom], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2); xue@0: } xue@0: else xue@0: { xue@0: //calculate loopframe, of size hn xue@0: free8(loopframe); xue@0: loopframe=(double*)malloc8(sizeof(double)*n); xue@0: double* looped=&loopframe[hn]; xue@0: if (dataen+hn/2<=datalen) IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, hn); xue@0: else xue@0: { xue@0: IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, datalen-(dataen-hn/2)); xue@0: memset(&loopframe[datalen-(dataen-hn/2)], 0, sizeof(double)*(dataen+hn/2-datalen)); xue@0: } xue@0: if (datast>hn/2) IntToDouble2416(looped, &data[(datast-hn/2)*bps], bps, hn); xue@0: else xue@0: { xue@0: memset(looped, 0, sizeof(double)*(hn/2-datast)); xue@0: IntToDouble2416(&looped[hn/2-datast], data, bps, datast+hn/2); xue@0: } xue@0: for (int i=0; iChannels==2); xue@0: int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2; xue@0: xue@0: int BlockSize=FSection->BlockSize/PlayBytesPerSample/FSection->Channels; xue@0: if (LoopPlay && LoopMode) xue@0: { xue@0: if (LoopMode==1) //loop visible xue@0: FSectionStartPos=FStartPos, FSectionEndPos=FEndPos; xue@0: else if (LoopMode==2)//loop selection xue@0: FSectionStartPos=FSelections->StartPos, FSectionEndPos=FSelections->EndPos; xue@0: if (PBPR1 && FStereoMode==wvpRight)?FData[1]:FData[0]); xue@0: xue@0: int Wid=FSpecRes, HWid=Wid/2; xue@0: while (PBPA=FSectionEndPos) xue@0: { xue@0: if (!LoopPlay) newPBPR=FSectionEndPos, newPBPA=PBPA+FSectionEndPos-PBPR; xue@0: else newPBPR=newPBPR-FSectionEndPos+FSectionStartPos, newPBPA=PBPA+HWid;// looping=true; xue@0: } xue@0: else newPBPA=PBPA+HWid; xue@0: xue@0: double k=GetFMask(famp, PBPR, FPlaybackFilter); xue@0: xue@0: if (k==0) xue@0: { xue@0: if (prevk==1) xue@0: { xue@0: for (int i=0; i0) xue@0: { xue@0: memmove(PlayBuffer0, &PlayBuffer0[PBPW], sizeof(double)*(PBPA-PBPW+HWid)); xue@0: if (stereo) memmove(PlayBuffer1, &PlayBuffer1[PBPW], sizeof(double)*(PBPA-PBPW+HWid)); xue@0: } xue@0: PBPA-=PBPW; PBPW=0; xue@0: } xue@0: if (PBPA>0) return FSection->BlockSize; xue@0: else return (BlockSize+PBPA)*PlayBytesPerSample*FSection->Channels; xue@0: } xue@0: xue@0: void __fastcall TWaveView::FMenuPopup(TObject* Sender) xue@0: { xue@0: ItemExtract->Visible=(FLength>0 && FSelections->Count>0 && FSelections->Focus>=0); xue@0: ItemPlay->Visible=(FLength>0); xue@0: ItemProperty->Visible=(FLength>0); xue@0: ItemXZoomRestore->Visible=(FLength>0 && (FStartPos!=0 || FEndPos!=FLength)); xue@0: bool hfa=FPanes.HasFreqAxis[FCurrentPane]; xue@0: ItemYZoomRestore->Visible=(FLength>0 && (!hfa && YZoomRate!=1 || hfa && (FStartDigiFreq!=0 || FEndDigiFreq!=0.5))); xue@0: } xue@0: xue@0: void __fastcall TWaveView::FocusSelection(int Index) xue@0: { xue@0: if (Index>=0 && IndexCount && Index!=FSelections->Focus) xue@0: { xue@0: FSelections->Focus=Index; xue@0: if (FOnSelectedChange) FOnSelectedChange(this); xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::FreeData(int ch) xue@0: { xue@0: if (ch>=FChannels || ch<0) xue@0: { xue@0: for (int i=0; i=FChannels || ch<0) xue@0: { xue@0: for (int i=0; i0.5) return 0.5; xue@0: else return result; xue@0: } xue@0: xue@0: QSPEC_FORMAT* __fastcall TWaveView::GetA(int Channel, int fr) xue@0: { xue@0: return FSpectrogram[Channel]->A(fr); xue@0: } xue@0: xue@0: double __fastcall TWaveView::GetCurrentAmplitude() xue@0: { xue@0: return FPTA(FCurrentPane, FY); xue@0: } xue@0: xue@0: //There is no SetCurrentRange() method. Use SetArea(). xue@0: TWaveViewSelection __fastcall TWaveView::GetCurrentRange() xue@0: { xue@0: TWaveViewSelection sel={FStartPos, FEndPos, FStartDigiFreq, FEndDigiFreq}; xue@0: return sel; xue@0: } xue@0: xue@0: __int16 __fastcall TWaveView::GetCurrentSample16() xue@0: { xue@0: return Data16[FPanes.Channel[FCurrentPane]][CurrentTime]; xue@0: } xue@0: xue@0: int __fastcall TWaveView::GetCurrentSampleInPixel() xue@0: { xue@0: if (FBytesPerSample==1) return FATP(FCurrentPane, Data8[FPanes.Channel[FCurrentPane]][CurrentTime]); xue@0: else if (FBytesPerSample==2) return FATP(FCurrentPane, Data16[FPanes.Channel[FCurrentPane]][CurrentTime]); xue@0: else return FATP(FCurrentPane, Data24[FPanes.Channel[FCurrentPane]][CurrentTime]); xue@0: } xue@0: xue@0: int __fastcall TWaveView::GetCurrentTimeEx() xue@0: { xue@0: return (FCurrentTime1+FCurrentTime2)/2;//+0.5; xue@0: } xue@0: xue@0: void* __fastcall TWaveView::GetData(int Channel) xue@0: { xue@0: return FData[Channel]; xue@0: } xue@0: xue@0: __int16* __fastcall TWaveView::GetData16(int Channel) xue@0: { xue@0: return (__int16*)(FData[Channel]); xue@0: } xue@0: xue@0: __pint24 __fastcall TWaveView::GetData24(int Channel) xue@0: { xue@0: return (__pint24)(FData[Channel]); xue@0: } xue@0: xue@0: char* __fastcall TWaveView::GetData8(int Channel) xue@0: { xue@0: return (char*)(FData[Channel]); xue@0: } xue@0: xue@0: double __fastcall TWaveView::GetFMask(double* mask, int t, TWaveViewPlaybackFilter Filter) xue@0: { xue@0: double result=0; xue@0: xue@0: if (Filter==wvfPass) memset(mask, 0, FSpecRes*sizeof(double)); xue@0: else for (int i=0; iCount; i++) xue@0: { xue@0: TWaveViewSelection sel=FSelections->Items[i]; xue@0: if (tsel.EndPos) continue; xue@0: LF1=sel.StartDigiFreq*FSpecRes+0.5; xue@0: LF2=sel.EndDigiFreq*FSpecRes+0.5; xue@0: if (LF1<0) LF1=0; xue@0: if (LF2>FSpecRes/2+1) LF2=FSpecRes/2+1; xue@0: if (Filter==wvfPass) for (int j=LF1; j<=LF2; j++) mask[j]=1; xue@0: else for (int j=LF1; j<=LF2; j++) mask[j]=0; xue@0: } xue@0: for (int i=FSpecRes/2+1; i=Rect.left && X=Rect.top && Y=0) xue@0: { xue@0: FOpMode=wopSelect; xue@0: if (FOnGetOpMode) FOnGetOpMode(this, Shift, FOpMode); xue@0: } xue@0: else xue@0: FOpMode=wopIdle; //Idle mode xue@0: xue@0: TCursor ACursor; xue@0: if (FOpMode==wopDrag) ACursor=crHandPoint; xue@0: else if (FOpMode==wopSelect) ACursor=crArrow; xue@0: else ACursor=Cursor; xue@0: if (ACursor!=Cursor) {Cursor=ACursor;::SetCursor(Screen->Cursors[Cursor]);} xue@0: } xue@0: xue@0: QSPEC_FORMAT* __fastcall TWaveView::GetPh(int Channel, int fr) xue@0: { xue@0: return FSpectrogram[Channel]->Ph(fr); xue@0: } xue@0: xue@0: cmplx* __fastcall TWaveView::GetSpec(int Channel, int fr) xue@0: { xue@0: return FSpectrogram[Channel]->Spec(fr); xue@0: } xue@0: xue@0: TQuickSpectrogram* __fastcall TWaveView::GetSpectrogram(int Channel) xue@0: { xue@0: return FSpectrogram[Channel]; xue@0: } xue@0: xue@0: bool __fastcall TWaveView::GetPlaying() xue@0: { xue@0: return FSection->Playing; xue@0: } xue@0: xue@0: double __fastcall TWaveView::GetSpecWindowParamD(int Index) xue@0: { xue@0: return FSpecWindowParamD[Index]; xue@0: } xue@0: xue@0: void __fastcall TWaveView::InvalidateBasic(int channel, int basic) xue@0: { xue@0: if (basic==0) xue@0: if (channel>=0) Basic0Settings[channel].Y=0; xue@0: else for (int i=0; i=0) Basic1Settings[channel].Y=0; xue@0: else for (int i=0; i0) xue@0: { xue@0: bool Shift=(GetKeyState(VK_SHIFT)<0); xue@0: DoExtract(Sender); xue@0: if (!Shift) RemoveSelection(-1); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::ItemPlayClick(TObject* Sender) xue@0: { xue@0: StartPlayback(Sender); xue@0: } xue@0: xue@0: void __fastcall TWaveView::ItemPropertyClick(TObject* Sender) xue@0: { xue@0: if (FLength>0) xue@0: { xue@0: if (FStartSelRStartPos ||FStartSelR>=FSelections->EndPos xue@0: ||FPanes.HasFreqAxis[FStartPane] && (FVStartSelRStartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq)) xue@0: { xue@0: if (DefaultPropertyItems) DefaultShowProperty(false); xue@0: else if (FCustomProperty) FCustomProperty(this, false); xue@0: } xue@0: else xue@0: { xue@0: if (DefaultPropertyItems) DefaultShowProperty(true); xue@0: else if (FCustomProperty) FCustomProperty(this, true); xue@0: } xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::ItemXZoomClick(TObject* Sender) xue@0: { xue@0: if (FCustomXZoomClick) FCustomXZoomClick(Sender); xue@0: else xue@0: { xue@0: if (dynamic_cast(Sender)->Tag==ITEMXZOOMIN_TAG) xue@0: Zoom(FStartSelR, 0.8); xue@0: else if (dynamic_cast(Sender)->Tag==ITEMXZOOMOUT_TAG) xue@0: Zoom(FStartSelR, 3); xue@0: else if (dynamic_cast(Sender)->Tag==ITEMXZOOMRESTORE_TAG) xue@0: Zoom(FStartSelR, 0); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::ItemYZoomClick(TObject* Sender) xue@0: { xue@0: if (FCustomYZoomClick) FCustomYZoomClick(Sender); xue@0: else xue@0: { xue@0: if (dynamic_cast(Sender)->Tag==ITEMYZOOMIN_TAG) YZoomRate*=1.5; xue@0: else if (dynamic_cast(Sender)->Tag==ITEMYZOOMRESTORE_TAG) xue@0: { xue@0: YZoomRate=1; xue@0: FStartDigiFreq=0; xue@0: FEndDigiFreq=0.5; xue@0: } xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::KeyDown(Word &Key, TShiftState Shift) xue@0: { xue@0: GetOpMode(0, TMouseButton(0), Shift); xue@0: if (FLength>0) xue@0: { xue@0: if (FOpMode<=wopReselect && FCurrentPane>=0) xue@0: { xue@0: switch(Key) xue@0: { xue@0: case VK_BACK: xue@0: { xue@0: int k=Selections->Count-1; xue@0: RemoveSelection(k); xue@0: break; xue@0: } xue@0: case VK_DELETE: xue@0: RemoveSelection(-1); xue@0: break; xue@0: case VK_ESCAPE: xue@0: ClearSelections(this); xue@0: break; xue@0: case VK_NEXT: xue@0: if (Selections->Count>0) xue@0: { xue@0: int k=(Selections->Focus+1)%Selections->Count; xue@0: FocusSelection(k); xue@0: } xue@0: break; xue@0: case VK_PRIOR: xue@0: if (Selections->Count>0) xue@0: { xue@0: int k=(Selections->Focus+Selections->Count-1)%Selections->Count; xue@0: FocusSelection(k); xue@0: } xue@0: break; xue@0: } xue@0: } xue@0: else if (ObjectAtPointer && ObjectAtPointer->OnKeyDown) ObjectAtPointer->OnKeyDown(this, Key, Shift); xue@0: } xue@0: xue@0: TWinControl::KeyDown(Key, Shift); xue@0: } xue@0: xue@0: void __fastcall TWaveView::KeyUp(Word &Key, TShiftState Shift) xue@0: { xue@0: GetOpMode(0, TMouseButton(0), Shift); xue@0: TWinControl::KeyUp(Key, Shift); xue@0: } xue@0: xue@0: void __fastcall TWaveView::MouseCursor(TShiftState Shift, int X, int Y) xue@0: { xue@0: FX=X, FY=Y, FLastShiftState=Shift; xue@0: } xue@0: xue@0: void __fastcall TWaveView::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y) xue@0: { xue@0: WaveViewHitTest(X, Y); xue@0: GetOpMode(0, Button, Shift); xue@0: xue@0: MouseCursor(Shift, X, Y); xue@0: if (Button==mbLeft && FOnMousePointer) MousePointer(Shift, X, Y); xue@0: xue@0: 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: xue@0: if (FLength>=1) xue@0: { xue@0: FStartSel=CurrentTime; xue@0: FVStartSel=CurrentDigiFreq; xue@0: FStartPane=FCurrentPane; xue@0: if (FStartPane>=0) xue@0: { xue@0: FStartSelR=FPTS(FCurrentPane, X); xue@0: FVStartSelR=FPTDF(FCurrentPane, Y); xue@0: } xue@0: FStartSelX=X; xue@0: FStartSelY=Y; xue@0: xue@0: if (FOpMode==wopSelect) xue@0: { xue@0: if (Button==mbLeft && FCurrentPane>=0) xue@0: { xue@0: if (FMultiSelect) xue@0: { xue@0: int slp=SelectionAtPos(CurrentTime, CurrentDigiFreq); xue@0: FLastFocus=(slp>=0)?slp:FSelections->Focus; xue@0: } xue@0: xue@0: if (FSelections->Count && !MultiSelect) Selections->Clear(); xue@0: xue@0: FStartSelX=X; xue@0: FStartSelY=Y; xue@0: xue@0: TWaveViewSelection sel; xue@0: if (FSelectMode==WV2_HSELECT) xue@0: { xue@0: sel.StartPos=sel.EndPos=FStartSel; xue@0: sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq; xue@0: FSelections->Add(sel); xue@0: } xue@0: else if (FSelectMode==WV2_VSELECT) xue@0: { xue@0: sel.StartPos=FStartPos, sel.EndPos=FEndPos; xue@0: sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel; xue@0: FSelections->Add(sel); xue@0: } xue@0: else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT)) xue@0: { xue@0: sel.StartPos=sel.EndPos=FStartSel; xue@0: sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel; xue@0: FSelections->Add(sel); xue@0: } xue@0: else {} xue@0: if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, 1); xue@0: } xue@0: } xue@0: else if (FOpMode==wopDrag) //drag mode xue@0: { xue@0: StartDrag(X, Y); xue@0: } xue@0: else if (FOpMode==wopReselect && Button==mbLeft && FCurrentPane>=0) xue@0: { xue@0: if (Button==mbLeft) xue@0: { xue@0: FStartSelHitTest=SelHitTest(X, Y); xue@0: FStartSelSel=(*FSelections)[FSelections->Focus]; xue@0: } xue@0: } xue@0: else //external mode xue@0: { xue@0: if (ObjectAtPointer && ObjectAtPointer->OnMouseDown) xue@0: { xue@0: StartObject=ObjectAtPointer; xue@0: ObjectAtPointer->OnMouseDown(this, Button, Shift, X, Y); xue@0: } xue@0: else xue@0: { xue@0: StartObject=0; xue@0: } xue@0: } xue@0: } xue@0: TControl::MouseDown(Button, Shift, X, Y); xue@0: FLastX=X, FLastY=Y; xue@0: Invalidate(); xue@0: } xue@0: xue@0: //Down=1: mouse down; -1, -2: mouse move pair; -3: mouse up xue@0: void __fastcall TWaveView::MouseLocalData(int X, int Y, int Down) xue@0: { xue@0: int t=CurrentTime, Wid=FSpecRes, HWid=Wid/2; xue@0: int FLength_Wid=FLength-Wid; xue@0: xue@0: int t0=t-HWid, tp=t, tn=t-Wid; xue@0: xue@0: if (FLocalDataTimeGrid) xue@0: { xue@0: int hoffst=FSpecOffst/2; xue@0: t0=(t0+hoffst)/FSpecOffst*FSpecOffst; xue@0: tp=(tp+hoffst)/FSpecOffst*FSpecOffst; xue@0: tn=(tn+hoffst)/FSpecOffst*FSpecOffst; xue@0: t=(t+hoffst)/FSpecOffst*FSpecOffst; xue@0: } xue@0: xue@0: if (t0<0) t0=0; xue@0: else if (t0>FLength_Wid) t0=FLength_Wid; xue@0: if (tp<0) tp=0; xue@0: else if (tp>FLength_Wid) tp=FLength_Wid; xue@0: if (tn<0) tn=0; xue@0: else if (tn>FLength_Wid) tn=FLength_Wid; xue@0: xue@0: FLocalDataOn=true; xue@0: FOnMouseLocalData(this, &Data8[0][t0*FBytesPerSample], &Data8[0][tp*FBytesPerSample], &Data8[0][tn*FBytesPerSample], Wid, FBytesPerSample, CurrentTime, CurrentDigiFreq, Down); xue@0: FLocalDataOn=false; xue@0: } xue@0: xue@0: void __fastcall TWaveView::MousePointer(TShiftState Shift, int X, int Y) xue@0: { xue@0: FOnMousePointer(this, FCurrentPane, CurrentTime, CurrentDigiFreq); xue@0: } xue@0: xue@0: void __fastcall TWaveView::MouseMove(TShiftState Shift, int X, int Y) xue@0: { xue@0: WaveViewHitTest(X, Y); xue@0: MouseCursor(Shift, X, Y); xue@0: if (Shift.Contains(ssLeft) && FOnMousePointer) if (X!=FLastX || Y!=FLastY) MousePointer(Shift, X, Y); xue@0: xue@0: if (!Shift.Contains(ssLeft)) GetOpMode(0, (TMouseButton)0, Shift); xue@0: xue@0: if (FLength>=1) xue@0: { xue@0: if (FOpMode==wopSelect && FStartPane>=0) //select mode xue@0: { xue@0: if ((X!=FLastX || Y!=FLastY) && Shift.Contains(ssLeft)) xue@0: { xue@0: TWaveViewSelection sel; xue@0: int ACurrentTime=FPTS(FStartPane, X+0.5)+0.5; if (ACurrentTime<0) ACurrentTime=0; else if (ACurrentTime>FLength) ACurrentTime=FLength; xue@0: double ACurrentDigiFreq=FPTDF(FStartPane, Y+0.5); if (ACurrentDigiFreq<0) ACurrentDigiFreq=0; else if (ACurrentDigiFreq>0.5) ACurrentDigiFreq=0.5; xue@0: if (FSelectMode==WV2_HSELECT) xue@0: { xue@0: if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime; xue@0: else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel; xue@0: sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq; xue@0: FSelections->Items[FSelections->Focus]=sel; xue@0: } xue@0: else if (FSelectMode==WV2_VSELECT) xue@0: { xue@0: sel.StartPos=FStartPos, sel.EndPos=FEndPos; xue@0: if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq; xue@0: else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel; xue@0: FSelections->Items[FSelections->Focus]=sel; xue@0: } xue@0: else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT)) xue@0: { xue@0: if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime; xue@0: else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel; xue@0: if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq; xue@0: else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel; xue@0: FSelections->Items[FSelections->Focus]=sel; xue@0: } xue@0: if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, -2); xue@0: } xue@0: } xue@0: else if (FOpMode==wopDrag && FStartPane>=0) //drag mode xue@0: { xue@0: if ((Shift.Contains(ssLeft)||true) && (X!=FLastX || Y!=FLastY)) xue@0: { xue@0: double lLength=FStartSelSel.EndPos-FStartSelSel.StartPos; xue@0: if (lLength>0) xue@0: { xue@0: double lWidth=FPanes.Rect[FStartPane].Width(); xue@0: FStartPos=FStartSelSel.StartPos-(X-FStartSelX)*lLength/lWidth; xue@0: if (FStartPos<0) FStartPos=0; xue@0: FEndPos=FStartPos+lLength; xue@0: if (FEndPos>FLength) {FEndPos=FLength; FStartPos=FEndPos-lLength;} xue@0: if (!FPanes.HasFreqAxis[FStartPane]) {}//waveform xue@0: else xue@0: { xue@0: if (FPanes.YScale[FStartPane]==0) //linear scale xue@0: { xue@0: lLength=FStartSelSel.EndDigiFreq-FStartSelSel.StartDigiFreq; xue@0: lWidth=FPanes.Rect[FStartPane].Height(); xue@0: FStartDigiFreq=FStartSelSel.StartDigiFreq-(FStartSelY-Y)*lLength/lWidth; xue@0: if (FStartDigiFreq<0) FStartDigiFreq=0; xue@0: FEndDigiFreq=FStartDigiFreq+lLength; xue@0: if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq-lLength;} xue@0: } xue@0: else //log scale xue@0: { xue@0: lLength=WV2_LOG_FREQ(FStartSelSel.EndDigiFreq)/WV2_LOG_FREQ(FStartSelSel.StartDigiFreq); xue@0: lWidth=FPanes.Rect[FStartPane].Height(); xue@0: FStartDigiFreq=WV2_LOG_FREQ(FStartSelSel.StartDigiFreq)*pow(lLength, (Y-FStartSelY)/lWidth); xue@0: FEndDigiFreq=FStartDigiFreq*lLength; xue@0: if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq/lLength;} xue@0: } xue@0: } xue@0: PageChange(); xue@0: } xue@0: } xue@0: } xue@0: else if (FOpMode==wopReselect && FStartPane>=0) //re-selecting mode xue@0: { xue@0: if (Shift.Contains(ssLeft) && FStartSelHitTest!=selOuter) xue@0: { xue@0: int NewStartPos, NewEndPos; xue@0: double NewStartDigiFreq, NewEndDigiFreq; xue@0: xue@0: if ((FStartSelHitTest & WV2_LEFT) && FStartSelX!=X) NewStartPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.StartPos)+X-FStartSelX)+0.5; xue@0: else NewStartPos=FStartSelSel.StartPos; xue@0: if ((FStartSelHitTest & WV2_RIGHT) && FStartSelX!=X) NewEndPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.EndPos)+X-FStartSelX)+0.5; xue@0: else NewEndPos=FStartSelSel.EndPos; xue@0: if ((FStartSelHitTest & WV2_TOP) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewEndDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.EndDigiFreq)+Y-FStartSelY); xue@0: else NewEndDigiFreq=FStartSelSel.EndDigiFreq; xue@0: if ((FStartSelHitTest & WV2_BOTTOM) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewStartDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.StartDigiFreq)+Y-FStartSelY); xue@0: else NewStartDigiFreq=FStartSelSel.StartDigiFreq; xue@0: xue@0: TWaveViewSelection sel={NewStartPos, NewEndPos, NewStartDigiFreq, NewEndDigiFreq}; xue@0: if (NewStartPos>NewEndPos) sel.StartPos=NewEndPos, sel.EndPos=NewStartPos; xue@0: if (NewStartDigiFreq>NewEndDigiFreq) sel.StartDigiFreq=NewEndDigiFreq, sel.EndDigiFreq=NewStartDigiFreq; xue@0: if (sel.StartPos<0) sel.StartPos=0; else if (sel.EndPos>FLength) sel.EndPos=FLength; xue@0: if (sel.StartDigiFreq<0) sel.StartDigiFreq=0; else if (sel.EndDigiFreq>0.5) sel.EndDigiFreq=0.5; xue@0: FSelections->Items[FSelections->Focus]=sel; xue@0: } xue@0: else xue@0: { xue@0: TCursor ACursor=ControlCursorAtPos(X, Y);; xue@0: if (Cursor!=ACursor) xue@0: { xue@0: Cursor=ACursor; xue@0: ::SetCursor(Screen->Cursors[Cursor]); xue@0: } xue@0: } xue@0: } xue@0: else //external mode xue@0: { xue@0: if (Shift.Contains(ssLeft) && StartObject) xue@0: { xue@0: if (StartObject->OnMouseMove) StartObject->OnMouseMove(this, Shift, X, Y); xue@0: } xue@0: else if (ObjectAtPointer && ObjectAtPointer->OnMouseMove) xue@0: ObjectAtPointer->OnMouseMove(this, Shift, X, Y); xue@0: } xue@0: xue@0: if (Shift.Contains(ssLeft) || Shift.Contains(ssRight)) FLastX=X, FLastY=Y; xue@0: } xue@0: if (FClickFocus && !Focused()) SetFocus(); xue@0: TControl::MouseMove(Shift, X, Y); xue@0: Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y) xue@0: { xue@0: WaveViewHitTest(X, Y); xue@0: MouseCursor(Shift, X, Y); xue@0: if (FLength>=1) xue@0: { xue@0: if (FOpMode==wopSelect && FStartPane>=0) xue@0: { xue@0: if (Button==mbLeft) xue@0: { xue@0: if (FSelections->Focus>=0) xue@0: { xue@0: TWaveViewSelection sel=FSelections->Items[FSelections->Focus]; xue@0: if (sel.StartPos==sel.EndPos || sel.StartDigiFreq==sel.EndDigiFreq) xue@0: { xue@0: FSelections->Delete(FSelections->Focus); xue@0: if (FMultiSelect) FSelections->Focus=FLastFocus; xue@0: } xue@0: } xue@0: } xue@0: } xue@0: else if (FOpMode==wopReselect && FStartPane>=0) xue@0: { xue@0: if (FSelections->Focus>=0 && FStartSelHitTest!=selOuter) xue@0: { xue@0: TWaveViewSelection sel=FSelections->Items[FSelections->Focus]; xue@0: if (FSTP(FStartPane, sel.EndPos)-FSTP(FStartPane, sel.StartPos)<0.01 xue@0: || FPanes.HasFreqAxis[FStartPane] && FDFTP(FStartPane, sel.StartDigiFreq)-FDFTP(FStartPane, sel.EndDigiFreq)<0.01) xue@0: { xue@0: FSelections->Delete(FSelections->Focus); xue@0: } xue@0: } xue@0: } xue@0: else //external mode xue@0: { xue@0: if (StartObject) xue@0: { xue@0: if (StartObject->OnMouseUp) StartObject->OnMouseUp(this, Button, Shift, X, Y); xue@0: StartObject=0; xue@0: } xue@0: else if (ObjectAtPointer && ObjectAtPointer->OnMouseUp) xue@0: ObjectAtPointer->OnMouseUp(this, Button, Shift, X, Y); xue@0: } xue@0: } xue@0: xue@0: if (Button==mbLeft || Button==mbRight) FLastX=X, FLastY=Y; xue@0: TControl::MouseUp(Button, Shift, X, Y); xue@0: Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::MouseWheelHandler(TMessage& Msg) xue@0: { xue@0: TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg; xue@0: xue@0: bool Handled=false; TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1); xue@0: if (ObjectAtPointer && ObjectAtPointer->OnMouseWheel) ObjectAtPointer->OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled); xue@0: else if (FCurrentPane>=0 && !DisableMouseWheelZoom) xue@0: { xue@0: if (Shift.Empty()) xue@0: { xue@0: int X=CurrentTime; xue@0: xue@0: if (X>=FStartPos && X<=FEndPos) xue@0: { xue@0: if (WMsg->WheelDelta<0) Zoom(X, 0.9); xue@0: else Zoom(X, 10.0/9); xue@0: } xue@0: } xue@0: else xue@0: { xue@0: if (!FPanes.HasFreqAxis[FCurrentPane]) xue@0: { xue@0: if (WMsg->WheelDelta>0) ZoomY(0.9); xue@0: else ZoomY(10.0/9); xue@0: } xue@0: else xue@0: { xue@0: double Y=CurrentDigiFreq; xue@0: if (Y>=FStartDigiFreq && Y<=FEndDigiFreq) xue@0: { xue@0: if (WMsg->WheelDelta<0) ZoomF(Y, 0.9, FPanes.YScale[FCurrentPane]); xue@0: else ZoomF(Y, 10.0/9, FPanes.YScale[FCurrentPane]); xue@0: } xue@0: } xue@0: } xue@0: } xue@0: if (OnMouseWheel) OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled); xue@0: if (!Handled) TCustomControl::MouseWheelHandler(Msg); xue@0: } xue@0: xue@0: void __fastcall TWaveView::PageChange(bool updatescrollbar) xue@0: { xue@0: if (FScrollBar && updatescrollbar) UpdateScrollBar(this); xue@0: if (FOnPageChange) FOnPageChange(this); xue@0: } xue@0: xue@0: //The Paint() methos draws form StartPos to EndPos in the xue@0: //WaveAudio stream, stretching it to fit the whole width xue@0: //Selected area is highlighted. xue@0: void __fastcall TWaveView::Paint() xue@0: { xue@0: if (FOnCustomPaint) xue@0: { xue@0: bool Done; xue@0: FOnCustomPaint(this, Done); xue@0: if (Done) xue@0: { xue@0: if (FOnPaint) FOnPaint(this); xue@0: return; xue@0: } xue@0: } xue@0: xue@0: if (FLength>0) xue@0: { xue@0: Canvas->Brush->Color=FBackColor; Canvas->FillRect(ClientRect); xue@0: DrawPanes(); xue@0: if (FOnPaint) FOnPaint(this); xue@0: if (FShowInfo) DrawInfo(); xue@0: } xue@0: if (FObjects.Count>0) for (int i=0; i=0) DrawCursor(FCurrentPane, FX, FY); xue@0: } xue@0: xue@0: void __fastcall TWaveView::PausePlayback(TObject* Sender) xue@0: { xue@0: if (FSection && FSection->Playing) FSection->PausePlayback(this); xue@0: } xue@0: xue@0: void __fastcall TWaveView::Post(int Mode) xue@0: { xue@0: if (!FWaveAudio) return; xue@0: FWaveAudio->OnAudioChange=NULL; xue@0: xue@0: //for a waveaudio using file stream, set file mode to RW xue@0: if (!FWaveAudio->UseMemoryStream) xue@0: { xue@0: int pos=FWaveAudio->FFileStream->Position; xue@0: delete FWaveAudio->FFileStream->File; xue@0: FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenReadWrite); xue@0: FWaveAudio->FFileStream->Position=pos; xue@0: } xue@0: xue@0: int Channels=FWaveAudio->Channels; xue@0: xue@0: int writefrom, writelength; xue@0: if (Mode==0) xue@0: { xue@0: writefrom=0; xue@0: writelength=FLength; xue@0: } xue@0: else if (Mode==1) xue@0: { xue@0: writefrom=FStartPos; xue@0: writelength=FEndPos-FStartPos; xue@0: } xue@0: int writefrombytes=writefrom*FBytesPerSample*Channels; xue@0: xue@0: if (Channels==1) xue@0: { xue@0: FWaveAudio->Seek(writefrombytes, soFromBeginning); xue@0: FWaveAudio->Write(&Data8[0][writefrombytes], writelength*FBytesPerSample); xue@0: } xue@0: else xue@0: { xue@0: //------------------------- xue@0: { xue@0: if (FWaveAudio->UseMemoryStream) xue@0: { xue@0: char* databuf=&((unsigned char*)((TMemoryStream*)FWaveAudio->WaveStream)->Memory)[writefrombytes]; xue@0: char* data=&((char*)FData)[writefrom*FBytesPerSample]; xue@0: for (int k=0; kSeek(writefrombytes, soFromCurrent); xue@0: char* data=&((char*)FData)[writefrom*FBytesPerSample]; xue@0: for (int k=0; kWaveStream->Read(data, FBytesPerSample); xue@0: data+=FBytesPerSample; xue@0: FWaveAudio->Seek(FBytesPerSample*(Channels-1), soFromCurrent); xue@0: } xue@0: } xue@0: } xue@0: //--------------------------- xue@0: } xue@0: xue@0: //for a waveaudio using file stream, set file mode to back to R after posting xue@0: if (!FWaveAudio->UseMemoryStream) xue@0: { xue@0: int pos=FWaveAudio->FFileStream->Position; xue@0: delete FWaveAudio->FFileStream->File; xue@0: FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenRead); xue@0: FWaveAudio->FFileStream->Position=pos; xue@0: } xue@0: FWaveAudio->OnAudioChange=WaveViewAudioChange; xue@0: } xue@0: xue@0: void __fastcall TWaveView::RemoveSelection(int Index) xue@0: { xue@0: if (Index==-1) Index=FSelections->Focus; xue@0: if (Index<0 || Index>=FSelections->Count) return; xue@0: if (Index==FSelections->Focus) xue@0: { xue@0: FSelections->Delete(Index); xue@0: if (FOnSelectedChange) FOnSelectedChange(this); xue@0: } xue@0: else xue@0: { xue@0: FSelections->Delete(Index); xue@0: } xue@0: Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::Resize() xue@0: { xue@0: FPanes.ResizePanes(ClientRect); xue@0: TControl::Resize(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::Retrieve(int Mode, int from, int length) xue@0: { xue@0: if (!FWaveAudio || FWaveAudio->Length==0) return; xue@0: xue@0: int readfrom, readlength; xue@0: if (Mode==0) xue@0: { xue@0: readfrom=0; xue@0: readlength=FLength; xue@0: } xue@0: else if (Mode==1) xue@0: { xue@0: readfrom=FStartPos; xue@0: readlength=FEndPos-FStartPos; xue@0: } xue@0: else if (Mode==2) xue@0: { xue@0: readfrom=from; xue@0: readlength=length; xue@0: } xue@0: int readfrombytes=readfrom*FBytesPerSample*FChannels; xue@0: FWaveAudio->Seek(readfrombytes, soFromBeginning); xue@0: xue@0: if (FChannels==1) xue@0: { xue@0: FWaveAudio->Read(&Data8[0][readfrombytes], readlength*FBytesPerSample); xue@0: ExtDataChange(this, 0, readfrom, readfrom+readlength); xue@0: } xue@0: else if (FChannels==2) xue@0: { xue@0: void *FFData0=&Data8[0][readfrom*FBytesPerSample], xue@0: *FFData1=&Data8[1][readfrom*FBytesPerSample]; xue@0: FWaveAudio->ReadSamplesInterleave(FFData0, FFData1, readlength); xue@0: ExtDataChange(this, 0, readfrom, readfrom+readlength); xue@0: ExtDataChange(this, 1, readfrom, readfrom+readlength); xue@0: } xue@0: else xue@0: { xue@0: void* FFData[WV2_MAX_CHANNEL]; xue@0: for (int i=0; iReadSamplesMultiChannel(FChannels, FFData, readlength); xue@0: for (int i=0; iA(fr); xue@0: if (!Spec) {memset(vyy, 0, sizeof(double)*dY); return;} xue@0: else xue@0: { xue@0: int yyd, oldyyd=-2, hWid=Spectrogram->Wid/2; xue@0: double yyr, v0, v1, v2, v3, a, b, c; xue@0: for (int y=0; yhWid) vyy[y]=0; xue@0: else xue@0: { xue@0: yyd=floor(yy[y]); yyr=yy[y]-yyd; xue@0: if (yyr==0) vyy[y]=Spec[yyd]; xue@0: else xue@0: { xue@0: if (yyd!=oldyyd) xue@0: { xue@0: oldyyd=yyd; v1=Spec[yyd], v2=Spec[yyd+1]; xue@0: if (yyd==0) v0=Spec[1]; else v0=Spec[yyd-1]; xue@0: if (yyd==hWid-1) v3=Spec[hWid-1]; else v3=Spec[yyd+2]; xue@0: xue@0: if (v1>v0 && v1>v3 && v2>v0 && v2>v3) //a local peak -> use quadratic interpolation xue@0: { xue@0: if (v0Size=bh.bfSize; xue@0: char* ASM=(char*)AS->Memory; xue@0: memcpy(ASM, &bh, sizeof(bh)); xue@0: memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi)); xue@0: int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)]; xue@0: xue@0: double xxr, maxv=0; xue@0: int xxd, sampr, sampg, sampb; xue@0: xue@0: double *vyys0=(double*)malloc8(sizeof(double)*(dY+dY)), *vyys1=&vyys0[dY]; xue@0: xue@0: int oldxxd=-3; xue@0: xue@0: if (interpolate) xue@0: { xue@0: for (int x=0; x=Spectrogram->Capacity) xue@0: { xue@0: for (int y=0; yCapacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1); xue@0: else memset(vyys1, 0, sizeof(double)*dY); xue@0: } xue@0: else xue@0: { xue@0: if (xxd>=0 && xxdCapacity) xue@0: { xue@0: SampleImageLine(vyys0, dY, yy, Spectrogram, xxd); xue@0: for (int i=0; iCapacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1); xue@0: else memset(vyys1, 0, sizeof(double)*dY); xue@0: } xue@0: xue@0: for (int y=0; y=1) xue@0: sampr=255, sampg=samp*32, sampb=0; xue@0: else xue@0: sampg=0, sampr=255*samp, sampb=0; xue@0: pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb)); xue@0: } xue@0: oldxxd=xxd; xue@0: } xue@0: } xue@0: else xue@0: { xue@0: for (int x=0; x=Spectrogram->Capacity) xue@0: { xue@0: for (int y=0; y=0 && xxdCapacity) xue@0: { xue@0: SampleImageLine(vyys0, dY, yy, Spectrogram, xxd); xue@0: for (int i=0; i=1) xue@0: sampr=255, sampg=samp*32, sampb=0; xue@0: else xue@0: sampg=0, sampr=255*samp, sampb=0; xue@0: pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb)); xue@0: } xue@0: } xue@0: oldxxd=xxd; xue@0: } xue@0: } xue@0: xue@0: AS->Position=0; xue@0: ABmp->LoadFromStream(AS); xue@0: delete AS; xue@0: xue@0: free8(vyys0); xue@0: return maxv; xue@0: } xue@0: xue@0: QSPEC_FORMAT __fastcall TWaveView::SampleSpectrogramX(int channel, Graphics::TBitmap* ABmp, double* xx, double* yy, int dX, int dY, double amp, bool interpolate) xue@0: { xue@0: return SampleImageX(FSpectrogram[channel], ABmp, dX, dY, xx, yy, amp, interpolate); xue@0: } xue@0: xue@0: 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: { xue@0: TQuickSpectrogram* Spectrogram=FSpectrogram[channel]; xue@0: xue@0: BITMAPFILEHEADER bh; xue@0: bh.bfType=0x4d42; xue@0: bh.bfSize=0x36+4*dX*dY; xue@0: bh.bfReserved1=bh.bfReserved2=0; xue@0: bh.bfOffBits=0x36; xue@0: xue@0: BITMAPINFOHEADER bi; xue@0: memset(&bi, 0, sizeof(bi)); xue@0: bi.biSize=0x28; xue@0: bi.biWidth=dX; xue@0: bi.biHeight=dY; xue@0: bi.biPlanes=1; xue@0: bi.biBitCount=0x20; xue@0: bi.biSizeImage=4*dX*dY; xue@0: xue@0: TMemoryStream* AS=new TMemoryStream; xue@0: AS->Size=bh.bfSize; xue@0: char* ASM=(char*)AS->Memory; xue@0: memcpy(ASM, &bh, sizeof(bh)); xue@0: memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi)); xue@0: int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)]; xue@0: xue@0: int xxd, sampr, sampg, sampb; xue@0: xue@0: double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0; xue@0: xue@0: int oldxxd=-3; xue@0: xue@0: for (int x=0; x=Spectrogram->Capacity) xue@0: { xue@0: for (int y=0; yA(xxd); xue@0: int istart=AStartDigiFreq*FSpecRes-1; xue@0: int iend=AnEndDigiFreq*FSpecRes+1; xue@0: if (istart<1) istart=1; xue@0: if (iend>FSpecRes/2) iend=FSpecRes/2; xue@0: for (int i=istart; ispec[i-1] && spec[i]>spec[i+1]) xue@0: { xue@0: if (maxv=0 && p=1) sampr=255, sampg=samp*32, sampb=0; xue@0: else sampg=0, sampr=255*samp, sampb=0; xue@0: pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb)); xue@0: } xue@0: oldxxd=xxd; xue@0: } xue@0: xue@0: AS->Position=0; xue@0: ABmp->LoadFromStream(AS); xue@0: delete AS; xue@0: xue@0: free8(vyys0); xue@0: return maxv; xue@0: } xue@0: xue@0: 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: { xue@0: TQuickSpectrogram* Spectrogram=FSpectrogram[channel]; xue@0: xue@0: BITMAPFILEHEADER bh; xue@0: bh.bfType=0x4d42; xue@0: bh.bfSize=0x36+4*dX*dY; xue@0: bh.bfReserved1=bh.bfReserved2=0; xue@0: bh.bfOffBits=0x36; xue@0: xue@0: BITMAPINFOHEADER bi; xue@0: memset(&bi, 0, sizeof(bi)); xue@0: bi.biSize=0x28; xue@0: bi.biWidth=dX; xue@0: bi.biHeight=dY; xue@0: bi.biPlanes=1; xue@0: bi.biBitCount=0x20; xue@0: bi.biSizeImage=4*dX*dY; xue@0: xue@0: TMemoryStream* AS=new TMemoryStream; xue@0: AS->Size=bh.bfSize; xue@0: char* ASM=(char*)AS->Memory; xue@0: memcpy(ASM, &bh, sizeof(bh)); xue@0: memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi)); xue@0: int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)]; xue@0: xue@0: int xxd, sampr, sampg, sampb; xue@0: xue@0: double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0; xue@0: xue@0: int oldxxd=-3; xue@0: xue@0: for (int x=0; x=Spectrogram->Capacity) xue@0: { xue@0: for (int y=0; yA(xxd); xue@0: int istart=AStartDigiFreq*FSpecRes-1; xue@0: int iend=AnEndDigiFreq*FSpecRes+1; xue@0: if (istart<1) istart=1; xue@0: if (iend>FSpecRes/2) iend=FSpecRes/2; xue@0: for (int i=istart; ispec[i-1] && spec[i]>spec[i+1]) xue@0: { xue@0: if (maxv=0 && p=1) sampr=255, sampg=samp*32, sampb=0; xue@0: else sampg=0, sampr=255*samp, sampb=0; xue@0: pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb)); xue@0: } xue@0: oldxxd=xxd; xue@0: } xue@0: xue@0: AS->Position=0; xue@0: ABmp->LoadFromStream(AS); xue@0: delete AS; xue@0: xue@0: free8(vyys0); xue@0: return maxv; xue@0: } xue@0: xue@0: void __fastcall TWaveView::ScrollBarChange(TObject* Sender) xue@0: { xue@0: int ALength=FEndPos-FStartPos; xue@0: if (ALength==0) return; xue@0: if (FScrollBar->Position>FScrollBar->Max-FScrollBar->PageSize) xue@0: FScrollBar->Position=FScrollBar->Max-FScrollBar->PageSize; xue@0: int startpos=FScrollBar->Position; xue@0: bool willdozoom=true; xue@0: if (willdozoom) xue@0: { xue@0: FStartPos=startpos; xue@0: FEndPos=FStartPos+ALength; xue@0: Invalidate(); xue@0: PageChange(false); xue@0: } xue@0: else UpdateScrollBar(this); xue@0: } xue@0: xue@0: int __fastcall TWaveView::SelectionAtPos(int Pos, double DigiFreq) xue@0: { xue@0: int result=-1; xue@0: double marea; xue@0: for (int i=0; iCount; i++) xue@0: { xue@0: TWaveViewSelection sel=FSelections->Items[i]; xue@0: if (Pos>=sel.StartPos && Pos=sel.StartDigiFreq && DigiFreqCount==0) result=selOuter; xue@0: else xue@0: { xue@0: int lleft=FSTP(FCurrentPane, FSelections->StartPos); xue@0: int lright=FSTP(FCurrentPane, FSelections->EndPos), ltop, lbottom; xue@0: if (FPanes.HasFreqAxis[FCurrentPane]) xue@0: { xue@0: ltop=FDFTP(FCurrentPane, FSelections->EndDigiFreq); xue@0: lbottom=FDFTP(FCurrentPane, FSelections->StartDigiFreq); xue@0: } xue@0: else xue@0: { xue@0: ltop=FPanes.Rect[FCurrentPane].top-2*BW-1, lbottom=FPanes.Rect[FCurrentPane].bottom+2*BW+1; xue@0: } xue@0: xue@0: enum {sOuter, sIBorder, sInner, sSBorder} sx, sy; xue@0: if (Xlright+BW) sx=sOuter; xue@0: else if (X<=lleft+BW) sx=sIBorder; xue@0: else if (Xlbottom+BW) sy=sOuter; xue@0: else if (Y<=ltop+BW) sy=sIBorder; xue@0: else if (YAnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos.")); xue@0: bool willdozoom=true; xue@0: if (willdozoom) xue@0: { xue@0: FStartPos=AStartPos; xue@0: FEndPos=AnEndPos; xue@0: if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos.")); xue@0: FStartDigiFreq=AStartDigiFreq; xue@0: FEndDigiFreq=AnEndDigiFreq; xue@0: xue@0: Invalidate(); xue@0: PageChange(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetAutoExtractMode(bool AnAutoExtractMode) xue@0: { xue@0: if (FAutoExtractMode!=AnAutoExtractMode) xue@0: { xue@0: FAutoExtractMode=AnAutoExtractMode; xue@0: if (AnAutoExtractMode) FExtractMode=FSelectMode; xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetAutomaticSpecAmp(int channel, double* xx, double AStartDigiFreq, double AnEndDigiFreq, int dX, int dY) xue@0: { xue@0: if (maxv_specamp<=0) return; xue@0: TQuickSpectrogram* Spectrogram=FSpectrogram[channel]; xue@0: xue@0: int xxd, sampr, sampg, sampb; xue@0: int oldxxd=-3; xue@0: double maxv=0; xue@0: for (int x=0; x=Spectrogram->Capacity) continue; xue@0: xue@0: if (xxd==oldxxd) {} xue@0: else xue@0: { xue@0: QSPEC_FORMAT* spec=Spectrogram->A(xxd); xue@0: int istart=AStartDigiFreq*FSpecRes-1; xue@0: int iend=AnEndDigiFreq*FSpecRes+1; xue@0: if (istart<1) istart=1; xue@0: if (iend>FSpecRes/2) iend=FSpecRes/2; xue@0: for (int i=istart; i0) FSpecAmp=maxv_specamp/maxv; xue@0: } xue@0: xue@0: xue@0: void __fastcall TWaveView::SetAutoSpecAmp(bool AnAutoSpecAmp) xue@0: { xue@0: if (FAutoSpecAmp!=AnAutoSpecAmp) xue@0: FAutoSpecAmp=AnAutoSpecAmp; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetAxisColor(TColor AnAxisColor) xue@0: { xue@0: FAxisColor=AnAxisColor; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetBackColor(TColor ABackColor) xue@0: { xue@0: if (FBackColor!=ABackColor) xue@0: { xue@0: FBackColor=ABackColor; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetCaption(AnsiString ACaption) xue@0: { xue@0: if (ACaption!=FCaption) xue@0: { xue@0: FCaption=ACaption; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetClickFocus(bool AClickFocus) xue@0: { xue@0: FClickFocus=AClickFocus; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetContent(int index, int channel, int type) xue@0: { xue@0: FPanes.Content[index]=type*WV2_MAX_CHANNEL+channel; xue@0: if (Visible) Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetContent(int X, int Y, int channel, int type) xue@0: { xue@0: FPanes.Content[Y*FPanes.FX+X]=type*WV2_MAX_CHANNEL+channel; xue@0: if (Visible) Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetCursorTF(int PaneIndex, int t, double digif) xue@0: { xue@0: int X=FSTP(PaneIndex, t); xue@0: int Y=FDFTP(PaneIndex, digif); xue@0: TPoint P=ClientToScreen(TPoint(X, Y)); xue@0: SetCursorPos(P.x, P.y); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetData(int index, void* AData) xue@0: { xue@0: if (FData[index] && FData[index]!=AData) delete[] FData[index]; xue@0: FData[index]=AData; xue@0: FSpectrogram[index]->Data=AData; xue@0: FSpectrogram[index]->FreeBuffers(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetDefaultPopupMenu(bool ADefaultPopupMenu) xue@0: { xue@0: FDefaultPopupMenu=ADefaultPopupMenu; xue@0: if (FLength>0 && ADefaultPopupMenu) PopupMenu=FMenu; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetEndPos(int AnEndPos) xue@0: { xue@0: if (FEndPos==AnEndPos) return; xue@0: if (AnEndPosTabStop=false; xue@0: if (FLength>0) xue@0: { xue@0: FScrollBar->OnChange=ScrollBarChange; xue@0: UpdateScrollBar(this); xue@0: } xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSelection(int Start, int End, double VStart, double VEnd) xue@0: { xue@0: TWaveViewSelection sel={Start, End, VStart, VEnd}; xue@0: if (!FMultiSelect) FSelections->Clear(); xue@0: FSelections->Add(sel); xue@0: Invalidate(); xue@0: if (FOnSelectedChange) FOnSelectedChange(this); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSelectedAreaColorX(TColor ASelectedAreaColorX) xue@0: { xue@0: if (FSelectedAreaColorX!=ASelectedAreaColorX) xue@0: { xue@0: FSelectedAreaColorX=ASelectedAreaColorX; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSelectedFrameColorX(TColor ASelectedFrameColorX) xue@0: { xue@0: if (FSelectedFrameColorX!=ASelectedFrameColorX) xue@0: { xue@0: FSelectedFrameColorX=ASelectedFrameColorX; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSelectingFrameColorX(TColor ASelectingFrameColorX) xue@0: { xue@0: FSelectingFrameColorX=ASelectingFrameColorX; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSelectMode(int ASelectMode) xue@0: { xue@0: FSelectMode=ASelectMode; xue@0: if (FAutoExtractMode) FExtractMode=ASelectMode; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSpecOffst(int ASpecOffst) xue@0: { xue@0: if (FSpecOffst!=ASpecOffst) xue@0: { xue@0: FSpecOffst=ASpecOffst; xue@0: ClearSpectrograms(); xue@0: Invalidate(); xue@0: for (int i=0; iOffst=ASpecOffst; xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSpecRes(int ASpecRes) xue@0: { xue@0: if (FSpecRes!=ASpecRes) xue@0: { xue@0: FSpecOffst=FSpecOffst*ASpecRes/FSpecRes; xue@0: FSpecRes=ASpecRes; xue@0: ClearSpectrograms(); xue@0: free8(fw); free(fhbi); free8(fwin); xue@0: xue@0: fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); SetTwiddleFactors(FSpecRes, fw); xue@0: fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes]; xue@0: xue@0: fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); xue@0: fhbi=CreateBitInvTable(Log2(FSpecRes)-1); xue@0: xue@0: for (int i=0; iWid=ASpecRes, FSpectrogram[i]->Offst=FSpecOffst; xue@0: xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSpecWindowParamD(int Index, double AParamD) xue@0: { xue@0: if (FSpecWindowParamD[Index]!=AParamD) xue@0: { xue@0: FSpecWindowParamD[Index]=AParamD; xue@0: ClearSpectrograms(); xue@0: if (Index==0) for (int i=0; iWinParam=AParamD; xue@0: fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin); xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSpecWindowType(WindowType ASpecWindowType) xue@0: { xue@0: if (FSpecWindowType!=ASpecWindowType) xue@0: { xue@0: FSpecWindowType=ASpecWindowType; xue@0: ClearSpectrograms(); xue@0: for (int i=0; iWinType=ASpecWindowType; xue@0: fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin); xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetSpecAmp(double ASpecAmp) xue@0: { xue@0: if (FSpecAmp!=ASpecAmp) xue@0: { xue@0: FSpecAmp=ASpecAmp; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetStartPos(int AStartPos) xue@0: { xue@0: if (FStartPos==AStartPos) return; xue@0: if (AStartPos>FEndPos) throw(EWriteError("TWaveView err: StartPos must be no bigger than EndPos.")); xue@0: bool willdozoom=true; xue@0: if (willdozoom) xue@0: { xue@0: FStartPos=AStartPos; xue@0: Invalidate(); xue@0: PageChange(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetStartAndEndPos(int AStartPos, int AnEndPos) xue@0: { xue@0: if (FStartPos==AStartPos && FEndPos==AnEndPos) return; xue@0: if (AStartPos>AnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos.")); xue@0: bool willdozoom=true; xue@0: if (willdozoom) xue@0: { xue@0: FStartPos=AStartPos; xue@0: FEndPos=AnEndPos; xue@0: Invalidate(); xue@0: PageChange(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetTools(TWaveViewTools ATools) xue@0: { xue@0: FTools=ATools; xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetStartAndEndDigiFreq(double AStartDigiFreq, double AnEndDigiFreq) xue@0: { xue@0: if (FStartDigiFreq==AStartDigiFreq && FEndDigiFreq==AnEndDigiFreq) return; xue@0: if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartDigiFreq must be no bigger than EndDigiFreq.")); xue@0: FStartDigiFreq=AStartDigiFreq; xue@0: FEndDigiFreq=AnEndDigiFreq; xue@0: Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetWaveAudio(TWaveAudio* AWaveAudio) xue@0: { xue@0: //* tends to cause comfliction, use only when FWaveAudio!=AWaveAudio xue@0: if (FWaveAudio) FWaveAudio->OnAudioChange=NULL; xue@0: xue@0: FWaveAudio=AWaveAudio; xue@0: xue@0: if (FWaveAudio) xue@0: { xue@0: if (FStartDigiFreq<0) FStartDigiFreq=0, FEndDigiFreq=0.5; xue@0: FWaveAudio->OnAudioChange=WaveViewAudioChange; xue@0: xue@0: FreeData(FChannels); xue@0: FreeInternalBitmaps(FChannels); xue@0: ClearSpectrograms(); xue@0: xue@0: FChannels=FWaveAudio->Channels; xue@0: FBytesPerSample=FWaveAudio->BitsPerSample/8; xue@0: FLength=FWaveAudio->WaveStream->Size/FChannels/FBytesPerSample; xue@0: FBlockSize=FWaveAudio->BlockSize; xue@0: SamplesPerSec=FWaveAudio->SamplesPerSec; xue@0: xue@0: if (FLength) xue@0: { xue@0: for (int i=0; iData=FData[i]; xue@0: FSpectrogram[i]->WinType=FSpecWindowType; xue@0: FSpectrogram[i]->Wid=FSpecRes; xue@0: FSpectrogram[i]->Offst=FSpecOffst; xue@0: FSpectrogram[i]->WinParam=FSpecWindowParamD[0]; xue@0: FSpectrogram[i]->BytesPerSample=FBytesPerSample; xue@0: FSpectrogram[i]->DataLength=FLength; xue@0: } xue@0: } xue@0: xue@0: Retrieve(); xue@0: xue@0: FStartPos=0; xue@0: FEndPos=FLength; xue@0: FSelections->Clear(); xue@0: xue@0: if (FScrollBar) xue@0: { xue@0: FScrollBar->PageSize=0; xue@0: FScrollBar->OnChange=NULL; xue@0: FScrollBar->SetParams(0, 0, (FLength-1>0)?FLength-1:1); xue@0: FScrollBar->OnChange=ScrollBarChange; xue@0: FScrollBar->LargeChange=FLength/10; xue@0: } xue@0: } xue@0: UndoExtractSelection.EndPos=-1; xue@0: PageChange(); xue@0: Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetWaveBackColor(TColor AWaveBackColor) xue@0: { xue@0: if (FWaveBackColor!=AWaveBackColor) xue@0: { xue@0: FWaveBackColor=AWaveBackColor; xue@0: FWaveColor2=TColor((AWaveBackColor+FWaveColor)/2); xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetWaveColor(TColor AWaveColor) xue@0: { xue@0: if (FWaveColor!=AWaveColor) xue@0: { xue@0: FWaveColor=AWaveColor; xue@0: FWaveColor2=TColor((AWaveColor+FWaveBackColor)/2); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetYScale(int index, int yscale) xue@0: { xue@0: FPanes.YScale[index]=yscale; xue@0: if (Visible) Invalidate(); xue@0: } xue@0: xue@0: void __fastcall TWaveView::SetYZoomRate(double AYZoomRate) xue@0: { xue@0: FYZoomRate=AYZoomRate; xue@0: Invalidate(); xue@0: if (FOnScaleChange) FOnScaleChange(this); xue@0: } xue@0: xue@0: void TWaveView::StartDrag(int aX, int aY) xue@0: { xue@0: FStartSelX=aX; xue@0: FStartSelY=aY; xue@0: FStartSelSel=CurrentRange; xue@0: } xue@0: xue@0: void __fastcall TWaveView::StartPlayback(TObject* Sender) xue@0: { xue@0: if (FBeforePlayback) FBeforePlayback(this); xue@0: if (FLength<1) return; xue@0: xue@0: if (!FSection->Playing) xue@0: { xue@0: int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2; xue@0: xue@0: loopframe0=0; xue@0: loopframe1=0; xue@0: prevk=-1; xue@0: xue@0: FSection->CustomFillBlock=FillBlock; xue@0: FSectionBlocks=0; xue@0: xue@0: FSection->Clear(this); xue@0: FSection->Channels=FChannels; xue@0: FSection->BlockSize=FBlockSize; xue@0: FSection->BitsPerSample=PlayBytesPerSample*8; xue@0: FSection->SamplesPerSec=FSamplesPerSec; xue@0: if (FSamplesPerSec>0) FSection->SamplesPerSec=FSamplesPerSec; xue@0: if (FStereoMode==wvpLeft || FStereoMode==wvpRight) FSection->Channels=1; xue@0: if (FSection->Channels>2) FSection->Channels=2; xue@0: FSection->OnPlaybackProg=WaveViewSectionPlaybackProg; xue@0: FSectionProgress=-1; xue@0: xue@0: //if the playback starts from outside the focused selection according to mouse pointer xue@0: if (FStartSelRStartPos||FStartSelR>=FSelections->EndPos|| xue@0: FPanes.HasFreqAxis[FStartPane] && (FVStartSelRStartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq)) xue@0: { xue@0: if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, false); xue@0: else FSectionStartPos=FStartPos, FSectionEndPos=FLength; xue@0: if (LoopPlay) LoopMode=1; xue@0: } xue@0: else //the playback starts from inside the focused selection xue@0: { xue@0: if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, true); xue@0: else xue@0: { xue@0: FSectionStartPos=FSelections->StartPos; if (FSectionStartPos<0) FSectionStartPos=0; xue@0: FSectionEndPos=FSelections->EndPos; if (FSectionEndPos>FLength) FSectionEndPos=FLength; xue@0: } xue@0: if (LoopPlay) LoopMode=2; xue@0: } xue@0: xue@0: if (FSectionEndPos>FSectionStartPos) xue@0: { xue@0: int PlayBufferSize=FSection->BlockSize/PlayBytesPerSample+FSpecRes; xue@0: if (FSection->Channels!=2) xue@0: { xue@0: PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize); PlayBuffer1=0; xue@0: memset(PlayBuffer0, 0, sizeof(double)*FSpecRes); xue@0: } xue@0: else xue@0: { xue@0: PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize*2); PlayBuffer1=&PlayBuffer0[PlayBufferSize]; xue@0: memset(PlayBuffer0, 0, sizeof(double)*FSpecRes); memset(PlayBuffer1, 0, sizeof(double)*FSpecRes); xue@0: } xue@0: PBPR=FSectionStartPos, PBPA=0, PBPW=0; xue@0: if (FForceHamming) fw1=NewWindow8(wtHamming, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); xue@0: else fw1=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); xue@0: fw2=NewWindow8(wtHann, FSpecRes, NULL, NULL, 0); fw2_fw1=(double*)malloc8(sizeof(double)*FSpecRes*2); ifw1=&fw2_fw1[FSpecRes]; xue@0: 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: for (int i=1; iPlay(&WaveViewSectionPlaybackDone); xue@0: ItemPlay->Caption=WV2_STRINGS_Stop_playback; xue@0: if (FOnPlaybackStart) FOnPlaybackStart(this); xue@0: } xue@0: } xue@0: else xue@0: { xue@0: PausePlayback(this); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::TFFilter(int channel, bool pass, bool wholelength) xue@0: { xue@0: ::TFFilter(this, channel, FSelections, pass, wholelength); xue@0: } xue@0: xue@0: void __fastcall TWaveView::UndoExtract(TObject* Sender) xue@0: { xue@0: SetArea(UndoExtractSelection.StartPos, UndoExtractSelection.EndPos, UndoExtractSelection.StartDigiFreq, UndoExtractSelection.EndDigiFreq); xue@0: UndoExtractSelection.EndPos=-1; xue@0: } xue@0: xue@0: void __fastcall TWaveView::UpdateScrollBar(TObject* Sender) xue@0: { xue@0: TNotifyEvent SBChange=FScrollBar->OnChange; xue@0: FScrollBar->OnChange=NULL; xue@0: if (FEndPos-FStartPos>=FLength) xue@0: { xue@0: FScrollBar->PageSize=FLength; xue@0: FScrollBar->SetParams(FStartPos, 0, FLength); xue@0: ScrollBar->Visible=false; xue@0: } xue@0: else xue@0: { xue@0: FScrollBar->SetParams(FStartPos, 0, FLength); xue@0: FScrollBar->PageSize=FEndPos-FStartPos; xue@0: int change=FScrollBar->PageSize/10; xue@0: if (change>FSamplesPerSec/2) change=FSamplesPerSec/2; xue@0: FScrollBar->SmallChange=change; xue@0: change=FScrollBar->PageSize*0.9; xue@0: if (change>FSamplesPerSec) change=FSamplesPerSec; xue@0: FScrollBar->LargeChange=change; xue@0: FScrollBar->Visible=true; xue@0: } xue@0: FScrollBar->OnChange=SBChange; xue@0: } xue@0: xue@0: void __fastcall TWaveView::WaveViewAudioChange(TObject* Sender) xue@0: { xue@0: WaveAudio=FWaveAudio; xue@0: if (WaveAudio==FWaveAudio && FSection->Playing && true) xue@0: { xue@0: FSectionStartPos=FStartPos; xue@0: FSectionEndPos=FEndPos; xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::WaveViewHitTest(int X, int Y) xue@0: { xue@0: FCurrentPane=-1; xue@0: for (int i=0; i=Rect.left && X=Rect.top && Y=Rect.left && X=Rect.top && YCaption=WV2_STRINGS_Play; xue@0: xue@0: if (PlayBuffer0) xue@0: { xue@0: free8(PlayBuffer0); xue@0: PlayBuffer0=0; xue@0: free8(fw1); free8(fw2); free8(fw2_fw1); xue@0: } xue@0: xue@0: FSectionProgress=-1; xue@0: free8(loopframe0); xue@0: free8(loopframe1); xue@0: if (FOnPlaybackDone) FOnPlaybackDone(this); xue@0: } xue@0: xue@0: void __fastcall TWaveView::WaveViewSectionPlaybackProg(TObject* Sender, double Progress) xue@0: { xue@0: if (FProgressCursor) xue@0: { xue@0: FSectionProgress=PBPR-FSpecRes/2; xue@0: if (AutoScroll && PBPR>FEndPos) xue@0: { xue@0: int len=FEndPos-FStartPos; xue@0: int newen=FEndPos+len; xue@0: if (newen>FLength) newen=FLength; xue@0: SetStartAndEndPos(newen-len, newen); xue@0: } xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::Zoom(int X, double Rate) xue@0: { xue@0: int X1,X2; xue@0: bool pagechange=false; xue@0: xue@0: if (Rate<=0){X1=0; X2=FLength;} xue@0: else xue@0: { xue@0: X1=FStartPos-X; X2=FEndPos-X; xue@0: X1=floor(X1*Rate); X2=ceil(X2*Rate); xue@0: X1+=X; X2+=X; xue@0: if (X1<0) X1=0; if (X2>Length) X2=Length; xue@0: if (X1>=X2) X1=X2-1; xue@0: } xue@0: xue@0: if (FStartPos!=X1) FStartPos=X1, pagechange=true; xue@0: if (FEndPos!=X2) FEndPos=X2, pagechange=true; xue@0: if (pagechange) xue@0: { xue@0: Invalidate(); xue@0: PageChange(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::ZoomF(double Y, double Rate, int yscale) xue@0: { xue@0: double Y1, Y2; xue@0: xue@0: if (Rate<=0) {Y1=0; Y2=0.5;} xue@0: else xue@0: { xue@0: if (yscale==0) //linear scale xue@0: { xue@0: Y1=FStartDigiFreq-Y; Y2=FEndDigiFreq-Y; xue@0: Y1=Y1*Rate; Y2=Y2*Rate; xue@0: Y1+=Y; Y2+=Y; xue@0: if (Y1<0) Y1=0; if (Y2>0.5) Y2=0.5; xue@0: } xue@0: else //log scale xue@0: { xue@0: double AStartDigiFreq=(FStartDigiFreq>WV2_MIN_LOG_FREQ)?FStartDigiFreq:WV2_MIN_LOG_FREQ; xue@0: double AnEndDigiFreq=(FEndDigiFreq>WV2_MIN_LOG_FREQ)?FEndDigiFreq:WV2_MIN_LOG_FREQ; xue@0: if (Y0.5) Y2=0.5; xue@0: } xue@0: } xue@0: xue@0: if (FStartDigiFreq!=Y1 || FEndDigiFreq!=Y2) xue@0: { xue@0: FStartDigiFreq=Y1, FEndDigiFreq=Y2; xue@0: Invalidate(); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TWaveView::ZoomY(double Rate) xue@0: { xue@0: FYZoomRate*=Rate; xue@0: Invalidate(); xue@0: } xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: //--------------------------------------------------------------------------- xue@0: // ValidCtrCheck is used to assure that the components created do not have xue@0: // any pure virtual functions. xue@0: // xue@0: namespace Waveview xue@0: { xue@0: void __fastcall PACKAGE Register() xue@0: { xue@0: TComponentClass classes[1] = {__classid(TWaveView)}; xue@0: RegisterComponents("Samples", classes, 0); xue@0: } xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: #undef USE_ASM