Codejie's C++ Space

Using C++

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


posted on 2009-03-23 22:49 codejie 阅读(577) 评论(0)  编辑 收藏 引用 所属分类: C++


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


公告

Using C++

导航

统计

留言簿(73)

随笔分类(513)

积分与排名

最新评论

阅读排行榜

评论排行榜