VC++中播放声音的方法

本文介绍了在VC++中播放声音文件的三种方法:直接调用播放函数、将声音文件作为资源加入程序、使用音频设备及多媒体文件操作函数进行高级播放。涵盖了从基本应用到复杂处理的多种场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声音是多媒体的一个重要组成部分,在应用程序中加入声音可以使界面更友好。在VC++中可以根据不同的应用要求,用不同的方法实现声音的播放。

一.播放声音文件的简单方法
   在VC++ 中的多媒体动态连接库中提供了一组与音频设备有关的函数。利用这些函数可以方便地播放声音。最简单的播放声音方法就是直接调用VC++中提供的声音播放函数BOOL sndPlaySound ( LPCSTR lpszSound,UINT fuSound ); 或BOOL PlaySound( LPCSTR lpszSound, HMODULE hmod, DWORD fuSound );其中参数lpszSound是需要播放声音的.WAV文件的路径和文件名, hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC++中的帮助。 例如播放C:soundmusic.wav可以用sndPlaySound ("c:/sound/music.wav",SND_ASYNC);或PlaySound("c:/sound/music.wav",NULL, SND_ASYNC|SND_NODEFAULT );如果没有找到music.wav文件,第一种格式将播放系统默认的声音,第二种格式不会播放系统默认的声音。

二.将声音文件加入到程序中
   在VC++的程序设计中,可以利用各种标准的资源,如位图,菜单,对话框等。同时VC++也允许用户自定义资源,因此我们可以将声音文件作为用户自定义资源加入程序资源文件中,经过编译连接生成EXE文件,实现无.WAV文件的声音播放。
   要实现作为资源的声音文件的播放,首先要在资源管理器中加入待播放的声音文件(实现过程并不复杂,这里不在叙述)。假设生成的声音文件资源标识符为IDR_WAVE1。在播放时只需要调用下面的语句:
   PlaySound(MAKEINTRESOURCE(IDR_WAVE1),AfxGetResourceHandle(),   SND_ASYNC|SND_RESOURCE|SND_NODEFAULT|SND_LOOP);
   其中MAKEINTRESOURCE()宏将整数资源标识符转变为字符串,AfxGetResourceHandle()函数返回包含资源的模块句柄,
SND_RESOURCE是必须的标志。
   作为资源的声音文件的第二种播放方法是把资源读入内存后作为内存数据播放。具体步骤入下:
   1.获得包含资源的模块句柄:
   HMODULE hmod=AfxGetResourceHandle();
   2.检索资源块信息:
   HRSRC hSndResource=FindResource(hmod,MAKEINTRESOURCE(IDR_WAVE1),_T("WAVE"));
   3. 装载资源数据并加锁:
   HGLOBAL hGlobalMem=LoadResource(hmod,hSndResource);
LPCTSTR lpMemSound=(LPCSTR)LockResource(hGlobalMem);
   4.播放声音文件:
   sndPlaySound(lpMemSound,SND_MEMORY));
   5.释放资源句柄:
   FreeResource(hGlobalMem);

三.播放声音文件的高级方法
   在VC++中提供了一组对音频设备及多媒体文件直接进行操作的函数。利用这些函数可以灵活地对声音文件进行各种处理。
   首先介绍几个要用到的数据结构。WAVEFORMATEX结构定义了WAVE音频数据文件的格式。WAVEHDR结构定义了波形音频缓冲区。读出的数据首先要填充此缓冲区才能送音频设备播放。WAVEOUTCAPS结构描述了音频设备的性能。MMCKINFO结构包含了RIFF文件中一个块的信息。详细的说明请参考VC++中的帮助。
   下面给出程序流程简图及程序源代码清单,在VC++环境下可直接使用:


源程序清单如下:
LPSTR szFileName;//声音文件名
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubChunk;
DWORD dwFmtSize;
HMMIO m_hmmio;//音频文件句柄
DWORD m_WaveLong;
HPSTR lpData;//音频数据
HANDLE m_hData;
HANDLE m_hFormat;
WAVEFORMATEX * lpFormat;
DWORD m_dwDataOffset;
DWORD m_dwDataSize;
WAVEHDR pWaveOutHdr;
WAVEOUTCAPS pwoc;
HWAVEOUT hWaveOut;
//打开波形文件
if(!(m_hmmio=mmioOpen(szFileName,NULL,MMIO_READ|MMIO_ALLOCBUF)))
{
//File open Error
Error("Failed to open the file.");//错误处理函数
return false;
}
//检查打开文件是否是声音文件
mmckinfoParent.fccType =mmioFOURCC('W','A','V','E');
if(mmioDescend(m_hmmio,(LPMMCKINFO)&mmckinfoParent,NULL,MMIO_FINDRIFF))
{
//NOT WAVE FILE AND QUIT
}
//寻找 'fmt' 块
mmckinfoSubChunk.ckid =mmioFOURCC('f','m','t',' ');
if(mmioDescend(m_hmmio,&mmckinfoSubChunk,&mmckinfoParent,MMIO_FINDCHUNK))
{
//Can't find 'fmt' chunk
}
//获得 'fmt '块的大小,申请内存
dwFmtSize=mmckinfoSubChunk.cksize ;
m_hFormat=LocalAlloc(LMEM_MOVEABLE,LOWORD(dwFmtSize));
if(!m_hFormat)
{
//failed alloc memory
}
lpFormat=(WAVEFORMATEX*)LocalLock(m_hFormat);
if(!lpFormat)
{
//failed to lock the memory
}
if((unsigned long)mmioRead(m_hmmio,(HPSTR)lpFormat,dwFmtSize)!=dwFmtSize)
{
//failed to read format chunk
}
//离开 fmt 块
mmioAscend(m_hmmio,&mmckinfoSubChunk,0);
//寻找 'data' 块
mmckinfoSubChunk.ckid=mmioFOURCC('d','a','t','a');
if(mmioDescend(m_hmmio,&mmckinfoSubChunk,&mmckinfoParent,MMIO_FINDCHUNK))
{
//Can't find 'data' chunk
}
//获得 'data'块的大小
m_dwDataSize=mmckinfoSubChunk.cksize ;
m_dwDataOffset =mmckinfoSubChunk.dwDataOffset ;
if(m_dwDataSize==0L)
{
//no data in the 'data' chunk
}
//为音频数据分配内存
lpData=new char[m_dwDataSize];
if(!lpData)
{
//faile
}
if(mmioSeek(m_hmmio,SoundOffset,SEEK_SET)<0)
{
//Failed to read the data chunk

}
m_WaveLong=mmioRead(m_hmmio,lpData,SoundLong);
if(m_WaveLong<0)
{
//Failed to read the data chunk
}
//检查音频设备,返回音频输出设备的性能
if(waveOutGetDeVCaps(WAVE_MAPPER,&pwoc,sizeof(WAVEOUTCAPS))!=0)
{
//Unable to allocate or lock memory
}
//检查音频输出设备是否能播放指定的音频文件
if(waveOutOpen(&hWaveOut,DevsNum,lpFormat,NULL,NULL,CALLBACK_NULL)!=0)
{
//Failed to OPEN the wave out devices
}
//准备待播放的数据
pWaveOutHdr.lpData =(HPSTR)lpData;
pWaveOutHdr.dwBufferLength =m_WaveLong;
pWaveOutHdr.dwFlags =0;
if(waveOutPrepareHeader(hWaveOut,&pWaveOutHdr,sizeof(WAVEHDR))!=0)
{
//Failed to prepare the wave data buffer
}
//播放音频数据文件
if(waveOutWrite(hWaveOut,&pWaveOutHdr,sizeof(WAVEHDR))!=0)
{
//Failed to write the wave data buffer
}
//关闭音频输出设备,释放内存
waveOutReset(hWaveOut);
waveOutClose(hWaveOut);
LocalUnlock(m_hFormat);
LocalFree(m_hFormat);
delete [] lpData;
说明:1)以上使用的音频设备和声音文件操作函数的声明包含在mmsystem.h头文件中,因此在程序中必须用#include "mmsystem.h"语句加入头文件。同时在编译时要加入动态连接导入库winmm.lib,具体实现方法是从Developer Studio的Project菜单中选择Settings,然后在Link选项卡上的Object/Library Modules控制中加入winmm.lib。2)在pWaveOutHdr.lpData中指定不同的数据,可以播放音频数据文件中任意指定位置的声音。3) 以上程序均在VC++6.0中调试通过,在文中省略了对错误及异常情况的处理,在实际应用中必须加入。
四.结论
在VC++中可以根据应用需要采用不同的方法播放声音文件。简单应用可以直接调用声音播放函数。第二种方法可以把声音作为资源加入可执行文件中。如果在播放之前要对声音数据进行处理,可用第三种方法。

