Codejie's C++ Space

Using C++

使用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)this0&_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(00, 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, 0sizeof(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, 0sizeof(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 }



posted on 2009-03-26 10:57 codejie 阅读(5981) 评论(8)  编辑 收藏 引用 所属分类: C++

评论

# re: 使用DirectSound播放MP3文件 2009-12-07 19:51 chl

你好,看了你的DS播放MP3的代码,我也是在写这个相关代码,第一次接触声音部分,看了你的代码很有收获,想问你,mpg123_read就可以把MP3转化为WAV的了吗?还有就是你有mpg123的源码吗?可以发给我吗?我的QQ:84818557,邮箱84818557@qq.com,看到消息给我回复好吗,谢谢。  回复  更多评论   

# re: 使用DirectSound播放MP3文件[未登录] 2009-12-07 21:40 codejie

@chl
我想你需要的都在http://www.mpg123.de/api/  回复  更多评论   

# re: 使用DirectSound播放MP3文件 2009-12-08 21:13 chl

我已经解决了,还是很 感谢你,以后多交流,我的声音系统也完成了。  回复  更多评论   

# re: 使用DirectSound播放MP3文件 2009-12-09 09:30 codejie

@chl
GX  回复  更多评论   

# re: 使用DirectSound播放MP3文件 2010-01-24 13:58 kun

能把 vs下 编译libmpg的sln给我?(kunooo@qq.com)  回复  更多评论   

# re: 使用DirectSound播放MP3文件[未登录] 2010-01-24 14:48 codejie

@kun
mpg库到http://www.mpg123.de/下载就可以了。  回复  更多评论   

# re: 使用DirectSound播放MP3文件 2011-07-02 20:28 huangdi

好像不能播放。只能播放开头一点点  回复  更多评论   

# re: 使用DirectSound播放MP3文件 2011-07-04 10:39 codejie

@huangdi
啊,我都忘记这个了。。看了半天,如果是这样,那应该是‘循环’加载数据时没有算准‘位置’。辛苦你多试试了。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

Using C++

导航

统计

留言簿(73)

随笔分类(513)

积分与排名

最新评论

阅读排行榜

评论排行榜