📄 sample.cpp
字号:
// Precompute complex exponentials
int _2_l = 2;
for (int l = 1; l <= logPoints; l++)
{ W[l] = new TComplex[FnPoints];
for (int i=0; i<FnPoints; i++ )
{ double re = cos (2. * PI * i / _2_l);
double im = -sin (2. * PI * i / _2_l);
W[l][i] = TComplex (re, im);
}
_2_l *= 2;
}
// set up bit reverse mapping
int rev = 0;
int halfPoints = FnPoints/2;
for (int i=0; i<FnPoints-1; i++)
{ aBitRev[i] = rev;
int mask = halfPoints;
// add 1 backwards
while (rev >= mask)
{ rev -= mask; // turn off this bit
mask >>= 1;
}
rev += mask;
}
aBitRev [FnPoints-1] = FnPoints-1;
for (int i=0; i<MAX_FFTINTERESTS; i++) {if (interest[i]!=NULL) interest[i](this,rrOpen);}
}
void __fastcall TFFT::CopyIn()
{ int cSample=Source->BufNumSamples;
if (cSample>FnPoints) return;
// make space for cSample samples at the end of tape
// shifting previous samples towards the beginning
memmove(aTape, &aTape[cSample],
(FnPoints-cSample)*sizeof(double));
// copy samples from source to tail end of tape
int iTail = FnPoints-cSample;
for (int i=0; i<cSample; i++)
{ aTape[i+iTail]=(double)Source->iData[i]; }
// Initialize the FFT buffer
for (int i=0; i<FnPoints; i++) X[aBitRev[i]]=TComplex(aTape[i]);
}
void __fastcall TFFT::Transform ()
{ int step = 1;
for (int level=1; level<=logPoints; level++)
{ int increm = step*2;
for (int j=0; j<step; j++)
{ // U = exp ( - 2 PI j / 2 ^ level )
TComplex U = W [level][j];
for (int i=j; i<FnPoints; i+=increm)
{ // butterfly
TComplex T = U;
T *= X [i+step];
X [i+step] = X[i];
X [i+step] -= T;
X [i] += T;
}
}
step *= 2;
}
}
void __fastcall TFFT::Sample(TRecorder *rec)
{ CopyIn();
Transform();
for (int i=0; i<MAX_FFTINTERESTS; i++) {if (interest[i]!=NULL) interest[i](this,rrData);}
}
//---------------------------------------------------------------------------
__fastcall TWaveView::TWaveView(TComponent* Owner)
: TGraphicControl(Owner)
{ isRegistered=false; FSource=NULL;
numPoints=0; pts=NULL;
Width=200; Height=100;
Color=clBlack;
Line=clLime;
nFrame=0;
FSkip=0;
}
__fastcall TWaveView::~TWaveView()
{ UnregisterInterest();
if (pts!=NULL) delete[] pts; pts=NULL;
}
void __fastcall TWaveView::SetSource(TRecorder *s)
{ UnregisterInterest();
FSource=s;
RegisterInterest();
s->FreeNotification(this);
}
void __fastcall TWaveView::UnregisterInterest()
{ if (FSource!=NULL && isRegistered) FSource->RemoveInterest(InterestProc);
isRegistered=false;
}
void __fastcall TWaveView::RegisterInterest()
{ if (FSource==NULL || isRegistered) return;
FSource->AddInterest(InterestProc); isRegistered=true;
}
void __fastcall TWaveView::InterestProc(TObject *Sender, TRecorderReason rr)
{ if (rr==rrTidy) {isRegistered=false; return;}
if (rr==rrData) {if (nFrame>=SkipFrames) {Sample(Source);nFrame=0;}else nFrame++;}
}
void __fastcall TWaveView::Notification(TComponent *c,TOperation op)
{ if (op==opRemove && c==FSource) FSource=NULL;
}
void __fastcall TWaveView::SetLine(TColor col)
{ if (FLine==col) return;
FLine=col; Invalidate();
}
void __fastcall TWaveView::Paint()
{ Canvas->Brush->Color=Color;
Canvas->FillRect(Canvas->ClipRect);
if (ComponentState.Contains(csDesigning))
{ POINT pt[4]; int ch=ClientHeight,cw=ClientWidth;
int maxx=cw;
//if (Source!=NULL)
//{ if (Source->BufSize<maxx) maxx=Source->BufSize;
//} This stuff no longer relevant, because I've changed the Sample
// routine to make it stretch to fit available width
pt[0].x=0; pt[0].y=(ch-1)/2;
pt[1].x=maxx/4; pt[1].y=ch*1/4;
pt[2].x=maxx*3/4; pt[2].y=ch*3/4;
pt[3].x=maxx-1; pt[3].y=(ch-1)/2;
Canvas->Pen->Color=Line;
Canvas->Polyline(pt,3);
}
}
void __fastcall TWaveView::Sample(TRecorder *rec)
{ int npts=rec->BufNumSamples;
if (npts>numPoints)
{ if (pts!=NULL) delete[] pts;
pts=new POINT[npts];
numPoints=npts;
}
int ch=ClientHeight, cw=ClientWidth;
int xnumer=cw, xdenom=npts; if (xdenom>xnumer) xdenom=xnumer;
int ynumer=ch, ydenom=256*32*2;
for (int i=0; i<npts; i++)
{ int scaledx=i*xnumer/xdenom;
int scaledy=rec->iData[i]*ynumer/ydenom+ch/2;
if (scaledx>=cw)
{ pts[i].x=cw-1; pts[i].y=(ch-1)/2;
}
else
{ if (scaledy<0) {pts[i].x=scaledx; pts[i].y=0;}
else if (scaledy>=ch) {pts[i].x=scaledx; pts[i].y=ch-1;}
else {pts[i].x=scaledx; pts[i].y=scaledy;}
}
}
Paint();
Canvas->Pen->Color=Line;
Canvas->Polyline(pts,npts-1);
}
//---------------------------------------------------------------------------
__fastcall TFingerprintView::TFingerprintView(TComponent* Owner)
: TGraphicControl(Owner)
{ isRegistered=false; FSource=NULL;
Width=200; Height=100;
x=0;
Color=clBlack;
FLine=clWhite;
nFrame=0; FSkip=0;
}
__fastcall TFingerprintView::~TFingerprintView()
{ UnregisterInterest();
}
void __fastcall TFingerprintView::SetSource(TFFT *s)
{ UnregisterInterest();
FSource=s;
RegisterInterest();
s->FreeNotification(this);
}
void __fastcall TFingerprintView::SetLine(TColor col)
{ if (FLine==col) return;
FLine=col; Invalidate();
}
void __fastcall TFingerprintView::UnregisterInterest()
{ if (FSource!=NULL && isRegistered) FSource->RemoveInterest(InterestProc);
isRegistered=false;
}
void __fastcall TFingerprintView::RegisterInterest()
{ if (FSource==NULL || isRegistered) return;
FSource->AddInterest(InterestProc); isRegistered=true;
}
void __fastcall TFingerprintView::InterestProc(TObject *Sender, TRecorderReason rr)
{ if (rr==rrTidy) {isRegistered=false; return;}
if (rr==rrData) {if (nFrame>=SkipFrames) {Sample(Source);nFrame=0;}else nFrame++;}
}
void __fastcall TFingerprintView::Paint()
{ if (!ComponentState.Contains(csDesigning)) return;
Canvas->Brush->Color=Color;
Canvas->FillRect(Canvas->ClipRect);
if (Source!=NULL)
{ int ch=ClientHeight,cw=ClientWidth;
Canvas->Pen->Color=clGreen;
Canvas->Font->Color=clGreen;
Canvas->Font->Height=8;
for (int i=0; i<Source->BufSize/2 && i<ch; i+=30)
{ int hz=Source->FrequencyFromPoint(i);
Canvas->TextOut(15,ch-i-1-22,String(hz/1000)+"."+String((hz/100)%10)+"KHz");
}
for (int i=0; i<Source->BufSize/2 && i<ch; i+=30)
{ Canvas->MoveTo(0,ch-i-1); Canvas->LineTo(cw,ch-i-1);
}
Canvas->Pen->Color=Line;
Canvas->MoveTo(5,0); Canvas->LineTo(5,ch);
}
}
void __fastcall TFingerprintView::Notification(TComponent *c,TOperation op)
{ if (op==opRemove && c==FSource) FSource=NULL;
}
COLORREF MapColor (int s)
{ if (s<16) return RGB(0, 0, 128);
else if (s<32) return RGB(0, 0, 255);
else if (s<64) return RGB(0, 255, 0);
else if (s<128)return RGB(255, 255, 0);
else if (s<256)return RGB(255, 128, 0);
else return RGB(255, 0, 0);
}
void __fastcall TFingerprintView::Sample(TFFT *src)
{ int cw=ClientWidth,ch=ClientHeight;
// Erase background for current spectrum
Canvas->Pen->Color=Color;
Canvas->MoveTo(x,0); Canvas->LineTo(x,ch);
Canvas->MoveTo(x+1,0); Canvas->LineTo(x+1,ch);
for (int i=0; i<src->BufSize/2 && i<ch; i++)
{ int s = int (src->IntensityFromFrequency(i)/256);
COLORREF color;
if (s > 8)
{ color = MapColor (s);
Canvas->Pixels[x][ch-i-1]=TColor(color);
Canvas->Pixels[x+1][ch-i-1]=TColor(color);
}
}
x += 2;
if (x >= cw) x=0;
// Draw white vertical mark
Canvas->Pen->Color=Line;
Canvas->MoveTo(x,0); Canvas->LineTo(x,ch);
}
//---------------------------------------------------------------------------
__fastcall TSpectralView::TSpectralView(TComponent* Owner)
: TGraphicControl(Owner)
{ isRegistered=false; FSource=NULL;
Width=200; Height=100;
FSkip=0;
FBands=10;
nFrame=0;
Line=clGreen;
Color=clBlack;
}
__fastcall TSpectralView::~TSpectralView()
{ UnregisterInterest();
}
void __fastcall TSpectralView::SetSource(TFFT *s)
{ UnregisterInterest();
FSource=s;
RegisterInterest();
s->FreeNotification(this);
}
void __fastcall TSpectralView::Notification(TComponent *c,TOperation op)
{ if (op==opRemove && c==FSource) FSource=NULL;
}
void __fastcall TSpectralView::SetLine(TColor col)
{ if (FLine==col) return;
FLine=col; Invalidate();
}
void __fastcall TSpectralView::SetBands(int b)
{ if (FBands==b) return;
FBands=b; Invalidate();
}
void __fastcall TSpectralView::UnregisterInterest()
{ if (FSource!=NULL && isRegistered) FSource->RemoveInterest(InterestProc);
isRegistered=false;
}
void __fastcall TSpectralView::RegisterInterest()
{ if (FSource==NULL || isRegistered) return;
FSource->AddInterest(InterestProc); isRegistered=true;
}
void __fastcall TSpectralView::InterestProc(TObject *Sender, TRecorderReason rr)
{ if (rr==rrTidy) {isRegistered=false; return;}
if (rr==rrData) {if (nFrame>=SkipFrames) {Sample(Source);nFrame=0;}else nFrame++;}
}
void __fastcall TSpectralView::Paint()
{ Canvas->Brush->Color=Color;
Canvas->FillRect(Canvas->ClipRect);
if (ComponentState.Contains(csDesigning))
{ int ch=ClientHeight,cw=ClientWidth;
Canvas->Pen->Color=Line;
Canvas->Brush->Color=Line;
Canvas->Font->Color=Line;
Canvas->Font->Height=8;
int tb=Bands; if (tb==0) tb=10;
int screendiv=cw/Bands, screenpos=0;
int div,pos;
if (Source!=NULL)
{ div=Source->BufSize/(2*Bands); pos=0;
}
for (int b=0; b<tb; b++)
{ int tot=ch*((b*((int)Line+10))%tb)/(tb+2);
TRect r; r.Left=screenpos; r.Right=r.Left+screendiv;
r.Top=ch-tot; r.Bottom=ch;
if (Source!=NULL)
{ Canvas->Brush->Color=clBlack;
int hz=Source->FrequencyFromPoint(pos+(div/2));
Canvas->TextOut(r.Left,r.Top-16,String(hz/1000)+"."+String((hz/100)%10)+"KHz");
pos=pos+div;
Canvas->Brush->Color=Line;
}
Canvas->FillRect(r);
screenpos+=screendiv;
}
}
}
void __fastcall TSpectralView::Sample(TFFT *src)
{ int cw=ClientWidth,ch=ClientHeight;
int nBars=Bands;
int div=src->BufSize/(2*nBars);
int screendiv=cw/nBars;
int pos=0, screenpos=0;
for (int b=0; b<nBars; b++)
{ int tot=0;
for (int i=pos; i<pos+div; i++) tot=tot+src->IntensityFromFrequency(i);
tot=tot/(32*div); if (tot>ch) tot=ch;
Canvas->Brush->Color=clGreen;
TRect r; r.Left=screenpos; r.Right=r.Left+screendiv;
r.Top=ch-tot; r.Bottom=ch;
Canvas->FillRect(r);
r.Top=0; r.Bottom=ch-tot;
Canvas->Brush->Color=clBlack;
Canvas->FillRect(r);
pos+=div;
screenpos+=screendiv;
}
}
//---------------------------------------------------------------------------
namespace Sample
{ void __fastcall PACKAGE Register()
{ TComponentClass classes[] = {__classid(TRecorder),
__classid(TFFT),
__classid(TWaveView),
__classid(TFingerprintView),
__classid(TSpectralView)};
RegisterComponents("ScrPlus",classes,(sizeof(classes)/sizeof(classes[0]))-1);
RegisterPropertyEditor(__typeinfo(TWaveInDeviceID),0,"",__classid(TWaveInDeviceIDProperty));
RegisterPropertyEditor(__typeinfo(TAudioLineParameters),0,"",__classid(TAudioLineParametersProperty));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -