实验2 波形音频播放器.docx

上传人:b****8 文档编号:30138265 上传时间:2023-08-05 格式:DOCX 页数:23 大小:140.33KB
下载 相关 举报
实验2 波形音频播放器.docx_第1页
第1页 / 共23页
实验2 波形音频播放器.docx_第2页
第2页 / 共23页
实验2 波形音频播放器.docx_第3页
第3页 / 共23页
实验2 波形音频播放器.docx_第4页
第4页 / 共23页
实验2 波形音频播放器.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

实验2 波形音频播放器.docx

《实验2 波形音频播放器.docx》由会员分享,可在线阅读,更多相关《实验2 波形音频播放器.docx(23页珍藏版)》请在冰豆网上搜索。

实验2 波形音频播放器.docx

实验2波形音频播放器

实验2波形音频播放器

实验目的

1.了解Wave文件格式,并学习Windows下用MCI函数播放Wave文件。

2.熟悉多媒体开发工具——VisualC++。

3.制作波形音频播放器。

其运行界面如下图所示:

要求此播放器具有打开、播放、录制及保存波形音频文件的功能。

预备知识

1.VC6编程方法,MCI编程方法。

2.Wave文件的结构

用.wav为扩展名的文件格式称为波形文件格式(WAVEFileFormat),它是一种资源交换文件格式(ResourceInterchangeFileFormat,RIFF),RIFF格式是面向部分(chunk)的,一个RIFF文件是由一个或多个部分组成的,其中每一个部分都指向下一个部分。

下图是一个RIFF文件结构的示意:

波形文件格式支持存储各种采样频率和样本精度的声音数据,并支持声音数据的压缩。

一个WAVE文件至少包含三个块RIFF块是其中最大的,整个WAVE文件就是一个RIFF块。

Cksize紧跟在“RIFF”CKID之后出现,它包含一个值,等于文件的大小减去8个字节,这8个字节用来存储RIFF的CKID和CKSIZE。

第二和第三块称为子块,包含在RIFF块之中。

这些块的第一个块是“fmt”块,包含PCMWAVEFORMAT结构所需要的信息;第二个块“data”块紧跟在“fmt”之后,包含所有的数据波形。

RIFF的CKSIZE等于“fmt”块和“data”块所占用的字节之和。

为了读写RIFF文件,用户使用为多媒体块信息准备的叫MMCKINFO的标准的数据结构。

在VC中这个结构定义为:

typedefsruct{

FOURCCckid;

DWORDcksize;

FOURCCfccType;

DWORDdwDataOffset;

DWORDdwFlags;

}MMCKINFO;

设计多媒体程序,关键是对多种多媒体设备的控制和使用,在Windows操作系统中,对多媒体设备进行控制主要有三种方法:

第一种方法是使用微软公司窗口系统中对多媒体支持的MCI,即媒体控制接口,MCI是多媒体设备和多媒体应用软件之间进行设备无关的沟通的桥梁。

在VB和VC中MCI都得到了很好的支持;第二种方法,通过调用Windows的API(应用程序接口)多媒体相关函数实现媒体控制;第三种方法是使用OLE(ObjectLinking&Embedding),即对象嵌入和链接技术,它为不同数据之间共享数据和资源提供了有利的手段。

实验步骤:

1.用VC建立应用程序框架:

a)打开文件菜单,点击新建,在弹出的对话框中选中MFCAppWizard(exe)后,选好你文件所需存储的目录,然后在工程中填入工程文件名,如下图所示:

点击确定按钮在弹出的对话框中,按下图进行设置后,点击“完成”。

b)编制应用程序界面:

各控件的属性如下表所示:

控件

ID

标题

控件

ID

标题

GroupBox

IDC_STATIC

波形音频信息

Static

IDC_RESOLUTION

Static

IDC_STATIC

波形文件:

Static

IDC_WAVE_LENGTH

Static

IDC_STATIC

声道:

Button

IDC_OPEN

打开

Static

IDC_STATIC

采样率:

Button

IDC_PLAY

播放

Static

IDC_STATIC

音频长度:

Button

IDC_RECORD

录制

Static

IDC_WAVE_NAME

Button

IDC_SAVE

保存

Static

IDC_CHANNEL

Button

IDC_STOP

停止

Static

IDC_SAMPLE_RATE

Picture

IDC_WAVE_GRAPH

c)点击查看建立类向导,在MessageMaps中建立相应的消息函数OnOpen(),OnPlay(),OnRecord(),OnSave(),OnStop(),点击确定。

-

2.建立处理波形音频的类CWaveAudio:

工程添加工程ComponentsandControls,选中WaveAudio.ogx文件插入,可重用类CWaveAudio便添加到工程中。

在CWavePlayerDlg类的头文件中将CWaveAudio的头文件包含进来。

3.加入所需的功能:

a)在CWavePlayerDlg类中加入以下成员变量

CStringpath;//文件目录

CWaveAudiom_Wave;//可重用类的对象

intINFO_WAVEWIDE;//绘图框的宽度

intINFO_WAVEDEEP;//绘图框的高度

boolm_bOpen;//判断是否有波形音频文件打开

右键点击Class中的CWavePlayerDlg,选中AddNumberFunction,如下所示,将绘图函数

voidDrawWave(HDChdc,unsignedintx,unsignedinty,char*path)加到CWavePlayerDlg中。

b)在BOOLCWavePlayerDlg:

:

OnInitDialog()中进行初始化:

CWnd*m_pWnd;

m_pWnd=GetDlgItem(IDC_PLAY);

m_pWnd->EnableWindow(false);

m_pWnd=GetDlgItem(IDC_SAVE);

m_pWnd->EnableWindow(false);

c)在OnOpen(),OnPlay(),OnRecord(),OnSave(),OnStop()中添加代码如下:

voidCWavePlayerDlg:

:

OnOpen()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

CStringFilter,str;

Filter="波形音频文件(*.WAV)|*.WAV||";

CFileDialogFileDlg(true,NULL,NULL,OFN_HIDEREADONLY,Filter);

if(FileDlg.DoModal()==IDOK)

{

if(!

m_Wave.Load(FileDlg.GetFileName()))

{

MessageBox("不能打开文件!

","错误",MB_OK|MB_ICONSTOP);

}

CWnd*m_pWnd;

m_pWnd=GetDlgItem(IDC_PLAY);

m_pWnd->EnableWindow(true);

}

path=FileDlg.GetPathName();

SetDlgItemText(IDC_WAVE_NAME,FileDlg.GetFileName());

str.Format("%5.3f",m_Wave.GetSampleRate()/1000);

str+=_T("kHZ");

SetDlgItemText(IDC_SAMPLE_RATE,str);

str.Empty();

switch(m_Wave.GetChannel())

{

case1:

str="单声道";

break;

case2:

str="立体声";

break;

}

SetDlgItemText(IDC_CHANNEL,str);

str.Empty();

str.Format("%d",m_Wave.GetResolution());

str+="位";

SetDlgItemText(IDC_RESOLUTION,str);

str.Empty();

str.Format("%2.2u:

%02.2f:

%02.2u",m_Wave.GetWaveLength()/1000/60,

m_Wave.GetWaveLength()/1000,m_Wave.GetWaveLength()/1000/3600);

SetDlgItemText(IDC_WAVE_LENGTH,str);

m_bOpen=true;

}

voidCWavePlayerDlg:

:

OnPlay()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

m_Wave.Play();

}

voidCWavePlayerDlg:

:

OnRecord()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

CWnd*m_pWnd;

m_pWnd=GetDlgItem(IDC_PLAY);

m_pWnd->EnableWindow(false);

m_pWnd=GetDlgItem(IDC_OPEN);

m_pWnd->EnableWindow(false);

m_pWnd=GetDlgItem(IDC_SAVE);

m_pWnd->EnableWindow(false);

m_Wave.Record();

}

voidCWavePlayerDlg:

:

OnSave()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

CStringFilter;

Filter="WaveFile(*.WAV)|*.WAV||";

CFileDialogFileDlg(false,NULL,NULL,OFN_OVERWRITEPROMPT,Filter);

FileDlg.m_ofn.lpstrDefExt="wav";

if(FileDlg.DoModal()==IDOK)

m_Wave.Save(FileDlg.GetPathName());

}

voidCWavePlayerDlg:

:

OnStop()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

CWnd*m_pWnd;

m_pWnd=GetDlgItem(IDC_PLAY);

m_pWnd->EnableWindow(true);

m_pWnd=GetDlgItem(IDC_OPEN);

m_pWnd->EnableWindow(true);

m_pWnd=GetDlgItem(IDC_SAVE);

m_pWnd->EnableWindow(true);

m_Wave.Stop();

}

现在可以编译运行一下,可以发现你已经实现了绝大多数的功能。

d)现在,我们将绘图功能添加进去,由于对话框的变动都会触发调用OnPaint()函数重绘客户区,我们在OnPaint()中加入以下代码:

voidCWavePlayerDlg:

:

OnPaint()

{

if(IsIconic())

{

……

}

else

{

CDialog:

:

OnPaint();

if(m_bOpen)

{

CWnd*m_pWnd;

CRectrect;

m_pWnd=GetDlgItem(IDC_WAVE_GRAPH);

m_pWnd->GetClientRect(rect);

INFO_WAVEWIDE=rect.Width();

INFO_WAVEDEEP=rect.Height();

CClientDCdc(m_pWnd);

DrawWave(dc.m_hDC,rect.left,rect.top,(char*)path.operatorLPCTSTR());

}

}

}

我们就在OnPaint()中调用了DrawWave函数绘制波形,DrawWave函数的代码如下:

voidCWavePlayerDlg:

:

DrawWave(HDChdc,unsignedintx,unsignedinty,char*path)

{

HMMIOh;

MMCKINFOmmParent,mmSub;//MMCKINFO结构中包含了有关部分的信息

GLOBALHANDLEgh;

PCMWAVEFORMATwaveformat;//fmt部分结构

char*p;

unsignedlongnextsample;

longafactor;

unsignedinti,n,amp;

int*ip;

HPENOldPen=(HPEN)SelectObject(hdc,GetStockObject(BLACK_PEN));

HBRUSHOldBrush=(HBRUSH)SelectObject(hdc,GetStockObject(WHITE_BRUSH));

Rectangle(hdc,x,y,x+INFO_WAVEWIDE,y+INFO_WAVEDEEP);

if((h=mmioOpen(path,NULL,MMIO_READ))==NULL)

return;

mmParent.fccType=mmioFOURCC('W','A','V','E');

if(mmioDescend(h,(LPMMCKINFO)&mmParent,NULL,MMIO_FINDRIFF))

{

mmioClose(h,0);

return;

}

mmSub.ckid=mmioFOURCC('f','m','t','');

if(mmioDescend(h,(LPMMCKINFO)&mmSub,(LPMMCKINFO)&mmParent,MMIO_FINDCHUNK))

{

mmioClose(h,0);

return;

}

n=min((unsignedint)mmSub.cksize,sizeof(PCMWAVEFORMAT));

if(mmioRead(h,(LPSTR)&waveformat,n)!

=(int)n)

{

mmioClose(h,0);

return;

}

if(waveformat.wf.wFormatTag!

=WAVE_FORMAT_PCM)

{

mmioClose(h,0);

return;

}

mmioAscend(h,&mmSub,0);//当读出一个部分的数据后,退出该部分

mmSub.ckid=mmioFOURCC('d','a','t','a');

if(mmioDescend(h,(LPMMCKINFO)&mmSub,(LPMMCKINFO)&mmParent,MMIO_FINDCHUNK))

{

mmioClose(h,0);

return;

}

if(waveformat.wBitsPerSample==8&&waveformat.wf.nChannels==1)

{

nextsample=mmSub.cksize/(long)INFO_WAVEWIDE;

afactor=2L*(255L/(long)INFO_WAVEDEEP);

}

elseif(waveformat.wBitsPerSample==8&&waveformat.wf.nChannels==2)

{

nextsample=2L*((mmSub.cksize/2L)/(long)INFO_WAVEWIDE);

afactor=2L*(255L/(long)INFO_WAVEDEEP);

}

elseif(waveformat.wBitsPerSample>8&&waveformat.wf.nChannels==1)

{

nextsample=2L*((mmSub.cksize/(long)INFO_WAVEWIDE))&0xfffffffeL;

afactor=2L*(65535L/(long)INFO_WAVEDEEP);

}

else

{

nextsample=4L*((mmSub.cksize/4L)/(long)INFO_WAVEWIDE)&0xfffffffeL;

afactor=2L*(65535L/(long)INFO_WAVEDEEP);

}

MoveToEx(hdc,x,y+INFO_WAVEDEEP/2,NULL);

LineTo(hdc,x+INFO_WAVEWIDE,y+INFO_WAVEDEEP/2);

if((gh=GlobalAlloc(GMEM_MOVEABLE,mmSub.cksize))!

=NULL)

{

if((p=(char*)GlobalLock(gh))!

=NULL)

{

if(mmioRead(h,p,mmSub.cksize)==mmSub.cksize)

{

for(i=0;i

{

ip=(int*)p;

if(waveformat.wBitsPerSample==8&&waveformat.wf.nChannels==1)

amp=(unsignedint)max(labs(((long)p[0]-128L)/afactor),1L);

elseif(waveformat.wBitsPerSample==8&&waveformat.wf.nChannels==2)

amp=(unsignedint)max(labs(((long)p[0]-128L+(long)p[1]-128L)/2)/afactor,1L);

elseif(waveformat.wBitsPerSample>8&&waveformat.wf.nChannels==1)

amp=(unsignedint)max(labs((long)ip[0]/afactor),1L);

else

amp=(unsignedint)max(labs((((long)ip[0]+(long)ip[1])/2)/afactor),1L);

if(amp>(unsignedint)INFO_WAVEDEEP/2)

amp=INFO_WAVEDEEP/2-3;

MoveToEx(hdc,x+i,y+(INFO_WAVEDEEP/2)-amp,NULL);

LineTo(hdc,x+i,y+(INFO_WAVEDEEP/2)+amp);

i+=2;

p+=nextsample;

}

}

GlobalUnlock(gh);

}

GlobalFree(gh);

}

SelectObject(hdc,OldPen);

(HBRUSH)SelectObject(hdc,OldBrush);

mmioClose(h,0);

return;

}

现在编译执行你的程序,就会发现一个简单的波形音频播放器已经完成了。

实验注意事项:

1.调试程序时,Ctrl+F7为Compile,Build为F7,运行时按F5。

2.注意可重用类CwaveAudio的设计。

3.熟练掌握MCI多媒体函数的应用。

4.编译时,菜单选中“项目”“设置”,要在库的链接中加入winmm.lib。

二、预备知识

1.VC6编程方法,MCI编程方法。

2.Wave文件的结构

用.wav为扩展名的文件格式称为波形文件格式(WAVEFileFormat),它是一种资源交换文件格式(ResourceInterchangeFileFormat,RIFF),RIFF格式是面向部分(chunk)的,一个RIFF文件是由一个或多个部分组成的,其中每一个部分都指向下一个部分。

下图是一个RIFF文件结构的示意:

波形文件格式支持存储各种采样频率和样本精度的声音数据,并支持声音数据的压缩。

一个WAVE文件至少包含三个块RIFF块是其中                          最大的,整个WAVE文件就是一个RIFF块。

Cksize紧跟在“RIFF”CKID之后出现,它包含一个值,等于文件的大小减去8个字节,这8个字节用来存储RIFF的CKID和CKSIZE。

第二和第三块称为子块,包含在RIFF块之中。

这些块的第一个块是“fmt”块,包含PCMWAVEFORMAT结构所需要的信息;第二个块“data”块紧跟在“fmt”之后,包含所有的数据波形。

RIFF的CKSIZE等于“fmt”块和“data”块所占用的字节之和。

为了读写RIFF文件,用户使用为多媒体块信息准备的叫MMCKINFO的标准的数据结构。

在VC中这个结构定义为:

typedefsruct{

FOURCCckid;

DWORDcksize;

FOURCCfccType;

DWORDdwDataOffset;

DWORDdwFlags;

}MMCKINFO;

设计多媒体程序,关键是对多种多媒体设备的控制和使用,在Windows操作系统中,对多媒体设备进行控制主要有三种方法:

第一种方法是使用微软公司窗口系统中对多媒体支持的MCI,即媒体控制接口,MCI是多媒体设备和多媒体应用软件之间进行设备无关的沟通的桥梁。

在VB和VC中MCI都得到了很好的支持;第二种方法,通过调用Windows的API(应用程序接口)多媒体相关函数实现媒体控制;第三种方法是使用OLE(ObjectLinking&Embedding),即对象嵌入和链接技术,它为不同数据之间共享数据和资源提供了有利的手段。

三、思考题

1.什么是MCI接口?

简述MCI所囊括的内容。

2.Windows下播放波形文件可采用几种方法?

各有什么有缺点?

3.简述Windows下多媒体程序开发的特点。

 

以下是media.h的程序

#if_MSC_VER>1000

#pragmaonce

#endif//_MSC_VER>1000

#include

#include

#include

#include

classCWaveAudio//处理波形类

{

public:

CWaveAudio();//构造函数

virtual~CWaveAudio();//构析函数

intGetDevices(void);//得到播放设备

BOOLLoad(CString);//载入文件

voidClose(void);//关闭文件

BOOLPlay

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 财务管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1