📄 sound.cpp
字号:
/*********************************************
程序设计:罗穆峰 2008-11-20
http://lmf.biaotian.com
E-mail: lmf@biaotian.com
QQ: 16324942 [模范英雄]
*********************************************/
#include <windows.h>
#include "Sound.h"
static HWAVEOUT s_hWave=NULL;
static char s_Buffer[2][1024];
static WAVEHDR s_WaveHdr[2];
static CRITICAL_SECTION s_DataSection;
static CRITICAL_SECTION s_WaveSection;
static bool s_Stop;
static std::vector<int> s_TempBuf;
CSound * s_pSound;
void CALLBACK WaveCallBack(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
{
if(WOM_DONE==uMsg)
{
if(!s_Stop)
{//已停止播放,则不要再读数据了
s_pSound->ReadData(((WAVEHDR*)dwParam1)->lpData,1024);
EnterCriticalSection(&s_WaveSection);
waveOutWrite(hwo,(WAVEHDR*)dwParam1,sizeof(WAVEHDR));
LeaveCriticalSection(&s_WaveSection);
}
}
}
bool CSound::Init()
{
/*
初始化声音设备。
返回值:
true 成功。
false 失败。
*/
s_pSound=this;
s_Stop=false;
WAVEFORMATEX wf;
wf.cbSize=0;
wf.nChannels=1;
wf.nSamplesPerSec=11025;
wf.wBitsPerSample=8;
wf.wFormatTag=WAVE_FORMAT_PCM;
wf.nBlockAlign=wf.wBitsPerSample/8*wf.nChannels;
wf.nAvgBytesPerSec=wf.nBlockAlign*wf.nSamplesPerSec;
if(MMSYSERR_NOERROR!=waveOutOpen(&s_hWave,WAVE_MAPPER,&wf,(DWORD)WaveCallBack,0,CALLBACK_FUNCTION))
{
s_hWave=NULL;
return false;
}
InitializeCriticalSection(&s_DataSection);
InitializeCriticalSection(&s_WaveSection);
s_WaveHdr[0].dwBufferLength=1024;
s_WaveHdr[0].dwBytesRecorded=0;
s_WaveHdr[0].dwFlags=0;
s_WaveHdr[0].dwLoops=1;
s_WaveHdr[0].dwUser=0;
s_WaveHdr[0].lpData=s_Buffer[0];
s_WaveHdr[0].lpNext=0;
s_WaveHdr[0].reserved=0;
s_WaveHdr[1]=s_WaveHdr[0];
s_WaveHdr[1].lpData=s_Buffer[1];
waveOutPrepareHeader(s_hWave,s_WaveHdr,sizeof(WAVEHDR));
waveOutPrepareHeader(s_hWave,s_WaveHdr+1,sizeof(WAVEHDR));
memset(s_Buffer,0x80,sizeof s_Buffer);
EnterCriticalSection(&s_WaveSection);
waveOutWrite(s_hWave,&s_WaveHdr[0],sizeof(WAVEHDR));
waveOutWrite(s_hWave,&s_WaveHdr[1],sizeof(WAVEHDR));
LeaveCriticalSection(&s_WaveSection);
return true;
}
void * CSound::AddChannel(const void * Data,size_t Len,bool Loop)
{
/*
增加一个声音通道。
参数:
[i]Data 该通道的音频数据。数据格式为11025Hz,8位单声道。
[i]Len 数据的长度。必须大于0。
[i]Loop 是否循环播放。若不是,则播放完后自动删除该通道。
返回值:
返回新通道的指针。
*/
if(!s_hWave)return NULL;//未初始化成功
SOUNDCHANNEL * psc;
EnterCriticalSection(&s_DataSection);
m_ChannelList.push_back(SOUNDCHANNEL());
psc=&m_ChannelList.back();
psc->Data.resize(Len);
memcpy(&psc->Data[0],Data,Len);
psc->CurPos=0;
psc->Loop=Loop;
LeaveCriticalSection(&s_DataSection);
return psc;
}
void CSound::DeleteChannel(void * Chn)
{
/*
删除一个通道。
参数:
[i]Chn 要删除的通道的指针。必须是一个有效的指针。
*/
std::list<SOUNDCHANNEL>::iterator it;
EnterCriticalSection(&s_DataSection);
for(it=m_ChannelList.begin();;++it)
{
if(&*it==Chn)
{
m_ChannelList.erase(it);
break;
}
}
LeaveCriticalSection(&s_DataSection);
}
void CSound::ReadData(void * Buf,int Len)
{
/*
读取音频数据进行播放。
参数:
[o]Buf 读取的数据存在该缓存中。如果缺少数据,则缺少的数据填为128。
[i]Len 缓存的长度。
*/
int n;
int * p;
int i;
EnterCriticalSection(&s_DataSection);
//混合各个声道的数据
s_TempBuf.resize(Len);//混合时数据可能超出范围,先用整形保存
memset(&s_TempBuf[0],0,sizeof(int)*Len);//未填充时全部为0
std::list<SOUNDCHANNEL>::iterator it=m_ChannelList.begin();
while(it!=m_ChannelList.end())
{
n=Len;
p=&s_TempBuf[0];
while(n)
{
int cnt=it->Data.size()-it->CurPos;
unsigned char * p2=reinterpret_cast<unsigned char*>(&it->Data[0]+it->CurPos);
if(cnt>n)cnt=n;
for(i=0;i<cnt;i++)
{
*p+=*p2-128;
p++;
p2++;
}
n-=cnt;
it->CurPos=reinterpret_cast<char*>(p2)-&it->Data[0];
if(it->Data.size()==it->CurPos)
{//已放到缓存尾
if(!it->Loop)break;//不循环
it->CurPos=0;//从头开始播放
}
}
if(it->Data.size()==it->CurPos)
{//已放到缓存尾且未绕回开头的,一定是不循环的,要删除该通道
it=m_ChannelList.erase(it);
}
else
{
++it;
}
}
LeaveCriticalSection(&s_DataSection);
//将数值限定在0~255之间
for(i=0;i<Len;i++)
{
if(s_TempBuf[i]>=127)
reinterpret_cast<char*>(Buf)[i]=static_cast<unsigned char>(255);
else if(s_TempBuf[i]<=-128)
reinterpret_cast<char*>(Buf)[i]=0;
else
reinterpret_cast<char*>(Buf)[i]=s_TempBuf[i]+128;
}
}
void CSound::Stop()
{
/*
停止播放并清除所有通道。
*/
s_Stop=true;
EnterCriticalSection(&s_WaveSection);
waveOutReset(s_hWave);
waveOutClose(s_hWave);
waveOutUnprepareHeader(s_hWave,s_WaveHdr,sizeof(WAVEHDR));
waveOutUnprepareHeader(s_hWave,s_WaveHdr+1,sizeof(WAVEHDR));
LeaveCriticalSection(&s_WaveSection);
EnterCriticalSection(&s_DataSection);
m_ChannelList.clear();
LeaveCriticalSection(&s_DataSection);
s_hWave=NULL;
DeleteCriticalSection(&s_WaveSection);
DeleteCriticalSection(&s_DataSection);
}
CSound::~CSound()
{
if(s_hWave)Stop();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -