更新 - 使用DirectSound播放Wave文件

更新 - 使用DirectSound播放Wave文件

    修改了一下DSound程序,增加播放Notify,支持播放Buffer。这样就可以连续播放一个比较大的Wave文件了。 源码在这里。下面是主要的代码:

    DSoundObject.h
 1  #ifndef __DSOUNDOBJECT_H__
 2  #define  __DSOUNDOBJECT_H__
 3 
 4  #include  < windows.h >
 5  #include  < dsound.h >
 6 
 7  #include  < string >
 8 
 9  extern  HANDLE _eventNotify[ 2 ];//这句很奇怪,如果改成CDSoundObject的static成员,VCExpress链接会出错,不明原因。
10 
11  class  CDSoundObject
12  {
13  public :
14       enum  SoundType { ST_WAVE, ST_MP3 };
15       static   const  DWORD SIZE_DS_BUFFER     =      32   *   1024 ;
16  public :
17      CDSoundObject(SoundType type);
18       virtual   ~ CDSoundObject();
19 
20       virtual   int  Init(HWND hwnd);
21       virtual   int  LoadFile( const  std:: string &  file)  =   0 ;
22 
23       virtual   int  Play()  =   0 ;
24       virtual   int  Pause()  =   0 ;
25       virtual   int  Stop()  =   0 ;
26       virtual   bool  IsPlaying()  const   =   0 ;
27       virtual  size_t Duration()  const   =   0 ;
28  protected :
29       virtual   void  Release();
30       virtual   int  CreateDSound();
31       virtual   int  CreateDSoundBuffer();
32 
33       virtual   int  LoadData(DWORD start, DWORD count)  =   0 ;
34       virtual   int  PlayOver()  =   0 ;
35  protected :
36      HWND _hWnd;
37      SoundType _eType;
38      IDirectSound  *  _pDS;
39      IDirectSoundBuffer  *  _pDSBuffer;
40      IDirectSoundNotify8 *  _pDSNotify;
41  protected :
42       int  CreateNotifyThread();
43       void  ReleaseNotifyThread();
44       static  DWORD NotifyHandleProc(LPVOID param);
45  public :
46      DWORD _dwNotifyThreadID;
47      HANDLE _hNotifyThread;
48 
49      DSBPOSITIONNOTIFY _notifyPos[ 2 ];
50  };
51 
52  #endif

    DSoundObject.cpp
  1  #include  " DSoundObject.h "
  2 
  3  HANDLE _eventNotify[ 2 ];
  4 
  5  CDSoundObject::CDSoundObject(CDSoundObject::SoundType type)
  6  : _eType(type)
  7  , _pDS(NULL), _pDSBuffer(NULL), _pDSNotify(NULL)
  8  , _dwNotifyThreadID( 0 ), _hNotifyThread(NULL)
  9  {
 10  }
 11 
 12  CDSoundObject:: ~ CDSoundObject()
 13  {
 14      Release();
 15  }
 16 
 17  void  CDSoundObject::Release()
 18  {
 19      ReleaseNotifyThread();
 20 
 21       if (_pDS  !=  NULL)
 22          _pDS -> Release();
 23  }
 24 
 25  int  CDSoundObject::Init(HWND hwnd)
 26  {
 27      _hWnd  =  hwnd;
 28 
 29       return  CreateDSound();
 30  }
 31 
 32  int  CDSoundObject::CreateDSound()
 33  {
 34      HRESULT hr  =  DirectSoundCreate(NULL,  & _pDS, NULL);
 35       if (hr  !=  DS_OK)
 36           return   - 1 ;
 37      _pDS -> SetCooperativeLevel(_hWnd, DSSCL_NORMAL);
 38       return   0 ;
 39  }
 40 
 41  int  CDSoundObject::CreateDSoundBuffer()
 42  {
 43       // if(CreateNotifyThread() != 0)
 44       //     return -1;
 45       return   0 ;
 46  }
 47 
 48  int  CDSoundObject::CreateNotifyThread()
 49  {
 50       // event
 51      _eventNotify[ 0 =  CreateEvent(NULL, FALSE, FALSE, NULL);
 52      _eventNotify[ 1 =  CreateEvent(NULL, FALSE, FALSE, NULL);
 53 
 54      _hNotifyThread  =  CreateThread(NULL,  0 , (LPTHREAD_START_ROUTINE)NotifyHandleProc, (LPVOID) this 0 & _dwNotifyThreadID);
 55       if (_hNotifyThread  ==  NULL)
 56           return   - 1 ;
 57 
 58      HRESULT hr  =  _pDSBuffer -> QueryInterface(IID_IDirectSoundNotify8, ( void ** ) & _pDSNotify);
 59       if (hr  !=  DS_OK)
 60           return   - 1 ;
 61 
 62      _notifyPos[ 0 ].dwOffset  =  (SIZE_DS_BUFFER  /   2 -   1 ;
 63      _notifyPos[ 0 ].hEventNotify  =  _eventNotify[ 0 ];
 64      _notifyPos[ 1 ].dwOffset  =  SIZE_DS_BUFFER  -   1 ;
 65      _notifyPos[ 1 ].hEventNotify  =  _eventNotify[ 1 ];
 66 
 67      hr  =  _pDSNotify -> SetNotificationPositions( 2 , _notifyPos);
 68       if (hr  !=  DS_OK)
 69           return   - 1 ;
 70 
 71       return   0 ;
 72  }
 73 
 74  void  CDSoundObject::ReleaseNotifyThread()
 75  {
 76       if (_hNotifyThread  !=  NULL)
 77      {
 78          TerminateThread(_hNotifyThread,  0 );
 79          CloseHandle(_hNotifyThread);
 80          _hNotifyThread  =  NULL;
 81      }
 82       for ( int  i  =   0 ; i  <   2 ++  i)
 83      {
 84           if (_eventNotify[i]  !=  NULL)
 85          {
 86              CloseHandle(_eventNotify[i]);
 87              _eventNotify[i]  =  NULL;
 88          }
 89      }
 90 
 91       if (_pDSNotify  !=  NULL)
 92      {
 93          _pDSNotify -> Release();
 94          _pDSNotify  =  NULL;
 95      }
 96  }
 97 
 98  DWORD CDSoundObject::NotifyHandleProc(LPVOID param)
 99  {
100      CDSoundObject *  obj  =  (CDSoundObject * )(param);
101       if (obj  ==  NULL)
102           return   - 1 ;
103 
104       while ( true )
105      {
106          DWORD ret  =  MsgWaitForMultipleObjects( 2 , _eventNotify, FALSE, INFINITE, QS_ALLEVENTS);
107           if (ret  ==  WAIT_FAILED)
108               return   - 1 ;
109          
110          DWORD notify  =  ret  -  WAIT_OBJECT_0;
111           if (notify  ==   0 )
112          {
113               if (obj -> LoadData( 0 , SIZE_DS_BUFFER  /   2 !=   0 )
114                   break ;
115          }
116           else   if (notify  ==   1 )
117          {
118               if (obj -> LoadData(SIZE_DS_BUFFER  /   2  , SIZE_DS_BUFFER  /   2 !=   0 )
119                   break ;
120          }
121           else
122          {
123               continue ;
124  //             return -1;
125          }
126      }
127 
128      obj -> PlayOver();
129 
130       return   0 ;
131  }

    DSWaveObject.h
 1  #ifndef __DSWAVEOBJECT_H__
 2  #define  __DSWAVEOBJECT_H__
 3 
 4  #include  < fstream >
 5  #include  < string >
 6 
 7  #include  " DSoundObject.h "
 8 
 9  class  CDSWaveObject :  public  CDSoundObject
10  {
11  protected :
12  //  .WAV file header
13       struct  WAVE_HEADER
14      {
15           char     riff_sig[ 4 ];             //  'RIFF'
16           long     waveform_chunk_size;     //  8
17           char     wave_sig[ 4 ];             //  'WAVE'
18           char     format_sig[ 4 ];           //  'fmt ' (notice space after)
19           long     format_chunk_size;       //  16;
20           short    format_tag;              //  WAVE_FORMAT_PCM
21           short    channels;                //  # of channels
22           long     sample_rate;             //  sampling rate
23           long     bytes_per_sec;           //  bytes per second
24           short    block_align;             //  sample block alignment
25           short    bits_per_sample;         //  bits per second
26           char     data_sig[ 4 ];             //  'data'
27           long     data_size;               //  size of waveform data
28      };
29 
30  public :
31      CDSWaveObject();
32       virtual   ~ CDSWaveObject();
33 
34       virtual   int  LoadFile( const  std:: string &  file);
35       virtual   int  Play();
36       virtual   int  Pause();
37       virtual   int  Stop();
38       virtual   bool  IsPlaying()  const ;
39       virtual  size_t Duration()  const ;
40  protected :
41       virtual   void  Release();
42  protected :
43       int  LoadWaveData();
44       int  ReadWaveHeader(WAVE_HEADER &  header);
45       int  CreateDSBuffer( const  WAVE_HEADER &  header);
46 
47       virtual   int  LoadData(DWORD start, DWORD count);
48       virtual   int  PlayOver();
49  private :
50      std:: string  _strFileName;
51 
52      WAVE_HEADER _headerWave;
53      WAVEFORMATEX _fmtWave;
54      std::ifstream _ifStream;
55      DWORD _dwReadSize;
56      DWORD _dwPlayPos; 
57  };
58 
59 
60  #endif

    DSWaveObject.cpp
  1  #include  " DSWaveObject.h "
  2 
  3  CDSWaveObject::CDSWaveObject()
  4  : CDSoundObject(CDSoundObject::ST_WAVE)
  5  , _dwReadSize( 0 )
  6  , _dwPlayPos( 0 )
  7  {
  8  }
  9 
 10  CDSWaveObject:: ~ CDSWaveObject()
 11  {
 12      Release();
 13  }
 14 
 15  void  CDSWaveObject::Release()
 16  {
 17      ReleaseNotifyThread();
 18 
 19       if (_pDSBuffer  !=  NULL)
 20      {
 21          _pDSBuffer -> Stop();
 22          _pDSBuffer -> Release();
 23          _pDSBuffer  =  NULL;
 24      }
 25       if (_ifStream.is_open())
 26          _ifStream.close();
 27  }
 28 
 29  int  CDSWaveObject::LoadFile( const  std:: string   & file)
 30  {
 31      Release();
 32 
 33      _ifStream.open(file.c_str(), std::ios:: in   |  std::ios::binary);
 34       if ( ! _ifStream.is_open())
 35           return   - 1 ;
 36 
 37      memset( & _headerWave,  0 sizeof (WAVE_HEADER));
 38 
 39       if (ReadWaveHeader(_headerWave)  !=   0 )
 40           return   - 1 ;
 41 
 42       if (CreateDSBuffer(_headerWave)  !=   0 )
 43           return   - 1 ;
 44 
 45       return   0 ;
 46  }
 47 
 48  int  CDSWaveObject::LoadWaveData()
 49  {
 50      _dwPlayPos  =   0 ;
 51      _dwReadSize  =   0 ;
 52 
 53      _ifStream.clear();
 54 
 55      _ifStream.seekg( sizeof (WAVE_HEADER), std::ios::beg);
 56       if (LoadData( 0 , CDSoundObject::SIZE_DS_BUFFER)  !=   0 )
 57      {
 58           return   - 1 ;
 59      }
 60 
 61      ReleaseNotifyThread();
 62 
 63       if (CreateNotifyThread()  !=   0 )
 64           return   - 1 ;
 65       return   0 ;
 66  }
 67 
 68  int  CDSWaveObject::ReadWaveHeader(CDSWaveObject::WAVE_HEADER  & header)
 69  {
 70      _ifStream.seekg( 0 , std::ios::beg);
 71      _ifStream.read(( char * ) & header,  sizeof (WAVE_HEADER));
 72       if ( ! _ifStream.good())
 73           return   - 1 ;
 74       if (memcmp(header.riff_sig,  " RIFF " 4 ||  memcmp(header.wave_sig,  " WAVE " 4 ||
 75         memcmp(header.format_sig,  " fmt  " 4 ||  memcmp(header.data_sig,  " data " 4 ))
 76      {
 77           return   - 1 ;
 78      }
 79       return   0 ;
 80  }
 81 
 82  int  CDSWaveObject::CreateDSBuffer( const  CDSWaveObject::WAVE_HEADER  & header)
 83  {
 84  //     WAVEFORMATEX wformat;
 85      memset( & _fmtWave,  0 sizeof (WAVEFORMATEX));
 86      _fmtWave.wFormatTag  =  WAVE_FORMAT_PCM;
 87      _fmtWave.nChannels  =  header.channels;
 88      _fmtWave.nSamplesPerSec  =  header.sample_rate;
 89      _fmtWave.wBitsPerSample  =  header.bits_per_sample;
 90      _fmtWave.nBlockAlign  =  header.bits_per_sample  /   8   *  header.channels; //  header.block_align;
 91      _fmtWave.nAvgBytesPerSec  =  header.sample_rate  *  header.block_align; // header.
 92       // wformat.cbSize = header.data_size;
 93 
 94      DSBUFFERDESC desc;
 95      memset( & desc,  0 sizeof (DSBUFFERDESC));
 96      desc.dwSize  =   sizeof (DSBUFFERDESC);
 97      desc.dwFlags  =  DSBCAPS_GLOBALFOCUS  |  DSBCAPS_CTRLVOLUME  |  DSBCAPS_CTRLPOSITIONNOTIFY  |  DSBCAPS_LOCSOFTWARE;
 98      desc.dwBufferBytes  =  CDSoundObject::SIZE_DS_BUFFER; // header.data_size;
 99      desc.lpwfxFormat  =   & _fmtWave;
100 
101       if (_pDSBuffer  !=  NULL)
102          _pDSBuffer -> Release();
103 
104      HRESULT hr  =  _pDS -> CreateSoundBuffer( & desc,  & _pDSBuffer, NULL);
105       if (hr  !=  DS_OK)
106           return   - 1 ;
107      
108       return   0 ;
109  }
110 
111  int  CDSWaveObject::LoadData(DWORD start, DWORD count)
112  {
113       if ( ! _ifStream.good())
114           return   - 1 ;
115       if (_dwReadSize  >=  _headerWave.data_size)
116           return   - 1 ;
117 
118      LPVOID aptr1  =  NULL, aptr2  =  NULL;
119      DWORD abyte1  =  NULL, abyte2  =  NULL;
120 
121      HRESULT hr  =  _pDSBuffer -> Lock(start, count,  & aptr1,  & abyte1,  & aptr2,  & abyte2,  0 );
122       if (hr  !=  DS_OK)
123           return   - 1 ;
124      
125      _ifStream.read(( char * )aptr1, abyte1);
126       if (aptr2  !=  NULL)
127          _ifStream.read(( char * )aptr2, abyte2);
128 
129      _pDSBuffer -> Unlock(aptr1, abyte1, aptr2, abyte2);
130 
131      _dwReadSize  +=  count;
132 
133       return   0 ;
134  }
135 
136  int  CDSWaveObject::Play()
137  {
138       if (_dwPlayPos  ==   0 )
139      {
140          LoadWaveData();
141      }
142 
143      _pDSBuffer -> SetCurrentPosition(_dwPlayPos);
144      _pDSBuffer -> SetVolume( - 2000 ); // DSBVOLUME_MAX);
145      _pDSBuffer -> Play( 0 0 , DSBPLAY_LOOPING);
146 
147       return   0 ;
148  }
149 
150  int  CDSWaveObject::Pause()
151  {
152       if (_pDSBuffer  ==  NULL)
153           return   - 1 ;
154      HRESULT hr  =  _pDSBuffer -> GetCurrentPosition( & _dwPlayPos, NULL);
155       if (hr  !=  DS_OK)
156           return   - 1 ;
157      _pDSBuffer -> Stop();
158 
159       return   0 ;
160  }
161 
162  int  CDSWaveObject::Stop()
163  {
164       if (_pDSBuffer  ==  NULL)
165           return   - 1 ;
166      _pDSBuffer -> Stop();
167      _dwPlayPos  =   0 ;
168 
169       return   0 ;
170  }
171 
172  bool  CDSWaveObject::IsPlaying()  const
173  {
174       if (_pDSBuffer  ==  NULL)
175           return   false ;
176 
177      DWORD status  =   0 ;
178      HRESULT hr  =  _pDSBuffer -> GetStatus( & status);
179       if (hr  !=  DS_OK)
180           return   false ;
181       return  ((status  &  DSBSTATUS_PLAYING)  ==  DSBSTATUS_PLAYING  ?   true  :  false );
182  }
183 
184  size_t CDSWaveObject::Duration()  const
185  {
186       return  (_headerWave.data_size  *   1000   /  _fmtWave.nAvgBytesPerSec);
187       // if(_pDSBuffer == NULL)
188       //     return 0;
189       // WAVEFORMATEX wformat;
190       // HRESULT hr = _pDSBuffer->GetFormat(&wformat, sizeof(WAVEFORMATEX), NULL);
191       // if(hr != DS_OK)
192       //     return 0;
193 
194       // DSBCAPS caps;
195       // memset(&caps, 0, sizeof(DSBCAPS));
196       // caps.dwSize = sizeof(DSBCAPS);
197       // hr = _pDSBuffer->GetCaps(&caps);
198       // if(hr != DS_OK)
199       //     return -1;
200 
201       // return (caps.dwBufferBytes * 1000 / wformat.nAvgBytesPerSec);
202  }
203 
204  int  CDSWaveObject::PlayOver()
205  {
206       return  Stop();
207  }
208 


你可能感兴趣的:(更新 - 使用DirectSound播放Wave文件)