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

📄 vib.cpp

📁 声音处理程序,通过FFT可以看声音的频谱.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	static CPen penFreq;
	static CPen penGrid;
	static CPen penSignal;
	if(cx!=rectClient.Width() || cy!=rectClient.Height() || nMaxFreq!=m_nDispMaxFreq)
	{
		cx=rectClient.Width();
		cy=rectClient.Height();
		nMaxFreq=m_nDispMaxFreq;

		mdc.DeleteDC();
		mdc.CreateCompatibleDC(pDC);
		bmp.DeleteObject();
		bmp.CreateCompatibleBitmap(pDC,cx,cy);
		penEnvelop.DeleteObject();penEnvelop.CreatePen(PS_SOLID,1,RGB(0,0,128));
		penFreq.DeleteObject();penFreq.CreatePen(PS_SOLID,1,RGB(255,0,0));
		penGrid.DeleteObject();penGrid.CreatePen(PS_SOLID,1,RGB(0,0,0));
		penSignal.DeleteObject();penSignal.CreatePen(PS_SOLID,1,RGB(0,128,0));
		font.DeleteObject();
		font.CreatePointFont(120,"Arial",pDC);
		CFont* pOldFont=mdc.SelectObject(&font);
		sizeText=pDC->GetTextExtent("字",2);
		pDC->SelectObject(pOldFont);
		nSubGrids=rectClient.Width()/sizeText.cx;
		nMainSubs=8;
		dScaleX=0;
		dFreqTo=m_nDispMaxFreq;
		CalcGrid(dScaleX,dFreqTo,nSubGrids,nMainSubs);
	}
	CPen* pOldPen=mdc.SelectObject(&penEnvelop);
	CFont* pOldFont=mdc.SelectObject(&font);
	CBitmap* pOldBmp=mdc.SelectObject(&bmp);
	mdc.FillSolidRect(rectClient,RGB(255,255,255));
	
	//画频谱
	dScaleX=1000.0/m_msWinFFT*rectClient.Width()/dFreqTo;
	dScaleY=rectClient.Height()/131072.0;
	dScaleY=m_nDispFreqPlus<0?-dScaleY/m_nDispFreqPlus:dScaleY*m_nDispFreqPlus;
	y0=rectClient.bottom-rectClient.Height()/4;
	p=m_nDispMaxFreq*m_msWinFFT/1000+1;
	for(i=0;i<p;i++)
	{
		x=rectClient.left+(int)(i*dScaleX+0.5);
		y=(int)(dScaleY*sqrt(m_aEnvelop[i])+0.5);
		if(i)mdc.LineTo(x,y0-y);else mdc.MoveTo(x,y0-y);
	}
	c=RGB(128,128,128);
	p0=-1;f0=(UINT)-1/2;
	mdc.SelectObject(&penFreq);
	for(i=0;i<p;i++)
	{
		x=rectClient.left+(int)(i*dScaleX+0.5);
		y=(int)(dScaleY*sqrt(m_aFFTOut[i])+0.5);
		if(i)mdc.LineTo(x,y0-y);else mdc.MoveTo(x,y0-y);
		if(m_nFreqBlur)
		{
			if(y>f0)p0=i;
			else if(y<f0 && p0>-1)
			{
				p0=(p0+i)/2;
				x=rectClient.left+(int)(p0*dScaleX+0.5);
				mdc.FillSolidRect(x,y0-f0,1,f0,c);
				p0=-1;
			}
			f0=y;
		}
	}
	
	//画刻度
	mdc.FillSolidRect(rectClient.left,y0,rectClient.Width(),1,RGB(0,0,0));
	mdc.SetBkColor(RGB(255,255,255));
	mdc.SelectObject(&penGrid);
	dScaleX=double(rectClient.Width())/nSubGrids;
	dScaleY=dFreqTo/nSubGrids;
	p=nSubGrids;
	rect.top=y0+20;rect.bottom=rect.top+sizeText.cy;
	for(i=1;i<p;i++)
	{
		x=rectClient.left+int(i*dScaleX+0.5);
		if(i%nMainSubs){mdc.MoveTo(x,y0);mdc.LineTo(x,y0+10);}
		else 
		{
			mdc.MoveTo(x,y0);mdc.LineTo(x,y0+20);
			str.Format("%g",i*dScaleY);
			rect.left=x-sizeText.cx*3;
			rect.right=x+sizeText.cx*3;
			mdc.DrawText(str,&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
		}
	}

	//画数值
	rect.left=rectClient.left;rect.right=rectClient.right;
	rect.top=y0+sizeText.cy;rect.bottom=rectClient.bottom;
	str.Format("当前振动值:%3d   峰值:%3d",m_nCurVibration,m_nPeakVibration);
	mdc.SetTextColor(m_nCurVibration+m_nPeakVibration>0?RGB(255,0,0):RGB(0,0,128));
	mdc.DrawText(str,&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
	mdc.SetTextColor(RGB(0,0,0));

	//画曲线
	p=m_nFFTPoint*m_msDispMaxTime/m_msWinFFT;
	dScaleX=1.0*rectClient.Width()/p;
	dScaleY=rectClient.Height()/131072.0;
	dScaleY=m_nDispSignalPlus<0?-dScaleY/m_nDispSignalPlus:dScaleY*m_nDispSignalPlus;
	y0=rectClient.bottom-rectClient.Height()*3/4;
	mdc.FillSolidRect(rectClient.left,y0,rectClient.Width(),1,RGB(192,192,192));
	mdc.SelectObject(&penSignal);
	for(i=0;i<p;i++)
	{
		x=rectClient.left+(int)(i*dScaleX+0.5);
		y=y0-(int)(dScaleY*m_aFFTIn[i]+0.5);
		if(i)mdc.LineTo(x,y);else mdc.MoveTo(x,y);
	}

	pDC->BitBlt(rectClient.left,rectClient.top,
		rectClient.Width(),rectClient.Height(),
		&mdc,rectClient.left,rectClient.top,SRCCOPY);
	mdc.SelectObject(pOldBmp);
	mdc.SelectObject(pOldFont);
	mdc.SelectObject(pOldPen);
}

BOOL CVibApp::CreateFIR(double* aw, int &N, double p1, double p2, double tw, double fs)
{
	int nMode,i,n;
	double w,w0,w1,dVal;
	
	if(fs<=0 || tw<=0 || tw>=fs || p1>fs || (p1<=0 && p2<=0))return FALSE;
	else if(p1<=0){nMode=1;w1=p2+tw/2;w0=fs;}
	else if(p2<=0 || p2>=fs){nMode=2;w1=fs/2-p1+tw/2;w0=fs/2;}
	else{nMode=3;w1=(p2-p1+tw)/2;w0=(p1+p2)/2;}

	//i=(int)(5.98*fs/tw); //布莱克曼
	//i=(int)(3.44*fs/tw); //哈明
	i=(int)(3.32*fs/tw); //汉宁
	if((i%2)==0)i++;
	if(N<i){N=i;return FALSE;}

	N=i;i=N/2;
	w1*=2*MATH_PI/fs;
	w0*=2*MATH_PI/fs;
	w=MATH_PI/i;
	aw[i]=w1/MATH_PI;
	for(n=1;n<=i;n++)
	{
		dVal=sin(n*w1)/(n*MATH_PI);
		//dVal*=0.42+0.5*cos(n*w)+0.08*cos(2*n*w); //布莱克曼
		//dVal*=0.54+0.46*cos(n*w); //哈明
		dVal*=0.50+0.50*cos(n*w); //汉宁

		if(nMode>1)dVal*=cos(n*w0);
		aw[i-n]=dVal;aw[n+i]=dVal;
	}
	for(i=0;i<N;i++)TRACE("aw[%d]=%.5f\r\n",i,aw[i]);
	return TRUE;
}

void CVibApp::DefautConfig()
{
	m_msWinFFT=200;
	m_nFreqHalfLive=1;
	m_nFreqValue=0;
	m_nFreqBlur=100;

	m_nPassbandFreq1=0;
	m_nPassbandFreq2=0;
	m_nTransbandWidth=500;
	m_bModulate=FALSE;

	m_nDispMaxFreq=5000;
	m_msDispMaxTime=100;
	m_nDispSignalPlus=1;
	m_nDispFreqPlus=4;
}

void CVibApp::LoadConfig()
{
	int i,i0,j;	
	m_msWinFFT=GetProfileInt("Config","WinFFT",m_msWinFFT);
	m_nFreqHalfLive=GetProfileInt("Config","FreqHalfLive",m_nFreqHalfLive);
	m_nFreqValue=GetProfileInt("Config","FreqValue",m_nFreqValue);
	m_nFreqBlur=GetProfileInt("Config","FreqBlur",m_nFreqBlur);

	m_nPassbandFreq1=GetProfileInt("Config","PassbandFreq1",m_nPassbandFreq1);
	m_nPassbandFreq2=GetProfileInt("Config","PassbandFreq2",m_nPassbandFreq2);
	m_nTransbandWidth=GetProfileInt("Config","TransbandWidth",m_nTransbandWidth);
	m_bModulate=GetProfileInt("Config","Modulate",m_bModulate);

	m_nDispMaxFreq=GetProfileInt("Config","DispMaxFreq",m_nDispMaxFreq);
	m_msDispMaxTime=GetProfileInt("Config","DispMaxTime",m_msDispMaxTime);
	m_nDispSignalPlus=GetProfileInt("Config","DispSignalPlus",m_nDispSignalPlus);
	m_nDispFreqPlus=GetProfileInt("Config","DispFreqPlus",m_nDispFreqPlus);

	//计算采样频率与FFT点数
	i=1;
	j=22050*m_msWinFFT/1000;
	while(i<j)i*=2;
	i0=i/2;
	if((double)(i-j)/i > (double)(j-i0)/i0)i=i0;
	m_nFFTPoint=i; if(m_nFFTPoint>30000)m_nFFTPoint/=2;
	m_nSampleFreq=m_nFFTPoint*1000/m_msWinFFT;
	
	//计算频谱的的半衰期差分系数
	i=(int)(m_nFreqHalfLive*1000.0/m_msWinFFT+0.5);
	m_dFreqHalfLive=i>1?exp(log(0.5)/i):0;
	
	//安全
	m_nDispMaxFreq=min(m_nDispMaxFreq,m_nFFTPoint*500/m_msWinFFT);
	m_msDispMaxTime=min(m_msDispMaxTime,m_msWinFFT);

	m_aData=new short[m_nFFTPoint];
	m_aEnvelop=new double[m_nFFTPoint];
	m_aFilter=new double[m_nFFTPoint]; 
	m_aFFTIn=new double[m_nFFTPoint];
	m_aFFTOut=new double[m_nFFTPoint];
	m_aPeak=new double[m_nFFTPoint]; 
	ZeroMemory(m_aData,sizeof(short)*m_nFFTPoint);
	ZeroMemory(m_aEnvelop,sizeof(double)*m_nFFTPoint);
	ZeroMemory(m_aFilter,sizeof(double)*m_nFFTPoint);
	ZeroMemory(m_aFFTIn,sizeof(double)*m_nFFTPoint);
	ZeroMemory(m_aFFTOut,sizeof(double)*m_nFFTPoint);
	ZeroMemory(m_aPeak,sizeof(double)*m_nFFTPoint);
	
	//创建频率模糊系数
	i0=m_nFreqBlur*m_msWinFFT/1000;
	for(i=1;i<i0;i++)
	{
		//m_aFilter[m_nFFTPoint-i]=0.50+0.50*cos(MATH_PI*i/i0); //汉宁
		m_aFilter[m_nFFTPoint-i]=0.42+0.5*cos(MATH_PI*i/i0)+0.08*cos(2*MATH_PI*i/i0); //布莱克曼
	}
	//创建信号滤波系数
	m_nFilterCnt=i=m_nFFTPoint-i0;
	CreateFIR(m_aFilter,m_nFilterCnt,m_nPassbandFreq1,m_nPassbandFreq2,m_nTransbandWidth,m_nSampleFreq);
	if(m_nFilterCnt>=i)m_nFilterCnt=0;

	ConfigOption(FALSE);
	m_bPause=FALSE;
}
void CVibApp::SaveConfig()
{
	ConfigOption(TRUE);

	delete[] m_aData;
	delete[] m_aEnvelop;
	delete[] m_aFilter;
	delete[] m_aFFTIn;
	delete[] m_aFFTOut;
	delete[] m_aPeak;

	WriteProfileInt("Config","WinFFT",m_msWinFFT);
	WriteProfileInt("Config","FreqHalfLive",m_nFreqHalfLive);
	WriteProfileInt("Config","FreqValue",m_nFreqValue);
	WriteProfileInt("Config","FreqBlur",m_nFreqBlur);

	WriteProfileInt("Config","PassbandFreq1",m_nPassbandFreq1);
	WriteProfileInt("Config","PassbandFreq2",m_nPassbandFreq2);
	WriteProfileInt("Config","TransbandWidth",m_nTransbandWidth);
	WriteProfileInt("Config","Modulate",m_bModulate);

	WriteProfileInt("Config","DispMaxFreq",m_nDispMaxFreq);
	WriteProfileInt("Config","DispMaxTime",m_msDispMaxTime);
	WriteProfileInt("Config","DispSignalPlus",m_nDispSignalPlus);
	WriteProfileInt("Config","DispFreqPlus",m_nDispFreqPlus);
}

int CVibApp::CalcGrid(double& dFrom,double& dTo,int& nSubGrids,int &nMainSubs)
{
	int m;
	double b,dSub,dMain,dValue;

	b=log10((dTo-dFrom)/nSubGrids);
	m=(int)floor(b);b-=m;
	if(b>0.875)b=10;
	else if(b>0.544)b=5;
	else if(b>0.176)b=2;
	else b=1;
	dSub=b*pow(10,m); //每小格单位
	dValue=fmod(dFrom,dSub);
	if(dValue>0)dFrom-=dValue<dSub?dValue:0;
	else if(dValue<0)dFrom-=dValue>-dSub?dSub+dValue:0;
	dValue=fmod(dTo,dSub);
	if(dValue>0)dTo+=dValue<dSub?dSub-dValue:0;
	else if(dValue<0)dTo-=dValue>-dSub?dValue:0;

	b=(double)nMainSubs/nSubGrids;
	nSubGrids=(int)((dTo-dFrom)/dSub+0.5); //确定小格总数
	b=log10(b*nSubGrids);
	m=(int)floor(b);b-=m;
	if(b>0.875)b=10;
	else if(b>0.544)b=5;
	else if(b>0.176)b=2;
	else b=1;
	b*=pow(10,m);
	nMainSubs=(int)(b+0.5); //每主格的小格数
	dMain=nMainSubs*dSub; //每主格的单位
	dValue=fmod(dFrom,dMain);
	if(dValue>0)m=dValue<dMain?(int)((dMain-dValue)/dSub+0.5):0;
	else if(dValue<0)m=dValue>-dMain?(int)(-dValue/dSub+0.5):0;
	else m=0;
	return m;
}


BOOL CVibApp::ConfigOption(BOOL bSave)
{
	if(bSave)
	{
		WriteProfileString("Config","Envelop",m_strEnvelop);
		WriteProfileInt("Config","EnvelopSense",m_bEnvelopSense);
	}
	else
	{
		int i,nAT;
		int f,x1,y1,x2=-99999,y2=0;
		double dVal;
		CString s,str;
		m_strEnvelop=GetProfileString("Config","Envelop");
		str=m_strEnvelop+";99999=0;";
		for(i=0;i<m_nFFTPoint;i++)
		{
			f=i*1000/m_msWinFFT;
			while(x2<f)
			{
				nAT=str.Find(";");
				s=str.Left(nAT);
				str=str.Mid(nAT+1);

				x1=x2;y1=y2;
				x2=atoi(s);y2=atoi(s.Mid(s.Find('=')+1));
			}
			dVal=double(y2-y1)/(x2-x1);
			dVal*=f-x1;dVal+=y1;
			m_aEnvelop[i]=dVal*dVal;
		}

		m_bEnvelopSense=GetProfileInt("Config","EnvelopSense",1);
	}
	return TRUE;
}

void CVibApp::SetPause(BOOL bPause)
{
	if(bPause)
	{
		CopyMemory(m_aFFTOut,m_aPeak,sizeof(double)*m_nFFTCnt/2);
		m_pView->Invalidate(FALSE);
	}
	else
	{
		ZeroMemory(m_aFFTOut,sizeof(double)*m_nFFTCnt);
		ZeroMemory(m_aPeak,sizeof(double)*m_nFFTCnt);
	}
	m_bPause=bPause;
}

BOOL CVibApp::OnIdle(LONG lCount) 
{
	// TODO: Add your specialized code here and/or call the base class
	if(m_pView->m_bRestart)
	{
		m_pView->m_bRestart=FALSE;
		m_pView->StartWave(TRUE);
	}
	return CWinApp::OnIdle(lCount);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -