修改了一下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