参考书目:
1. 美 Paul Perry 陈向群 等译《多媒体开发指南》 清华大学出版社
2. 美 Peter Norton, Rob McGregor 孙凤英 等译《MFC开发Windows95/NT4应用程序》 清华大学出版社 1998
3. 周敬利 《多媒体声卡技术及应用》 电子工业出版社 199

 
Docker 是一个开源的容器化平台,它可以让你更方便地创建、部署和运行应用程序。本文将为您提供 Docker 的基础知识,以及如何在您的计算机上安装和使用 Docker。 1. Docker 的基础概念 Docker 是一个容器化平台,它可以让您更轻松地创建、部署和运行应用程序。容器是一个轻量级的运行环境,它可以在任何操作系统上运行,而无需额外的配置。 Docker 的主要组成部分包括 Docker 镜像、Docker 容器Docker 仓库。 - Docker 镜像:一个 Docker 镜像是一个可执行的软件包,它包含了应用程序的所有代码、运行时环境、库和依赖项。您可以将 Docker 镜像看作是一个打包好的应用程序。 - Docker 容器:一个 Docker 容器是一个可运行的实例,它是由 Docker 镜像创建而来的。每个容器都是独立的运行环境,它可以运行在任何 Docker 主机上。多个 Docker 容器可以运行在同一个主机上,并且它们之间是隔离的。 - Docker 仓库:Docker 仓库是一个存储 Docker 镜像的地方。您可以将 Docker 镜像上传到 Docker 仓库中,也可以从 Docker 仓库中下载 Docker 镜像。 2. Docker安装 在开始使用 Docker 之前,您需要在您的计算机上安装 DockerDocker 可以在不同的操作系统上运行,包括 Linux、Windows 和 macOS。 - Linux:对于 Linux 用户,您可以根据您的发行版选择适当的 Docker 安装方式。例如,在 Ubuntu 上,您可以使用以下命令安装 Docker: ``` $ sudo apt-get update $ sudo apt-get install docker-ce ``` - Windows 和 macOS:对于 Windows 和 macOS 用户,您可以使用 Docker Desktop 进行安装Docker Desktop 是一个带有图形界面的应用程序,可以让您更轻松地管理 Docker。 3. Docker 的使用 一旦您成功地安装Docker,您就可以开始使用它来创建、部署和运行应用程序了。 - 创建 Docker 镜像:您可以使用 Dockerfile 文件来创建 Docker 镜像。Dockerfile 是一个文本文件,其中包含了创建 Docker 镜像所需的所有指令。例如,以下是一个简单的 Dockerfile 文件: ``` FROM ubuntu:latest RUN apt-get update && apt-get install -y nginx CMD ["nginx", "-g", "daemon off;"] ``` 这个 Dockerfile 文件指定了一个基于最新版 Ubuntu 镜像的 Docker 镜像,然后安装了 Nginx 服务器。最后,CMD 指令指定了 Nginx 服务器的启动命令。 - 构建 Docker 镜像:一旦您编写了 Dockerfile 文件,您就可以使用 docker build 命令来构建 Docker 镜像。例如,以下是一个简单的构建命令: ``` $ docker build -t my-nginx . ``` 这个命令将使用当前目录下的 Dockerfile 文件来创建一个名为 my-nginx 的 Docker 镜像。 - 运行 Docker 容器:一旦您有了 Docker 镜像,您就可以使用 docker run 命令来运行 Docker 容器。例如,以下是一个简单的运行命令: ``` $ docker run -d -p 80:80 my-nginx ``` 这个命令将在后台运行一个名为 my-nginx 的 Docker 容器,并将容器的 80 端口映射到主机的 80 端口上。 - 将 Docker 镜像推送到 Docker 仓库:一旦您创建了 Docker 镜像,您可以使用 docker push 命令将其推送到 Docker 仓库中。例如,以下是一个简单的推送命令: ``` $ docker push my-nginx ``` 这个命令将名为 my-nginx 的 Docker 镜像推送到 Docker 仓库中。 这些都是 Docker 的基础知识和用法。如果您想深入了解 Docker,您可以访问 Docker 官方网站,其中包含了更详细的文档和教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值