SoundOut.cpp
上传用户:wen82zi81
上传日期:2007-01-03
资源大小:40k
文件大小:10k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. // SoundOut.cpp: implementation of the CSoundOut class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. /*
  5.    
  6.     This program is Developped by Yannick Sustrac
  7.                    yannstrc@mail.dotcom.fr
  8.         http://www.mygale.org/~yannstrc/
  9.  
  10. This program is free software; you can redistribute it and/or modify it under the terms
  11. of the GNU General Public License as published by the Free Software Foundation; either
  12. version 2 of the License, or (at your option) any later version.
  13. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  14. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. See the GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License along with this program;
  17. if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. MODIFICATION:
  19. - CallBack function implementation 
  20. - Double buffer to feed the sound system
  21. */
  22. //////////////////////////////////////////////////////////////////////////////////////////    
  23. #include "stdafx.h"
  24. #include "math.h"
  25. #include "snd.h"
  26. #include "SoundOut.h"
  27. #pragma comment(lib, "winmm")
  28. /////////////////////////////////////////////////////////////////////////////////////////////
  29. // comment this line to compile with a thread implementation rather than a callback function
  30. //#define CALL_BACK_TEST
  31. /////////////////////////////////////////////////////////////////////////////////////////////
  32. #ifdef _DEBUG
  33. #undef THIS_FILE
  34. static char THIS_FILE[]=__FILE__;
  35. #define new DEBUG_NEW
  36. #endif
  37. #define real double
  38. UINT WaveOutThreadProc(void * pParam);
  39. void CALLBACK WaveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2);
  40. //////////////////////////////////////////////////////////////////////
  41. // Construction/Destruction
  42. //////////////////////////////////////////////////////////////////////
  43. CSoundOut::CSoundOut()
  44. {
  45.   m_NbMaxSamples = MAX_OUTPUT_SAMPLES;
  46.   m_WaveOutSampleRate = 11025;
  47.   m_Toggle = 0;
  48. }
  49. CSoundOut::~CSoundOut()
  50. {
  51. CloseOutput();
  52. }
  53. ///////////////////////////////////////////////////////////////////
  54. MMRESULT CSoundOut::OpenOutput()
  55. {
  56.      MMRESULT result;
  57.     result=waveOutGetNumDevs(); 
  58. if (result == 0)
  59. {
  60.         AfxMessageBox("No Sound Output Device");
  61. return result;
  62. }
  63.    // test for Mic available   
  64.    result=waveOutGetDevCaps (0, &m_WaveOutDevCaps, sizeof(WAVEOUTCAPS));
  65.    
  66.    if ( result!= MMSYSERR_NOERROR)
  67.    {
  68.        AfxMessageBox(_T("Sound output Cannot determine card capabilities !"));
  69.    }
  70. m_Terminate = FALSE;
  71. #ifndef CALL_BACK_TEST
  72. // The SoundOut Devive is OK now we can create an Event  and start the Thread
  73. m_WaveOutEvent = CreateEvent(NULL,FALSE,FALSE,"WaveOutThreadEvent");
  74. m_WaveOutThread= AfxBeginThread(WaveOutThreadProc,this,THREAD_PRIORITY_TIME_CRITICAL,0,CREATE_SUSPENDED,NULL);   
  75. m_WaveOutThread->m_bAutoDelete = TRUE;
  76. #endif
  77. // start the thread at the end of the buffer init
  78. // init format 
  79. WaveInitFormat(1/* mono*/,m_WaveOutSampleRate /* khz */,16 /* bits */); 
  80. // Open Output 
  81. #ifdef CALL_BACK_TEST
  82. result = waveOutOpen( &m_WaveOut,0, &m_WaveFormat,(DWORD)WaveOutProc ,(ULONG)this ,CALLBACK_FUNCTION); 
  83. #else
  84. result = waveOutOpen( &m_WaveOut,0, &m_WaveFormat,(DWORD)m_WaveOutEvent ,NULL ,CALLBACK_EVENT); 
  85. #endif
  86. if ( result!= MMSYSERR_NOERROR)
  87. {
  88.         AfxMessageBox(_T("Sound output Cannot Open Device!"));
  89.     return result;
  90. }
  91. m_Toggle = 0;
  92. m_SizeRecord = m_NbMaxSamples;
  93.     m_WaveHeader[m_Toggle].lpData = (CHAR *)&OutputBuffer[m_Toggle][0];
  94.     m_WaveHeader[m_Toggle].dwBufferLength = m_SizeRecord*2;
  95. m_WaveHeader[m_Toggle].dwFlags = 0;
  96.     result = waveOutPrepareHeader( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) ); 
  97.   //MMRESULT waveOutPrepareHeader( HWAVEOUT hwi, LPWAVEHDR pwh, UINT cbwh ); 
  98.    if ( (result!= MMSYSERR_NOERROR) || ( m_WaveHeader[m_Toggle].dwFlags != WHDR_PREPARED) )
  99.    {
  100.         AfxMessageBox(_T(" Sound Output Cannot Prepare Header !"));
  101.     return result;
  102.    }
  103.    result = waveOutWrite( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) );
  104.    if  (result!= MMSYSERR_NOERROR) 
  105.    {
  106.         AfxMessageBox(_T(" Sound Output Cannot Write Buffer !"));
  107.     return result;
  108.    }
  109.    // register the second frame don't wait for the end of the first one
  110.    // so when we will be notified, this second frame will be currently output when we will reload the first one 
  111. m_Toggle = 1;
  112. m_SizeRecord = m_NbMaxSamples;
  113.     m_WaveHeader[m_Toggle].lpData = (CHAR *)&OutputBuffer[m_Toggle][0];
  114.     m_WaveHeader[m_Toggle].dwBufferLength = m_SizeRecord*2;
  115. m_WaveHeader[m_Toggle].dwFlags = 0;
  116.     result = waveOutPrepareHeader( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) ); 
  117.   //MMRESULT waveOutPrepareHeader( HWAVEOUT hwi, LPWAVEHDR pwh, UINT cbwh ); 
  118.    if ( (result!= MMSYSERR_NOERROR) || ( m_WaveHeader[m_Toggle].dwFlags != WHDR_PREPARED) )
  119.    {
  120.         AfxMessageBox(_T(" Sound Output Cannot Prepare Header !"));
  121.     return result;
  122.    }
  123.    result = waveOutWrite( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) );
  124.    if  (result!= MMSYSERR_NOERROR) 
  125.    {
  126.         AfxMessageBox(_T(" Sound Output Cannot Write Buffer !"));
  127.     return result;
  128.    }
  129. #ifndef CALL_BACK_TEST
  130. m_WaveOutThread->ResumeThread();
  131. #endif
  132.    return result;
  133. }
  134. void CSoundOut::AddBuffer()
  135. {
  136.    MMRESULT result;
  137.    if (m_Toggle == 0) 
  138.    m_Toggle = 1; 
  139.    else 
  140.    m_Toggle = 0;
  141.    result = waveOutUnprepareHeader( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) ); 
  142.    if  (result!= MMSYSERR_NOERROR) 
  143.    {
  144.         AfxMessageBox(_T("Sound output Cannot UnPrepareHeader !"));
  145.         return;
  146.    };
  147.   m_SizeRecord = m_NbMaxSamples;
  148.     m_WaveHeader[m_Toggle].lpData = (CHAR *)&OutputBuffer[m_Toggle][0];
  149.     m_WaveHeader[m_Toggle].dwBufferLength = m_SizeRecord *2;
  150. m_WaveHeader[m_Toggle].dwLoops = 0;
  151. m_WaveHeader[m_Toggle].dwFlags = 0; //WHDR_BEGINLOOP ;
  152.     result = waveOutPrepareHeader( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) ); 
  153.    if ( (result!= MMSYSERR_NOERROR) || ( m_WaveHeader[m_Toggle].dwFlags != WHDR_PREPARED) )
  154.         AfxMessageBox(_T("Sound output Cannot Prepare Header !"));
  155.    result = waveOutWrite( m_WaveOut, &m_WaveHeader[m_Toggle], sizeof(WAVEHDR) );
  156.    if  (result!= MMSYSERR_NOERROR) 
  157.         AfxMessageBox(_T("Sound output Cannot Add Buffer !"));
  158. }
  159. /*
  160. WAVE_FORMAT_1M08  11.025 kHz, mono, 8-bit 
  161. WAVE_FORMAT_1M16  11.025 kHz, mono, 16-bit 
  162. WAVE_FORMAT_1S08  11.025 kHz, stereo, 8-bit 
  163. WAVE_FORMAT_1S16  11.025 kHz, stereo, 16-bit 
  164. WAVE_FORMAT_2M08  22.05 kHz, mono, 8-bit 
  165. WAVE_FORMAT_2M16  22.05 kHz, mono, 16-bit 
  166. WAVE_FORMAT_2S08  22.05 kHz, stereo, 8-bit 
  167. WAVE_FORMAT_2S16  22.05 kHz, stereo, 16-bit 
  168. WAVE_FORMAT_4M08  44.1 kHz, mono, 8-bit 
  169. WAVE_FORMAT_4M16  44.1 kHz, mono, 16-bit 
  170. WAVE_FORMAT_4S08  44.1 kHz, stereo, 8-bit 
  171. WAVE_FORMAT_4S16  44.1 kHz, stereo, 16-bit 
  172. */ 
  173. void CSoundOut:: WaveInitFormat(    WORD    nCh, // number of channels (mono, stereo)
  174. DWORD   nSampleRate, // sample rate
  175. WORD    BitsPerSample)
  176. {
  177. m_WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
  178. m_WaveFormat.nChannels = nCh;
  179. m_WaveFormat.nSamplesPerSec = nSampleRate;
  180. m_WaveFormat.nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample/8;
  181. m_WaveFormat.nBlockAlign = m_WaveFormat.nChannels * BitsPerSample/8;
  182. m_WaveFormat.wBitsPerSample = BitsPerSample;
  183. m_WaveFormat.cbSize = 0;
  184. }   
  185. ///////////////////////////////////////////////////////////////////////////
  186. // the comutation for the Output samples need to be calibrated according
  187. // to the SoundOut board  add an Offset and a Mult coef.
  188. void CSoundOut::ComputeSamples(SHORT *pt)
  189. {
  190. }  
  191. void CSoundOut::CloseOutput()
  192. {
  193. if (m_WaveOut) 
  194. waveOutPause(m_WaveOut);
  195.     Sleep(50);  // wait for the pause
  196. // CloseHandle(m_WaveOut);
  197. m_Terminate = TRUE;
  198.     if (m_WaveOutEvent )
  199. SetEvent(m_WaveOutEvent);
  200.     Sleep(50);  // wait for the thread to terminate
  201.    if (m_WaveOut) 
  202.    {
  203. waveOutReset(m_WaveOut);
  204. waveOutClose(m_WaveOut);
  205.    }
  206. }
  207. void CSoundOut::RazBuffers()
  208. {
  209. for (int i=0;i<MAX_OUTPUT_SAMPLES;i++)
  210. {
  211.         OutputBuffer[0][i] = 0;
  212.         OutputBuffer[1][i] = 0;
  213. }
  214. }
  215. void CSoundOut::StopOutput()
  216. {
  217. waveOutPause(m_WaveOut);
  218. }
  219. void CSoundOut::StartOutput()
  220. {
  221. waveOutRestart(m_WaveOut);
  222. }
  223. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  224. //    Glogal Thread procedure for the CSoundOut class
  225. //    It cannot be included inside the Class
  226. //   
  227. // The LPARAM is the Class pointer it can be the base class CSoundOut
  228. // or a drived class like CFft 
  229. // The value of this parametre can change according because 
  230. //  OpenMic() call a virtual funtion 
  231. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  232. #define PT_S ((CSoundOut*)pParam) 
  233. UINT WaveOutThreadProc(void * pParam)
  234. {
  235. //   CSoundOut * SoundOut = (class CSoundOut *)pParam;
  236.    UINT result;
  237.    UINT FirstPass = TRUE;
  238. if ( FirstPass)
  239. result = WaitForSingleObject(PT_S->m_WaveOutEvent,INFINITE);
  240. FirstPass = FALSE;
  241.     
  242. while (!PT_S->m_Terminate)
  243. {
  244. result = WaitForSingleObject(PT_S->m_WaveOutEvent,INFINITE);
  245. if ((result == WAIT_OBJECT_0)&&(!PT_S->m_Terminate ))
  246. {
  247. PT_S->AddBuffer();      // Toggle as changed state here !Toggle point to the just received buffer
  248.     PT_S->ComputeSamples(&PT_S->m_Toggle);
  249. }
  250. else
  251. return 0;  // 
  252. }
  253.     return 0;
  254. }
  255. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. //    Test with a callback function instead of a thread
  257. //    
  258. //////////////////////////////////////////////////////////////////////////////////////////////////////////// 
  259. #ifdef CALL_BACK_TEST
  260. void CALLBACK WaveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD pParam,DWORD dwParam1,DWORD dwParam2)
  261. {
  262. if (!PT_S->m_Terminate )
  263. switch (uMsg)
  264. {
  265. case WOM_DONE:
  266. PT_S->AddBuffer();
  267.     PT_S->ComputeSamples(&PT_S->m_Toggle);
  268. break;
  269. case WOM_OPEN:
  270. break;
  271. case WOM_CLOSE:
  272. break;
  273. }
  274. }
  275. #endif