使用DirectSound播放MP3文件

http://www.cppblog.com/codejie/archive/2009/03/26/77916.html


使用DirectSound播放MP3文件

    将对MP3的支持代码加入到DSound程序中,以供wxDeMPQ使用,随便调整了一下代码,使基类作更多的事情。下面修改后的代码, 源码在这里

    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[3];
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();
24      virtual  int Pause();
25      virtual  int Stop();
26      virtual  bool IsPlaying()  const;
27      virtual  double Duration() = 0;
28  protected:
29      virtual  int CreateDSound();
30      virtual  void ReleaseDSound();
31      virtual  int CreateDSoundBuffer();
32      virtual  void ReleaseDSoundBuffer();
33 
34      virtual  int InitDSData() = 0;
35      virtual  int LoadDSData(DWORD start, DWORD count) = 0;
36      virtual  int PlayOver();
37  protected:
38     HWND _hWnd;
39     SoundType _eType;
40     IDirectSound * _pDS;
41     IDirectSoundBuffer * _pDSBuffer;
42     IDirectSoundNotify8* _pDSNotify;
43  protected:
44      int CreateNotifyThread();
45      void ReleaseNotifyThread();
46      static DWORD NotifyHandleProc(LPVOID param);
47  protected:
48     DWORD _dwNotifyThreadID;
49     HANDLE _hNotifyThread;
50 
51     DSBPOSITIONNOTIFY _notifyPos[2];
52  protected:
53     DWORD _dwPlayPos; 
54 };
55 
56  #endif
    DSoundObject.cpp
  1 #include "DSoundObject.h"
  2 
  3 HANDLE _eventNotify[3];
  4 
  5 CDSoundObject::CDSoundObject(CDSoundObject::SoundType type)
  6 : _eType(type)
  7 , _pDS(NULL), _pDSBuffer(NULL), _pDSNotify(NULL)
  8 , _dwNotifyThreadID(0), _hNotifyThread(NULL)
  9 , _dwPlayPos(0)
 10 {
 11 }
 12 
 13 CDSoundObject::~CDSoundObject()
 14 {
 15     ReleaseNotifyThread();
 16     ReleaseDSoundBuffer();
 17     ReleaseDSound();
 18 }
 19 
 20 
 21  int CDSoundObject::Init(HWND hwnd)
 22 {
 23     _hWnd = hwnd;
 24 
 25      return CreateDSound();
 26 }
 27 
 28  int CDSoundObject::CreateDSound()
 29 {
 30     HRESULT hr = DirectSoundCreate(NULL, &_pDS, NULL);
 31      if(hr != DS_OK)
 32          return -1;
 33     _pDS->SetCooperativeLevel(_hWnd, DSSCL_NORMAL);
 34      return 0;
 35 }
 36 
 37 
 38  void CDSoundObject::ReleaseDSound()
 39 {
 40      if(_pDS != NULL)
 41         _pDS->Release(), _pDS = NULL;
 42 }
 43 
 44  int CDSoundObject::CreateDSoundBuffer()
 45 {
 46     ReleaseDSoundBuffer();
 47 
 48      return 0;
 49 }
 50 
 51  void CDSoundObject::ReleaseDSoundBuffer()
 52 {
 53      if(_pDSBuffer != NULL)
 54     {
 55         _pDSBuffer->Stop();
 56         _pDSBuffer->Release();
 57         _pDSBuffer = NULL;
 58     }
 59 }
 60 
 61  int CDSoundObject::CreateNotifyThread()
 62 {
 63     ReleaseNotifyThread();
 64 
 65      // event
 66      _eventNotify[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
 67     _eventNotify[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
 68     _eventNotify[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
 69 
 70 
 71     _hNotifyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NotifyHandleProc, (LPVOID) this, 0, &_dwNotifyThreadID);
 72      if(_hNotifyThread == NULL)
 73          return -1;
 74 
 75     HRESULT hr = _pDSBuffer->QueryInterface(IID_IDirectSoundNotify8, ( void**)&_pDSNotify);
 76      if(hr != DS_OK)
 77          return -1;
 78 
 79     _notifyPos[0].dwOffset = (SIZE_DS_BUFFER / 2) - 1;
 80     _notifyPos[0].hEventNotify = _eventNotify[0];
 81     _notifyPos[1].dwOffset = SIZE_DS_BUFFER - 1;
 82     _notifyPos[1].hEventNotify = _eventNotify[1];
 83 
 84     hr = _pDSNotify->SetNotificationPositions(2, _notifyPos);
 85      if(hr != DS_OK)
 86          return -1;
 87 
 88      return 0;
 89 }
 90 
 91  void CDSoundObject::ReleaseNotifyThread()
 92 {
 93      if(_hNotifyThread != NULL)
 94     {
 95          // TerminateThread(_hNotifyThread, 0);
 96          SetEvent(_eventNotify[2]);
 97         CloseHandle(_hNotifyThread);
 98         _hNotifyThread = NULL;
 99     }
100      for( int i = 0; i < 2; ++ i)
101     {
102          if(_eventNotify[i] != NULL)
103         {
104             CloseHandle(_eventNotify[i]);
105             _eventNotify[i] = NULL;
106         }
107     }
108 
109      if(_pDSNotify != NULL)
110     {
111         _pDSNotify->Release();
112         _pDSNotify = NULL;
113     }
114 }
115 
116 DWORD CDSoundObject::NotifyHandleProc(LPVOID param)
117 {
118     CDSoundObject* obj = (CDSoundObject*)(param);
119      if(obj == NULL)
120          return -1;
121 
122      while( true)
123     {
124         DWORD ret = MsgWaitForMultipleObjects(3, _eventNotify, FALSE, INFINITE, QS_ALLEVENTS);
125          if(ret == WAIT_FAILED)
126              return -1;
127         
128         DWORD notify = ret - WAIT_OBJECT_0;
129          if(notify == 0)
130         {
131              if(obj->LoadDSData(0, SIZE_DS_BUFFER / 2) != 0)
132                  break;
133         }
134          else  if(notify == 1)
135         {
136              if(obj->LoadDSData(SIZE_DS_BUFFER / 2 , SIZE_DS_BUFFER / 2) != 0)
137                  break;
138         }
139          else  if(notify == 2)
140         {
141              break;
142         }
143          else
144         {
145              continue;
146         }
147     }
148 
149     obj->PlayOver();
150 
151      return 0;
152 }
153 
154  int CDSoundObject::Play()
155 {
156      if(_dwPlayPos == 0)
157     {
158         InitDSData();
159     }
160 
161     _pDSBuffer->SetCurrentPosition(_dwPlayPos);
162     _pDSBuffer->SetVolume(-2000); // DSBVOLUME_MAX);
163      _pDSBuffer->Play(0, 0, DSBPLAY_LOOPING);
164 
165      return 0;
166 }
167 
168  int CDSoundObject::Pause()
169 {
170      if(_pDSBuffer == NULL)
171          return -1;
172     HRESULT hr = _pDSBuffer->GetCurrentPosition(&_dwPlayPos, NULL);
173      if(hr != DS_OK)
174          return -1;
175     _pDSBuffer->Stop();
176 
177      return 0;
178 }
179 
180  int CDSoundObject::Stop()
181 {
182      if(_pDSBuffer == NULL)
183          return -1;
184     _pDSBuffer->Stop();
185     _dwPlayPos = 0;
186 
187      return 0;
188 }
189 
190  bool CDSoundObject::IsPlaying()  const
191 {
192      if(_pDSBuffer == NULL)
193          return  false;
194 
195     DWORD status = 0;
196     HRESULT hr = _pDSBuffer->GetStatus(&status);
197      if(hr != DS_OK)
198          return  false;
199      return ((status & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING ?  true :  false);
200 }
201 
202  int CDSoundObject::PlayOver()
203 {
204      return Stop();
205 }
206 
207 
    DSMP3Object.h
 1 #ifndef __DSMP3OBJECT_H__
 2  #define __DSMP3OBJECT_H__
 3 
 4 #include <fstream>
 5 #include < string>
 6 
 7 #include "mpg123.h"
 8 
 9 #include "DSoundObject.h"
10 
11  class CDSMP3Object :  public CDSoundObject
12 {
13  public:
14     CDSMP3Object();
15      virtual ~CDSMP3Object();
16     
17      virtual  int LoadFile( const std:: string& file);
18      virtual  double Duration();
19  protected:
20      virtual  void Release();
21      virtual  int CreateDSoundBuffer();
22 
23      virtual  int InitDSData();
24      virtual  int LoadDSData(DWORD start, DWORD count);
25  private:
26     mpg123_handle* _handle;
27     unsigned  char _buffer[SIZE_DS_BUFFER / 2];
28     WAVEFORMATEX _fmtWave;
29 };
30 
31  #endif
32 
    DSMP3Object.cpp
  1 #include "DSMP3Object.h"
  2 
  3 CDSMP3Object::CDSMP3Object()
  4 : CDSoundObject(CDSoundObject::ST_MP3)
  5 , _handle(NULL)
  6 {
  7 }
  8 
  9 CDSMP3Object::~CDSMP3Object()
 10 {
 11     Release();
 12 }
 13 
 14  void CDSMP3Object::Release()
 15 {
 16      if(_handle != NULL)
 17     {
 18         mpg123_close(_handle);
 19         mpg123_delete(_handle);
 20         _handle = NULL;
 21         mpg123_exit();
 22     }
 23 }
 24 
 25  int CDSMP3Object::LoadFile( const std:: string &file)
 26 {
 27     Release();
 28 
 29      if(mpg123_init() != MPG123_OK)
 30          return -1;
 31      int ret = -1;
 32     _handle = mpg123_new(NULL, &ret);
 33      if(_handle == NULL || ret != MPG123_OK)
 34          return -1;
 35 
 36      if(mpg123_open(_handle, file.c_str()) != MPG123_OK)
 37          return -1;
 38 
 39      if(CreateDSoundBuffer() != 0)
 40          return -1;
 41 
 42      return 0;
 43 }
 44 
 45  int CDSMP3Object::CreateDSoundBuffer()
 46 {
 47     CDSoundObject::CreateDSoundBuffer();
 48 
 49      long rate = 0;
 50      int channel = 0;
 51      int encoding = 0;
 52 
 53      if(mpg123_getformat(_handle, &rate, &channel, &encoding) != MPG123_OK)
 54          return -1;
 55      if((encoding & MPG123_ENC_16) == MPG123_ENC_16)
 56         encoding = 16;
 57      else  if((encoding & MPG123_ENC_32) == MPG123_ENC_32)
 58         encoding = 32;
 59      else
 60         encoding = 8;
 61 
 62     memset(&_fmtWave, 0,  sizeof(WAVEFORMATEX));
 63     _fmtWave.wFormatTag = WAVE_FORMAT_PCM;
 64     _fmtWave.nChannels = channel;
 65     _fmtWave.nSamplesPerSec = rate;
 66     _fmtWave.wBitsPerSample = encoding;
 67     _fmtWave.nBlockAlign = encoding / 8 * channel;
 68     _fmtWave.nAvgBytesPerSec = rate * (encoding / 8) * channel;
 69     
 70     DSBUFFERDESC desc;
 71     memset(&desc, 0,  sizeof(DSBUFFERDESC));
 72     desc.dwSize =  sizeof(DSBUFFERDESC);
 73     desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
 74     desc.dwBufferBytes = CDSoundObject::SIZE_DS_BUFFER;
 75     desc.lpwfxFormat = &_fmtWave;
 76 
 77      if(_pDSBuffer != NULL)
 78         _pDSBuffer->Release();
 79 
 80     HRESULT hr = _pDS->CreateSoundBuffer(&desc, &_pDSBuffer, NULL);
 81      if(hr != DS_OK)
 82          return -1;
 83     
 84      return 0;
 85 }
 86 
 87  int CDSMP3Object::InitDSData()
 88 {
 89      // if(mpg123_seek(_handle, 0, SEEK_SET) < 0)
 90       //     return -1;
 91      off_t s = mpg123_seek(_handle, 0, SEEK_SET);
 92      if(s < 0)
 93          return -1;
 94 
 95      if(LoadDSData(0, CDSoundObject::SIZE_DS_BUFFER) != 0)
 96          return -1;
 97 
 98      if(CreateNotifyThread() != 0)
 99          return -1;
100 
101  //     _dwPlayPos = 0;
102 
103      return 0;
104 }
105 
106  int CDSMP3Object::LoadDSData(DWORD start, DWORD count)
107 {
108     LPVOID aptr1 = NULL, aptr2 = NULL;
109     DWORD abyte1 = NULL, abyte2 = NULL;
110 
111     HRESULT hr = _pDSBuffer->Lock(start, count, &aptr1, &abyte1, &aptr2, &abyte2, 0);
112      if(hr != DS_OK)
113          return -1;
114 
115     size_t outsize = 0;
116      if(mpg123_read(_handle, _buffer, SIZE_DS_BUFFER / 2, &outsize) != MPG123_OK)
117          return -1;
118 
119     memcpy(aptr1, _buffer, outsize);
120      if(aptr2 != 0)
121     {
122          if(mpg123_read(_handle, _buffer, SIZE_DS_BUFFER / 2, &outsize) != MPG123_OK)
123              return -1;
124         memcpy(aptr2, _buffer, outsize);
125     }
126 
127     _pDSBuffer->Unlock(aptr1, abyte1, aptr2, abyte2);
128 
129      return 0;
130 }
131 
132  double CDSMP3Object::Duration()
133 {
134     off_t len = mpg123_length(_handle);
135      return (len / _fmtWave.nSamplesPerSec);
136 }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值