基于声卡的频率计专业课程方案设计书报告.docx
《基于声卡的频率计专业课程方案设计书报告.docx》由会员分享,可在线阅读,更多相关《基于声卡的频率计专业课程方案设计书报告.docx(33页珍藏版)》请在冰点文库上搜索。
基于声卡的频率计专业课程方案设计书报告
专业综合课程设计
题目:
频率计
班级:
姓名:
同组名
指导教师:
设计日期:
引言 .................................................................................................. .......3
设计意义..................................................................................................3
一设计要求..............................................................................................3
二设计方案..............................................................................................4
2.1声卡的采样...................................................................................4
2.2对采样的信号进行频率值计算..................................................4
2.3程序编写模块..............................................................................5
三软件设计............................................................................................6
3.1音频录制.......................................................................................6
3.2数据抽样.....................................................................................7
3.3FFT分析与计算.........................................................................7
3.4显示......................................../....................................................8
四系统调试..............................................................................................9
五总结......................................................................................................9
六附录....................................................................................................10
七参考文献............................................................................................23
用声卡实现的频率计设计
引言
设计意义:
声卡,也叫音频卡,是MPC的必要部件,它是计算机进行声音处理的适配器。
它有三个基本功能:
一是音乐合成发音功能;二是混音器(Mixer)功能和数字声音效果处理器(DSP)功能;三是模拟声音信号的输入和输出功能。
声卡处理的声音信息在计算机中以文件的形式存储。
声卡工作应有相应的软件支持,包括驱动程序、混频程序(mixer)和CD播放程序等。
多媒体电脑中用来处理声音的接口卡。
声卡可以把来自话筒、收录音机、激光唱机等设备的语音、音乐等声音变成数字信号交给电脑处理,并以文件形式存盘,还可以把数字信号还原成为真实的声音输出。
声卡尾部的接口从机箱后侧伸出,上面有连接麦克风、音箱、游戏杆和MIDI设备的接口。
我们常用的PC机中的声卡不仅能输出个录制各种音频信号,利用其内部的A/D(模拟/数字)转换器,通过编写程序还可以对外部的音频信号进行采样处理,观察采样波形,并计算出采样周期,采样平率的最大值等所需的各种数据都可以通过声卡得到。
一设计内容及要求:
基于C++设计一个频率计,利用PC机中的声卡实现对音频的采集,频谱分析,最终计算出原始声音的频率等功能。
二设计方案:
该程序是在VS2010环境中用C++语言编写的,共三大模块:
一是声卡采样模块:
二是对采样的信号进行频率值的计算;三是程序编写模块。
2.1声卡的采样:
声卡是PC的一种多媒体设备,所以可以用Windows的MCI(MediaControlInterface)命令来控制声卡。
MCI它提供了一组与设备无关的控制命令,是一种访问多媒体设备的高层次方法。
也正因为它属于一种高层次方法,所以它提供给程序员的灵活性有限,利用MCI命令来控制声卡录音时,程序员不能在录音的过程中访问内存中的采样数据,只有在录音完成后通过访问*.WAV文件才可以得到采样数据,尽管最终还是得到了采样数据,但是这样做一方面嫌其麻烦,更重要的是存取文件需要耗费时间,声卡在采样的过程中有可能会停止下来等待文件操作,造成了采样的断续。
在一个标准的通过波形声音输入设备记录声音的程序中,函数应该按照以下顺序调用:
获取波形声音输入设备,设置波形声音格式;waveInOpen,打开波形声音输入设备;waveInPrepareHeader,为波形声音输入设备准备一个缓冲区;waveInAddBuffer向波形声音输入设备添加缓冲区;waveInStart开始录音。
在使用waveInOpen这个函数之前,应该设置一个类型为HWAVEIN的变量,传递给该函数来记录输入设备的句柄,并在之后的函数中使用,同时应通过uDeviceID和pwfx指定设备和声音格式,其中WINAPI中给予声音格式。
2.2对采样的信号进行频率值的计算:
标准的数字频率计测量信号的频率值时,为了提高测量精度,一般采用两种方法:
当被测信号的频率远高于基准频率时,采用频率记数法,即基准频率信号作为闸门信号,在该闸门信号的时间间隔内,对被测信号的脉冲进行记数,用公式:
被测信号的频率=被测信号的脉冲数÷闸门信号的时间间隔,计算出信号的频率值;当被测信号的频率远低于基准频率时,采用周期记数法,即被测信号作为闸门信号,在该闸门信号的时间间隔内,对基准信号的脉冲进行记数,用公式:
被测信号的周期=基准信号的脉冲数×基准信号的周期,计算出信号的周期,再求其倒数,就可计算出频率。
该程序计算频率值时,也采用两种方法,不同的是,一种是快速复数傅立叶变换FFTC法即对采得的信号数据进行快速复数傅立叶变换,把时间域的信号转换为频率域的信号,在频率域中找出最大值,就是该信号基波的频率值,另一种是采样脉冲记数法,即在时域内检测出被测信号在采样长度内的周期数M(M取整数),和该周期数内的采样脉冲数N采样长度就是对信号采样的点数,用公式:
被测信号的频率=声卡采样频率×M÷N计算出信号的频率值。
快速复数傅立叶变换FFTC法的优点是,不仅能对常见的标准的周期性波形,如:
正弦波、方波、三角波等信号基波的频率进行测量,而且还能计算出各种复杂波形的和信噪比非常低的信号基波的频率值;如:
淹没于噪声中的信号,缺点是:
分辨率受公式�分辨率=采样频率(Hz)÷采样长度的限制,如:
当采样频率=采样长度时,分辨率是1Hz最小测量误差是=1Hz÷被测信号的频率,可见,被测信号的频率值越低,该方法的测量误差越大。
采样脉冲记数法的优点是:
测量低频信号时精度较高,缺点是:
不适合波形复杂和信噪比低的信号频率的测量。
所以,为了提高测量的可靠性和精度,在被测信号频率高时,或波形复杂时,或信噪比低时,采用快速复数傅立叶变换(FFTC)法:
否则,采用采样脉冲记数法。
在测量的过程中,程序先判断信号上述的性质,根据信号的性质,自动地采用相应的测量方法。
2.3程序编写模块:
在一些实时性要求比较高的场合(比如波形分析,实时控制等),断续的采样明显是不行的。
Windows的低级波形音频函数提供了对声卡的最大灵活性的操作,它允许在采样过程中随机地访问内存中的每个采样数据,完全可以克服使用MCI命令所遇到的实时性问题。
Windows以动态连接库Mmsystem.dll的形式提供低级波形音频函数,在Mmsystem.dll中总共包括了以下几个有关波形录入的函数
waveInAddBuffer:
向声音输入设备发送缓冲区;
waveInClose:
关闭声音输入设备
waveInGetDevCaps:
获取声音输入设备性能;
waveInGetErrorText:
获取声音出错信息文本
waveInGetID:
获取声音输入设备ID;
waveInGetNumDevs:
返回声音输入设备数量
waveInGetPosition:
获取声音设备输入位置;
waveInMessage:
向声音输入设备发送信息
waveInOpen:
打开声音输入设备;
waveInPrepareHeader:
预备声音输入缓冲区
waveInReset:
停止声音输入设备工作;
waveInStart:
停止声音输入设备工作
waveInStop:
停止声音输入;
waveInUnprepareHeader:
清除预备的声音文件头
在C++中对声卡录音编程中,MCI按打开设备、配置设备、实现功能(或曰发送命令)、撤销配置、关闭设备的标准次序组织APIs。
对于录音编程而言,其要点在于根据音频格式打开对应的设备、配置录音所需的参数(主要是设置数据区以及根据数据接收方式设置回调函数或消息)、按一定次序发送命令给设备、接收数据并配置参数以继续录音、停止录音释放资源、关闭设备等几个步骤上。
所需的函数说明于mmsystem.h,引入库是winmm.lib。
三软件设计:
该软件设计公分四个部分:
分别是音频录制部分,音频段落抽样部分,FFT分析与计算部分,频率图形显示部分。
该软件是基于VisualStudio2010环境下用C++语言程序来实现各个模块的功能。
VisualStudio是微软公司推出的开发环境。
是目前最流行的Windows平台应用程序开发环境。
该软件支持开发面向Windows7的应用程序,因此此次设计的软件应用了waveInOpen,在音频处理中也会用到waveInPrepareHeader、waveInAddBuffer、waveInStart、waveInReset及waveInClose等函数。
数据流程如下图:
3.1音频录制部分:
如图1该部分由4个按键组成,按“rec”键开始录音,“stop”键录音停止,“play”键播放音频并且在显示框上显示所录制的音频的频率图形,“pstop”键清0(所有程序停止)。
图1
3.2数据抽样部分:
如图2中2个输入框“起点”、“终点”分别表示在录取的音频信号中抽取的的开始时间和和终止时间,时间间隔加入计时器程序,点击按键“显示”会在显示框中显示出该段的频率。
图2
3.3FFT分析与计算部分:
如图3该部分,点击“FFT”的时候就出现频谱图,左边的显示框显示频率值。
图3
3.4显示部分:
如图4该图所显示的是3种情况下的频率。
图4
四系统调试:
编译完程序代码后,运行调试生产没有错误后打开生产的文件“0907.exe”,点击开始“Rec”开始录音,计数器计时5s,然后点击“play”播放并且显示波形图形,然后选取间隔100~500,经过放大并显示出来,再点击“FFT”计算出所求的频率值,系统调试后的图形如图5。
图5
五总结:
通过这次的专业课程设计让我们学到很多,首先要感谢老师的悉心教导,老师给予我们信心和动力做出这个程序,让我们非计算机专业的学生也能编出一个程序来,给予我们为以后就业增长了很多经验。
同时更要感谢同学的不断努力,客服层层困难,最后做出来了。
我们学到了很多的知识。
我们要在windows下自带的录音机中采集一段语音信号,虽然看起来简单,但是要弄清C++语言的各种函数,方法,语言结构还是需要花费很多的时间来攻克并且积累经验。
通过这次课程设计,我才明白学习是一个长期积累的过程,在以后的工作、生活中都应该不断的学习,努力提高自己知识和综合素质。
特别是对于我,基础比较差,一定不能太过于心急,要静下心来慢慢的学习。
在这次课程设计中也使我们的同学关系更进一步了,同学之间互相帮助,有什么不懂的大家在一起商量,听听不同的看法有助于更好的理解知识,所以在这里感谢帮助我的同学。
以前对C语言也是仅局限在课程中的简单了解,但是通过此次的课程设计,让我了解了解到C++语言的功能的强大以及在Visual C++下进行可视化编程,同时让我对windows下编程有了进一步的了解。
虽然这个设计做得不算很成功,但是在设计过程中所学到的东西使我终身受益。
六附录:
程序代码:
//0907Dlg.cpp:
实现文件
#include"stdafx.h"
#include"0907.h"
#include"0907Dlg.h"
#include"afxdialogex.h"
#include"math.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#endif
/用于应用程序“关于”菜单项的CAboutDlg对话框
classCAboutDlg:
publicCDialogEx
{
public:
CAboutDlg()。
//对话框数据
enum{IDD=IDD_ABOUTBOX}。
protected:
virtualvoidDoDataExchange(CDataExchange*pDX)。
//DDX/DDV支持
//实现
protected:
DECLARE_MESSAGE_MAP()
}。
CAboutDlg:
:
CAboutDlg():
CDialogEx(CAboutDlg:
:
IDD)
{
}
voidCAboutDlg:
:
DoDataExchange(CDataExchange*pDX)
{CDialogEx:
:
DoDataExchange(pDX)。
}
BEGIN_MESSAGE_MAP(CAboutDlg,CDialogEx)
END_MESSAGE_MAP()
//CMy0907Dlg对话框
CMy0907Dlg:
:
CMy0907Dlg(CWnd*pParent/*=NULL*/)
:
CDialogEx(CMy0907Dlg:
:
IDD,pParent)
m_Xstart(0)
m_Yend(0)
m_Start(0)
m_End(0)
i(0)
m_dtemp(0)
{
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME)。
}
voidCMy0907Dlg:
:
DoDataExchange(CDataExchange*pDX)
{
CDialogEx:
:
DoDataExchange(pDX)。
DDX_Text(pDX,IDC_X_EDIT,m_Xstart)。
DDX_Text(pDX,IDC_Y_EDIT,m_Yend)。
DDX_Text(pDX,IDC_dTemp_EDIT,m_dtemp)。
}
BEGIN_MESSAGE_MAP(CMy0907Dlg,CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(MM_WIM_OPEN,OnMM_WIM_OPEN)//自定义消息映射宏
ON_MESSAGE(MM_WIM_DATA,OnMM_WIM_DATA)
ON_MESSAGE(MM_WIM_CLOSE,OnMM_WIM_CLOSE)
ON_MESSAGE(MM_WOM_OPEN,OnMM_WOM_OPEN)
ON_MESSAGE(MM_WOM_DONE,OnMM_WOM_DONE)
ON_MESSAGE(MM_WOM_CLOSE,OnMM_WOM_CLOSE)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_REC_START,&CMy0907Dlg:
:
OnBnClickedRecStart)
ON_BN_CLICKED(IDC_REC_STOP,&CMy0907Dlg:
:
OnBnClickedRecStop)
ON_BN_CLICKED(IDC_PLAY_START,&CMy0907Dlg:
:
OnBnClickedPlayStart)
ON_BN_CLICKED(IDC_PLAY_STOP,&CMy0907Dlg:
:
OnBnClickedPlayStop)
ON_BN_CLICKED(IDC_XIANSHI_BUTTON,&CMy0907Dlg:
:
OnBnClickedXianshiButton)
ON_BN_CLICKED(IDC_FFT,&CMy0907Dlg:
:
OnBnClickedFft)
ON_BN_CLICKED(IDC_TU_STATIC,&CMy0907Dlg:
:
OnBnClickedTuStatic)
END_MESSAGE_MAP()
//CMy0907Dlg消息处理程序
BOOLCMy0907Dlg:
:
OnInitDialog()
{
CDialogEx:
:
OnInitDialog()。
//将“关于...”菜单项添加到系统菜单中。
//IDM_ABOUTBOX必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX)。
ASSERT(IDM_ABOUTBOX<0xF000)。
CMenu*pSysMenu=GetSystemMenu(FALSE)。
if(pSysMenu!
=NULL)
{
BOOLbNameValid。
CStringstrAboutMenu。
bNameValid=strAboutMenu.LoadString(IDS_ABOUTBOX)。
ASSERT(bNameValid)。
if(!
strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR)。
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu)。
}
}
//设置此对话框的图标。
当应用程序主窗口不是对话框时,框架将自动
//执行此操作
SetIcon(m_hIcon,TRUE)。
//设置大图标
SetIcon(m_hIcon,FALSE)。
//设置小图标
//TODO:
在此添加额外的初始化代码
pWaveHdr1=reinterpret_cast(malloc(sizeof(WAVEHDR)))。
//数据缓存的结构体指针
pWaveHdr2=reinterpret_cast(malloc(sizeof(WAVEHDR)))。
//allocatememoryforsavebuffer
pSaveBuffer=reinterpret_cast(malloc
(1))。
returnTRUE。
//除非将焦点设置到控件,否则返回TRUE
}
voidCMy0907Dlg:
:
OnSysCommand(UINTnID,LPARAMlParam)
{
if((nID&0xFFF0)==IDM_ABOUTBOX)
{
CAboutDlgdlgAbout。
dlgAbout.DoModal()。
}
else
{
CDialogEx:
:
OnSysCommand(nID,lParam)。
}
}
//如果向对话框添加最小化按钮,则需要下面的代码
//来绘制该图标。
对于使用文档/视图模型的MFC应用程序,
//这将由框架自动完成。
voidCMy0907Dlg:
:
OnPaint()
{
if(IsIconic())
{
CPaintDCdc(this)。
//用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND,reinterpret_cast(dc.GetSafeHdc()),0)。
//使图标在工作区矩形中居中
intcxIcon=GetSystemMetrics(SM_CXICON)。
intcyIcon=GetSystemMetrics(SM_CYICON)。
CRectrect。
GetClientRect(&rect)。
intx=(rect.Width()-cxIcon+1)/2。
inty=(rect.Height()-cyIcon+1)/2。
//绘制图标
dc.DrawIcon(x,y,m_hIcon)。
}
else
{
CDialogEx:
:
OnPaint()。
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSORCMy0907Dlg:
:
OnQueryDragIcon()
{
returnstatic_cast(m_hIcon)。
}
voidCMy0907Dlg:
:
OnBnClickedRecStart()
{
//TODO:
在此添加控件通知处理程序代码
pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE)。
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE)。
if(!
pBuffer1||!
pBuffer2){
if(pBuffer1)free(pBuffer1)。
if(pBuffer2)free(pBuffer2)。
MessageBeep(MB_ICONEXCLAMATION)。
//