📄 playsnd.c
字号:
/******************************************************
Copyright(c) 版权所有,1998-2003微逻辑。保留所有权利。
******************************************************/
/*****************************************************
文件说明:播放一个声音源,API部分
版本号:1.0.0
开发时期:2003-04-16
作者:陈建明 Jami chen
修改记录:
******************************************************/
#include <ewindows.h>
#include <emmsys.h>
/*
#define SND_SYNC 0x00000000 // 同步播放
#define SND_ASYNC 0x00000001 // 异步播放
#define SND_NODEFAULT 0x00000002 // 如果没有找到声音源,则不播放默认声音
#define SND_MEMORY 0x00000004 // 声音源指向一个内存文件
#define SND_LOOP 0x00000008 // 循环播放直到下一个声音播放
#define SND_NOSTOP 0x00000010 // 不停止当前正在播放的声音
*/
typedef struct {
char id[4]; // 标志串 = "RIFF"
DWORD len; // 在这个头以后的长度
}RIFFHEADER, *PRIFFHEADER;
typedef struct {
char id[4]; // 标志 = "WAVE"
}WAVEID,*PWAVEID;
typedef struct {
WORD wFormatTag; // 格式类型, 目前支持WAVE_FORMAT_PCM
WORD wChannels; // 声音通道数目
DWORD dwSamplesPerSec; // 样本速率
DWORD dwAvgBytesPerSec; // 平均每秒数据数目
WORD wBlockAlign; // 数据块尺寸
}COMMON_FIELD, *PCOMMON_FIELD;
typedef struct {
WORD wBitsPerSample; // 样本大小,一般为 8 bit 或者 16 bit
}PCM_FORMAT_SPECIFIC, *PPCM_FORMAT_SPECIFIC;
typedef struct {
char id[4]; // 标志串 = "fmt " 或 "data"
DWORD len; // 在这个头以后的剩下的Chunk Header长度
COMMON_FIELD common_field; // 通用格式
PCM_FORMAT_SPECIFIC PCM_format_specific; // PCM 附加格式
}CHUNKHEADER, *PCHUNKHEADER;
typedef struct {
char id[4]; // 标志串 = "RIFF"
DWORD len; // 在这个头以后的长度
}DATAHEADER, *PDATAHEADER;
#define MAX_BUFFERNUM 4
#define MAX_BUFFERLENGTH (1024 * 4)
static HANDLE hFile = INVALID_HANDLE_VALUE;
static WAVEHDR wh[MAX_BUFFERNUM];
//static WORD nWaveRate=44100;
//static WORD nWaveChannel=2;
//static WORD nWaveBit=16;
static RIFFHEADER g_stRiffHeader;
static WAVEID g_stWaveID;
static CHUNKHEADER g_stChunkHeader;
static DATAHEADER g_stDataHeader;
static DWORD g_dwReadLen = 0;
static UINT g_fuSound = 0;
static HANDLE g_hThread = NULL;
static HWAVEOUT hwo = 0;
static BOOL bPlaying = FALSE;
static BOOL bStoping = FALSE;
static BOOL bStoped = TRUE;
static UINT uPlayingNum = 0;
static HANDLE hPlayOverEvent = NULL;
static BOOL GetSoundInfo(void );
void CALLBACK AudioProc( HWAVEOUT hwi,UINT uMsg, DWORD dwInstance,DWORD dwParam1);//, DWORD dwParam2 );
static void AddBuffer(LPWAVEHDR lpwh);
static BOOL FillBuffer(LPWAVEHDR lpwh);
static BOOL GetRiffHeader(PRIFFHEADER pRiffHeader);
static BOOL GetWaveID(PWAVEID pWaveID);
static BOOL GetChunkHeader(PCHUNKHEADER pChunkHeader);
static BOOL GetDataHeader(PDATAHEADER pDataHeader);
static BOOL OpenWav(void);
static DWORD WINAPI Audio_ASyncProc(VOID *pParam);
static void ShowErrorCode(MMRESULT result);
/*
#define SND_SYNC 0x00000000 // 同步播放
#define SND_ASYNC 0x00000001 // 异步播放
#define SND_NODEFAULT 0x00000002 // 如果没有找到声音源,则不播放默认声音
#define SND_MEMORY 0x00000004 // 声音源指向一个内存文件
#define SND_LOOP 0x00000008 // 循环播放直到下一个声音播放
#define SND_NOSTOP 0x00000010 // 不停止当前正在播放的声音
#define SND_NOWAIT 0x00002000 // 如果系统忙,则不等待
*/
// **************************************************
// 声明:BOOL WINAPI sndPlaySound( LPCTSTR lpszSoundName, UINT fuSound )
// 参数:
// IN lpszSoundName -- 要播放的声音源
// IN fuSound -- 播放O标志
//
// 返回值:成功返回TRUE,否则返回FALSE
// 功能描述:播放一个声音文件。
// 引用:
// **************************************************
BOOL WINAPI sndPlaySound( LPCTSTR lpszSoundName, UINT fuSound )
{
int i;
DWORD nFileLength = 0;
#ifdef EML_WIN32
return TRUE;
#endif
// RETAILMSG(1,("***sndPlaySound +++ %d\r\n",bPlaying));
// RETAILMSG(1,("***bPlaying %d\r\n",bPlaying));
g_fuSound = fuSound; // 得到播放标志
if (bPlaying == TRUE)
{ // 当前正在播放
// RETAILMSG(1,("The wave playing %x +++\r\n",fuSound));
if (fuSound & SND_NOSTOP)
{ // 不要停止以前的播放
// RETAILMSG(1,("sndPlaySound Busy\r\n"));
return TRUE;
}
/*
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
*/
bStoping = TRUE; // 停止以前的播放
// waveOutReset(hwo);
// if (lpszSoundName == NULL)
// return TRUE;
// waveOutClose(hwo);
while(bStoped == FALSE)
{ // 等待完成
Sleep(100);
}
}
if (g_hThread)
{ // 关闭线程
// RETAILMSG(1,("Close Old Thread\r\n"));
CloseHandle(g_hThread);
g_hThread = NULL;
}
if (lpszSoundName == NULL)
{ // 没有声音要播放
RETAILMSG(1,("sndPlaySound No Name\r\n"));
return TRUE;
}
g_dwReadLen = 0;
// RETAILMSG(1,("Will Play a test Sound \r\n"));
// 打开要播放的文件
hFile = CreateFile(lpszSoundName, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, 0);
if (hFile == INVALID_HANDLE_VALUE)
{ // 打开文件失败
DWORD dwError = GetLastError();
RETAILMSG(1,("Open <%s> failure %d\r\n",lpszSoundName,dwError));
if (fuSound & SND_NODEFAULT)
return TRUE; // 不播放默认声音
// 播放默认声音,目前没有设置默认声音
return TRUE;
}
// RETAILMSG(1,(("hFile = %X\r\n"),hFile));
// RETAILMSG(1,("Open Test audio file OK\r\n"));
if (GetSoundInfo() == FALSE)
{ // 得到声音信息
CloseHandle(hFile);
return FALSE;
}
if (OpenWav() == FALSE)
{ // 打开声音设备
RETAILMSG(1,("*********************************************Open Wav Failure\r\n"));
CloseHandle(hFile);
return FALSE;
}
// RETAILMSG(1,("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Open Wav OK\r\n"));
for (i = 0; i < MAX_BUFFERNUM; i++)
{ // 填充数据
if (FillBuffer(&wh[i])== FALSE)
break;
AddBuffer(&wh[i]); // 播放已经填充好的数据
}
if (fuSound & SND_ASYNC)
{ // 异步播放
g_hThread = CreateThread(NULL, 0, Audio_ASyncProc, 0, 0, 0 ); // 创建一个播放线程
// RETAILMSG(1,("Create hThread = %x \r\n",g_hThread));
}
else
{ // 同步播放
// while(bPlaying == TRUE)
// {
// Sleep(100);
// }
WaitForSingleObject(hPlayOverEvent,INFINITE); // 等待播放完成
/* for (i=0;i<MAX_BUFFERNUM;i++)
{
if (wh[i].lpData)
{
RETAILMSG(1,("free memory %x \r\n",wh[i].lpData));
free(wh[i].lpData);
wh[i].lpData = NULL;
}
}
*/
}
// RETAILMSG(1,("sndPlaySound ---\r\n"));
return TRUE;
}
// **************************************************
// 声明:BOOL WINAPI PlaySound( LPCTSTR pszSound, HANDLE hmod, DWORD fdwSound)
// 参数:
// IN pszSound -- 声音源
// IN hmod -- 播放的模块句柄
// IN fdwSound -- 播放标志
//
// 返回值:成功返回TRUE,否则返回FALSE
// 功能描述:播放一个声音源。
// 引用:
// **************************************************
BOOL WINAPI PlaySound( LPCTSTR pszSound, HANDLE hmod, DWORD fdwSound)
{
return TRUE;
}
// **************************************************
// 声明:void CALLBACK AudioProc( HWAVEOUT hwi, UINT uMsg,DWORD dwInstance, DWORD dwParam1)
// 参数:
// IN hwi -- 声音设备句柄
// IN uMsg -- 消息代码
// IN dwInstance -- 实例句柄
// IN dwParam1 -- 参数
//
// 返回值:无
// 功能描述:声音数据处理函数。
// 引用:
// **************************************************
void CALLBACK AudioProc( HWAVEOUT hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1)//,
// DWORD dwParam2 )
{
// DWORD SampleBytes;
LPWAVEHDR lpwh;
// RETAILMSG(1,(("*********************have a message form Audio (%d)\r\n"),uMsg));
switch( uMsg )
{
case WOM_OPEN: // 声音设备打开
// RETAILMSG(1,(("*********************The play is Open\r\n")));
return;
case WOM_DONE: // 声音设备完成一个数据
// RETAILMSG(1,(("WOM_DONE ++++ \r\n")));
uPlayingNum --;
lpwh=(LPWAVEHDR)dwParam1; // 得到完成的数据结构
// RETAILMSG(1,(("*********************The Complete wh is %X,dwFlags=%X\r\n"),lpwh,lpwh->dwFlags));
waveOutUnprepareHeader(hwo,lpwh,sizeof(WAVEHDR)); // 解除准备结构头
// RETAILMSG(1,(("1 \r\n")));
// free(lpwh->lpData);
// RETAILMSG(1,(("2 \r\n")));
if (FillBuffer(lpwh)== FALSE) // 填充缓存
break;
AddBuffer(lpwh); // 将数据添加到播放列表
// RETAILMSG(1,(("WOM_DONE ---- \r\n")));
return;
case WOM_CLOSE: // 播放完成
bPlaying = FALSE; // 不在播放中
// RETAILMSG(1,("***bPlaying %d\r\n",bPlaying));
SetEvent(hPlayOverEvent); // 设置完成播放的事件
// RETAILMSG(1,(("*********************The play is close\r\n")));
return;
}
}
// **************************************************
// 声明:static BOOL OpenWav(void)
// 参数:
// 无
// 返回值:成功返回TRUE,否则返回FALSE
// 功能描述:打开声音设备。
// 引用:
// **************************************************
static BOOL OpenWav(void)
{
WAVEFORMATEX waveFormatEx;
MMRESULT result;
int i;
bPlaying=TRUE;
// RETAILMSG(1,("***bPlaying %d\r\n",bPlaying));
bStoped = FALSE;
bStoping = FALSE;
waveFormatEx.wFormatTag = WAVE_FORMAT_PCM; // 要打开的声音格式
waveFormatEx.nChannels = g_stChunkHeader.common_field.wChannels; //nWaveChannel;
waveFormatEx.nSamplesPerSec = g_stChunkHeader.common_field.dwSamplesPerSec; // 每秒样本数
waveFormatEx.wBitsPerSample = g_stChunkHeader.PCM_format_specific.wBitsPerSample; // 每个样本的BIT数
waveFormatEx.nAvgBytesPerSec = g_stChunkHeader.common_field.dwAvgBytesPerSec; // 平均每秒要播放的BYTE数
waveFormatEx.nBlockAlign = g_stChunkHeader.common_field.wBlockAlign; // BLOCK对齐的大小
waveFormatEx.cbSize = 0;
// RETAILMSG(1,("waveOutOpen ...\r\n"));
// 打开声音设备
result=waveOutOpen(
&hwo,
0 ,
(LPWAVEFORMATEX)&waveFormatEx,
(DWORD)AudioProc,
0,
CALLBACK_FUNCTION);
if (result!=MMSYSERR_NOERROR )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -