WinCe6.0 播放语音问题

记录:
问题:
WinCE 中怎样实现播放一段wav 或wma或MP3格式的语音呢 具体函数是什么啊 我用PlaySound(TEXT("\\sounds\\bell.wav"),NULL,SND_SYNC|SND_NODEFAULT);怎么实现不了啊 我把\\sounds\\bell.wav直接放到工程文件夹的根目录下了
我把SND_NODEFAULT去掉之后  只播放一声“嘀”的声音  估计那是系统的声音吧
也可以用sndPlaySound()   也有同样的问题    这是什么原因呢
回答:
如果可以播放Default的系统声,应该就是用SND_FILENAME,或者TEXT(http://www.cnblogs.com/buffer/admin/file:////sounds//bell.wav)路径不对.
 
 
 

一.播放声音文件的简单方法
  在VC++ 中的多媒体动态连接库中提供了一组与音频设备有关的函数。利用这些函数可以方便地播放声音。最简单的播放声音方法就是直接调用VC++中提供的声音播放函数BOOL sndPlaySound ( LPCSTR lpszSound,UINT fuSound ); 或BOOL PlaySound( LPCSTR lpszSound, HMODULE hmod, DWORD fuSound );其中参数lpszSound是需要播放声音的.WAV文件的路径和文件名, hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC++中的帮助。 例如播放C:\sound\music.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. 周敬利 《多媒体声卡技术及应用》 电子工业出版社 1998


 1,高级音频函数.
MessageBeep,PlaySound和sndPlaySound.这三个函数你应该熟悉,我不想在这说
太多.因为我感觉很简单的,你查一下msdn就会了.要注意一下他们需要什么样的头文件,
参数都是做什么用,还有限于什么样的文件格式.比如它们都不能播放大于100k的波形声
音文件.
写个例子你应该清晰一些:
PlaySound("关机.wav", NULL, SND_ASYNC|SND_LOOP);
//第一个参数是声音文件名,最后的那个SND_LOOP是循环播放的意思.
我感觉要实现同时播放两个音乐好似只用这几个函数是不可能实现的.不管你用不用线程控
制,用了一次那么它就把那个设备的接口给占住了,用第二次要么把那个接口给抢走了第一
次的不能用了,要么抢不走,苦苦等你不想用了再拾过来.
2.MCI
什么是MCI
MCI(Media Control Interface)媒体控制接口是MircroSoft提供的一组多媒体设
备和文件的标准接口,它的好处是可以方便地控制绝大多数多媒体设备包括音频,视频,影
碟,录像等多媒体设备,而不需要知道它们的内部工作状况.但是古人云:成也萧何,败也
萧何.MCI虽然看上去高大全,但对于一些高级应用来说,它是远远不够的.
上面的话也不是我说的,但低级中级应用是完全凑合的.
MCI向Windows程序提供了在高层次上控制媒体设备接口的能力.程序不必关心具体设备,
就可以对激光唱机(CD),视盘机,波形音频设备,视频播放设备和MIDI设备等媒体设备
进行控制.对于程序员来说,可以把MCI理解为设备面板上的一排按键,通过选择不同的
按键(发送不同的MCI命令)可以让设备完成各种功能,而不必关心设备内部实现.比如,
对于play,视盘机和CD机有不同的反应(一个是播放视频,一个播放音频),而对用户来
说却只需要按同一按钮.
VC下音频文件的播放
Playing audio file with visual c++ 3
MCI的使用方法
应用程序通过向MCI发送命令来控制媒体设备.MCI命令接口分命令字符串和命令消息两
种,两者具有相同的功能.命令字符串具有使用简单的特点,但是它的执行效率不如命令消
息.(mciSendString,字符串消息. mciSendCommand,命令消息)
1.先说mciSendString.
表面上就是发送字符串的意思,就是要告诉某些设备,请你播放!,注意下面参数的第一个
都是用双引号弄起来的,只是引号里写的有固定的格式罢了.
先写个简单的例子,使你不至于一头雾水.
mciSendString("open 老鼠爱大米.avi type 设备1 ",…);
mciSendString("play 设备1 repeat",…);
上面这个例子是我胡乱写的,你应该一下子有些感觉到头上是蓝天了吧,大约看得懂什么意
思吧,那repeat什么意思啊知道吧.就是说你特别喜欢那首歌,听完一次还要听.
还是说一下吧吧.第一句话先发送个命令,把那个老鼠爱大米放进设备里,然后第二句再发
送个命令设备开始给我运转!
所有的MCI命令字符串都是通过多媒体API函数mciSendString传递给MCI的,该函
数的声明为:
MCIERROR mciSendString( //MCIERROR 只是一个返回类型,你别害怕啊.
//命令字符(刚才……前面的:"open 老鼠爱大米.avi type 设备1 ")
LPCTSTR lpszCommand,
LPTSTR lpszReturnString, //存放反馈信息的缓冲区
UINT cchReturn, //缓冲区的长度
HANDLE hwndCallback //回调窗口的句柄,一般为NULL
); //若成功则返回0,否则返回错误码.
//下面这些你瞄一眼就好了,关于错误处理的,你写程序时不用也没事.用的话抄一下就
好了.
该函数返回的错误码可以用mciGetErrorString函数进行分析,该函数的声明为:
BOOL mciGetErrorString(
DWORD fdwError, //函数mciSendString或mciSendCommand返回的错误码
LPTSTR lpszErrorText, //接收描述错误的字符串的缓冲区
VC下音频文件的播放
Playing audio file with visual c++ 4
UINT cchErrorText //缓冲区的长度
);
//下面你只看看红色的部分就好了,其它瞄一眼.
下面是使用mciSendString函数的一个简单例子:
char buf[50];
MCIERROR mciError;
mciError=mciSendString("open cdaudio",buf,strlen(buf),NULL);
if(mciError)
{
mciGetErrorString(mciError,buf,strlen(buf));
AfxMessageBox(buf);
return;
}
mciSendString("open 老鼠爱大米.avi type 设备1 ",…);
mciSendString("play 设备1 repeat",…);
这样你就可以听老鼠爱大米了,但是如果我还想听 [大米爱老鼠]这首歌,我就想两个歌一
起播放, 那我就在前面加一句mciSendString("open大米爱老鼠.avi type 设备1
",…);可以不
这是不可以的.
在这种情况下,需要为每次打开的设备起一个不同的别名,这样MCI才能区分两个播放设
备.
例如,下面这段代码打开并播放了两个AVI文件:(Alias是别名的意思.)
char buf[50];
mciSendString("open老鼠爱大米.avi type avivideo alias adu",buf,strlen
(buf),NULL);
mciSendString("play adu repeat",buf,strlen(buf),NULL); //重复播放
mciSendString("open大米爱老鼠.avi type avivideo alias
guanghao",buf,strlen
(buf),NULL);
mciSendString("play guanghao ",buf,strlen(buf),NULL);
把上面这些写成红色因为这样就实现了背景音乐和普通音乐的同时播放.
2. mciSendCommand
关于这个我就不用多说什么了.写个例子:
下面基本上都是固定的格式,比如要打开并播放一个.wav文件,只要把下面蓝色的两部分
VC下音频文件的播放
Playing audio file with visual c++ 5
换为
waveaudio 和 Windows XP 关机.wav 可以了.
MCI_DGV_OPEN_PARMS mciOpen;
UINT wDeviceID;
MCIERROR mciError;
mciOpen.lpstrDeviceType = "avivideo"; //设备名
mciOpen.lpstrElementName = "老鼠.avi"; //设备元素
mciError=mciSendCommand(0, MCI_OPEN,
MCI_OPEN_TYPE|MCI_OPEN_ELEMENT, //使用了设备元素
(DWORD)&mciOpen);
wDeviceID=mciOpen.wDeviceID; //保存设备ID
MCI_DGV_PLAY_PARMS mciPlay;
mciError=mciSendCommand(wDeviceID, MCI_PLAY, MCI_DGV_PLAY_REPEAT,
(DWORD)&mciPlay);
写这些程序时要包含许多的头文件.我也没有归纳过什么.比如
#include ;
#include
#include
#pragma comment(lib,"vfw32.lib")
#pragma comment(lib,"Winmm.lib")
我用的时候就是让程序不报错,最先全注释掉,然后露一行,如果报错了,看看用到了哪个
函数,然后查MSDN再把需要它的头文件放进去.
还有,就是感觉很多网上强人播放声音文件都用了下面的方法,MCIWndCreate和
MCIWndPlay.当然也都是用MCI类的.这个可真是方便又简单啊.呵呵.
如:
HWND m_hwndMCI;
if(m_hwndMCI!=NULL) //建立一个MCIWND窗口
{
MCIWndDestroy(m_hwndMCI);
}
int type=2; //隐藏默认工具栏 0表显示
CString filename="星空无限.mp3"; //要播放的文件文件名
m_hwndMCI=MCIWndCreate(m_hWnd,AfxGetInstanceHandle(),type,filenam
e);
MCIWndPlay(m_hwndMCI);
在stdafx.h中加入:
#include
#pragma comment(lib,"vfw32.lib")
更多控制函数请自己打开vfw.h文件查看
VC下音频文件的播放
Playing audio file with visual c++ 6
如:
MCIWndGetPosition(m_hwndMCI) 得到当前播放位置,用于控制播放进度滑块
MCIWndGetLength(m_hwndMCI) 文件播放长度
MCIWndSetVolume(m_hwndMCI,iVol) 设置音量,大小为iVol,最大为1000
MCIWndGetVolume(m_hwndMCI) 得到当前音量值
MCIWndPlayFromTo(m_hwndMCI, lStart, lEnd) 播放片段
展开阅读全文

没有更多推荐了,返回首页