将对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 }