原创 waveOutOpen函数

2011-2-12 18:15 5787 4 4 分类: 软件与OS

waveOutOpen函数介绍 收藏

(from MSDN)
 这个函数打开一个给定的波形音频输出装置来进行回放。
(The waveOutOpen function opens the given waveform-audio output device for playback)
URL:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_waveoutunprepareheader.asp

原型如下:
 MMRESULT waveOutOpen(
     LPHWAVEOUT     phwo,      
     UINT_PTR       uDeviceID, 
     LPWAVEFORMATEX pwfx,      
     DWORD_PTR      dwCallback,
     DWORD_PTR      dwCallbackInstance,
     DWORD          fdwOpen    
 );

参数介绍(paramters):
phwo
 一个指向接收波形音频输出装置柄的缓冲器。用柄来区别(identify

)装置当呼叫别的波形装置输出装置。如果fdwOpen被设定为WAVE_FORMAT_QUER

Y,那么这个参数可能为NULL 。
uDevideID
 将要被打开的波形音频输出装置的ID ,它可以是一个装置ID,也可以

是一个已经打开的波形音频输入装置柄,你可以用以下的值来货替:
 值                              含义
 WAVE_MAPPER  该函数选一个能够播放给定格式的波形音频输出装置

pwfx                           一个指向区别将被送到装置的音频数据格式的WAVEFORMATEX结构的指针,你可以FREE这个结构当你一将其传到waveOutOpen 函数;

dwCallback
 它指向一个特定的CALLBACK函数,事件柄,窗口柄,或一个将在波形

音频回放时以便处理与回放进度相关的消息的期间呼叫的线程ID,如果无须CALL

BACK函数,可以将其设为0 。更多请参看waveOutProc

dwCallbackInstance 
 传递到CALLBACK进程的用户实例数据。如果是窗口CALLBACK进程的话,该参数不用(设为0)
fwOpen
 用来打开装置的标识(FLAGS),它们的定义如下:
 值    含义
 CALLBACK_EVENT   dwCallback 参数栏是事件柄
 CALLBACK_FUNCTION  dwCallback 参数栏是CALLBACK过程地址
 CALLBACK_NULL   默认的设置,即无CALLBACK进程
 CALLBACK_THREAD   dwCallback 参数栏是线程ID
 CALLBACK_WINDOW   dwCallback 参数栏是窗口柄
 WAVE_ALLOWSYNC   如果该项被设置,一个同步的装

置能被打开。如果在打开一个同步驱动时没有用该项,装置打开将会失败。
 WAVE_FORMAT_DIRECT  如果设定该项,the ACM driver

does not perform conversions on the audio data.
 WAVE_FORMAT_QUERY  如果设定该项,waveOutOpen 询

问装置来决定是否支持给定的格式,但装置实际上并没有被打开。
 WAVE_MAPPED   该项被设定后uDeviceID参数表示

一个被声波映射装置映射的波形装置。

返回值:
 成功后返回MMSYSERR_NOERROR ,否则返回以下值:
 值    描述
 MMSYSERR_ALLOCATED  表示资源已存在
 MMSYSERR_BADDEVICEID  装置ID超出范围
 MMSYSERR_NODRIVER  没有驱动
 MMSYSERR_NOMEM   不能分配内存
 WAVERR_BADFORMAT  企图打开一个不被支持的格式
 WAVERR_SYNC   装置是可同步的,但waveOutOpen

没用有WAVE_ALLOWSYNC呼叫。
注:
 用waveOutGetNumDevs

函数测定在当前系统中输出装置的数目。如果uDeviceIC参数项是一个装置ID,

它将会表示从0 到总的数目,WAAVE_MAPPER常量也可以用作装置ID。
 pwfc所指的结构能够扩展到包含某些数据格式的特殊信息,例如,对

于PCM数据,一个额外的UNIT

类型用来表示取样的位数目。在这个情况下用PCMWAVEFORAMT结构。对于其它的

格式,用WAVEFORMATEX结构来表示额外的数据长度。
 如果你选用的是一个窗口或线程来接收CALLBACK信息,如下的信息将

会被送到窗口处理函数中,来表明波形音频输出进程:MM_WOM_OPEN

,MM_WOM_CLOSE ,和MM_WOM_DONE ,
 如果你选用的是一个函数来接收CALLBACK信息,如下的信息将会被传

到函数中,来显示波形音频输出进程:WOM_OPEN ,WOM_CLOSE ,WOM_DONE.
   
要求:

  Windows NT/2000/XP: Included in Windows NT 3.1 and later.
  Windows 95/98/Me: Included in Windows 95 and later.
  Header: Declared in Mmsystem.h; include Windows.h.
  Library: Use Winmm.lib.
参见:
 Waveform Audio, Waveform Functions, WAVEFORMATEX,

waveOutGetNumDevs, waveOutProc, PCMWAVEFORMAT, MM_WOM_OPEN,

MM_WOM_CLOSE, MM_WOM_DONE

 

MMRESULT   waveOutOpen( 
    LPHWAVEOUT   phwo,                       
    UINT   uDeviceID,                         
    LPWAVEFORMATEX   pwfx,               
    DWORD   dwCallback,                     
    DWORD   dwCallbackInstance,     
    DWORD   fdwOpen                             
); 
dwCallback   放回调函数指针 
dwCallbackInstance   放回调函数所在实例句柄(DLL的) 
有两个问题 
回调函数应该申明成什么样子? 
DLL的实例句柄如何取得?

 

1.回调函数设置: 
void   CALLBACK   waveOutProc(HWAVEOUT   hwo, 
                                                    UINT   uMsg, 
                                                    DWORD   dwInstance, 
                                                    DWORD   dwParam1, 
                                                    DWORD   dwParam2); 
更多描述见MSDN之waveOutProc。 
2.关于dwCallbackInstance: 
俺不知道你这里的DLL是什么意思。你的程序要做成DLL?首先这个参数windows是不关心的,它只是在调用你的回调函数时为你原封不动地传回来,也就是说对它没有什么固定的要求,你可以传入任何东西,关键看你需要这么用它。因为回调函数必须声明成全局或静态,所以一般来说都是把指向你当前调用waveOutOpen所在对象的实例的指针(也就是this)传进去,这样在回调函数里,你可以用这个指针来操作该对象所在类的成员。

 

 

谢谢你的回答 
我刚才在CSDN上也查到了这个声明 
是的,我想把它做在DLL中,这个dwCallbackInstance应该怎样给值呢? 
还有,利用回调函数后在MM_WIM_DATA 
中取出数据是用(PWAVEHDR)   dwParam1)-> lpData,还是用(PWAVEHDR)   dwParam2)-> lpData取得数据呢? 
期望你的回答,马上给分你!

 

 

 

使用心得:首先打开声音输出设备,然后初始化输出内存,并保证不要使用缓存;(调用waveOutPrepareHeader设置内存),然后通过回调函数进行状态通知。通过waveOutWrite进行声音播放;

最后调用waveOutUnprepareHeader释放内存,waveOutReset(m_hWaveOut);
   waveOutClose(m_hWaveOut);关闭音频设备

//声明:
waveOutOpen(
  lphWaveOut: PHWaveOut;   {用于返回设备句柄的指针; 如果 dwFlags=WAVE_FORMAT_QUERY, 这里应是 nil}
  uDeviceID: UINT;         {设备ID; 可以指定为: WAVE_MAPPER, 这样函数会根据给定的波形格式选择合适的设备}
  lpFormat: PWaveFormatEx; {TWaveFormat 结构的指针; TWaveFormat 包含要申请的波形格式}
  dwCallback: DWORD        {回调函数地址或窗口句柄; 若不使用回调机制, 设为 nil}
  dwInstance: DWORD        {给回调函数的实例数据; 不用于窗口}
  dwFlags: DWORD           {打开选项}
): MMRESULT;               {成功返回 0; 可能的错误值见下:}

MMSYSERR_BADDEVICEID = 2 {设备ID超界}
MMSYSERR_ALLOCATED   = 4 {指定的资源已被分配}
MMSYSERR_NODRIVER    = 6 {没有安装驱动程序}
MMSYSERR_NOMEM       = 7 {不能分配或锁定内存}
WAVERR_BADFORMAT     = 32; {设备不支持请求的波形格式}

//TWaveFormatEx 结构:
TWaveFormatEx = packed record
  wFormatTag: Word;       {指定格式类型; 默认 WAVE_FORMAT_PCM = 1;}
  nChannels: Word;        {指出波形数据的通道数; 单声道为 1, 立体声为 2}
  nSamplesPerSec: DWORD;  {指定样本速率(每秒的样本数)}一般为8000
  nAvgBytesPerSec: DWORD; {指定数据传输的平均速率(每秒的字节数)} 每秒的字节数: 
  nBlockAlign: Word;      {指定块对齐(单位字节), 块对齐是数据的最小单位}
  wBitsPerSample: Word;   {采样大小(字节)}每个样本的BIT数目,一般为16
  cbSize: Word;           {应该是该结构的大小}
end;
{16 位立体声 PCM 的块对齐是 4 字节(每个样本2字节, 2个通道)}

//打开选项 dwFlags 的可选值:
WAVE_FORMAT_QUERY = $0001;     {只是判断设备是否支持给定的格式, 并不打开}
WAVE_ALLOWSYNC    = $0002;     {当是同步设备时必须指定}
CALLBACK_WINDOW   = $00010000; {当 dwCallback 是窗口句柄时指定}
CALLBACK_FUNCTION = $00030000; {当 dwCallback 是函数指针时指定}

//如果选择窗口接受回调信息, 可能会发送到窗口的消息有:
MM_WOM_OPEN  = $3BB;
MM_WOM_CLOSE = $3BC;
MM_WOM_DONE  = $3BD;

//如果选择函数接受回调信息, 可能会发送给函数的消息有:
WOM_OPEN  = MM_WOM_OPEN;
WOM_CLOSE = MM_WOM_CLOSE;
WOM_DONE  = MM_WOM_DONE;
举例如下:

//回调函数

static void CALLBACK
SpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance,
                 DWORD dwParam1, DWORD dwParam2)
{
  WAVEHDR *wHdr;
   streamUtil * parentStream =NULL;

  switch (uMsg)
    {
      case WOM_OPEN:
//          ms_message("SpeakerCallback : WOM_OPEN");
    DEBUG_HELPER->log("streamUtil",LM_DEBUG,"RECEIVE WOM_OPEN\n");
        break;
      case WOM_CLOSE:
      DEBUG_HELPER->log("streamUtil",LM_DEBUG,"RECEIVE WOM_CLOSE\n");
  //        ms_message("SpeakerCallback : WOM_CLOSE");
        break;
      case WOM_DONE:
     parentStream = (streamUtil*)dwInstance;
   wHdr = (WAVEHDR *) dwParam1;
  // waveOutUnprepareHeader (parentStream->m_hWaveOut, wHdr, sizeof (WAVEHDR)) ;
  
        break;
   default:
    break;
   
    }
}

 

 

WAVEFORMATEX waveform;
 waveform.wFormatTag  = WAVE_FORMAT_PCM;
 waveform.nChannels  = channel;
 waveform.nSamplesPerSec =rate;//8000
 waveform.nAvgBytesPerSec=16000;
 waveform.nBlockAlign =2;
 waveform.wBitsPerSample =bits; //16
 waveform.cbSize   =0;
    //初始化回调标志
 dwFlag = CALLBACK_FUNCTION;
    if (devNumber != WAVE_MAPPER)
        dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
   //打开设备
 if (waveOutOpen(&m_hWaveOut,devNumber,&waveform,(DWORD) SpeakerCallback,(DWORD)this,dwFlag))  {
     
    DEBUG_HELPER->log("streamUtil",LM_ERROR,"Failed to open deice. (waveOutOpen:0x%i)\n", mr);
   return -1;
 }

 

  //
 //缓存的大小
 m_bufLength = (rate/8000) * INP_BUFFER_SIZE;
  for(int i=0;i<OUT_BUFFER_NUM;i++)
 {    
     //初始化输出缓存
   //m_outHdr= reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
          
  // m_outBuffer = (PBYTE)malloc(1 * m_bufLength);


   memset(m_outBuffer,0,m_bufLength);
    
      m_outHdr.lpData          = (LPSTR)(m_outBuffer );
   m_outHdr.dwBufferLength  = m_bufLength ;
   m_outHdr.dwBytesRecorded = 0 ;
   m_outHdr.dwUser          = 0 ;
   m_outHdr.dwFlags         = 0 ;
  // m_outHdr.lpNext          = NULL ;
   m_outHdr.reserved        = 0 ;
   m_outHdr.dwLoops =0;
   waveOutPrepareHeader (m_hWaveOut, &(m_outHdr), sizeof (WAVEHDR)) ;
 }

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条