⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sample.cpp

📁 C++ , microphone spectrogram viewer, real time
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  // 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 + -