blob: 13cd037756b1b4dd7587a3d0f418c242f1c2a830 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkOSSound.h"
2
3#ifdef SK_BUILD_FOR_WIN
4
5//////////////////////////////////////////////////////////////////////
6// Construction/Destruction
7//////////////////////////////////////////////////////////////////////
8
9#include <Mmreg.h>
10#if defined _WIN32 && _MSC_VER >= 1300 // disable nameless struct/union
11#pragma warning ( push )
12#pragma warning ( disable : 4201 )
13#endif
14#include <Mmsystem.h>
15#if defined _WIN32 && _MSC_VER >= 1300
16#pragma warning ( pop )
17#endif
18#include <stdio.h>
19
20class CWaveFile {
21public:
22 BOOL Open(const char path[]);
23 void Close();
24
25 long Read(char* pData, long nLength);
26
27 long GetLength() const {return m_nLength;}
28 WAVEFORMATEX* GetWaveFormat() {return (&m_Format);}
29
30protected:
31 FILE* m_pFile;
32 long m_nLength;
33 WAVEFORMATEX m_Format;
34
35private:
36 enum {
37 WF_OFFSET_FORMATTAG = 20,
38 WF_OFFSET_CHANNELS = 22,
39 WF_OFFSET_SAMPLESPERSEC = 24,
40 WF_OFFSET_AVGBYTESPERSEC = 28,
41 WF_OFFSET_BLOCKALIGN = 32,
42 WF_OFFSET_BITSPERSAMPLE = 34,
43 WF_OFFSET_DATASIZE = 40,
44 WF_OFFSET_DATA = 44,
45 WF_HEADER_SIZE = WF_OFFSET_DATA
46 };
47};
48
49BOOL CWaveFile::Open(const char path[])
50{
51 BYTE aHeader[WF_HEADER_SIZE];
52
53/* hResInfo = FindResource (hInst, lpName, "WAVE");
54
55 if (hResInfo == NULL)
56 return FALSE;
57
58 // Load the wave resource.
59 hRes = LoadResource (hInst, hResInfo);
60
61 if (hRes == NULL)
62 return FALSE;
63
64 // Lock the wave resource and play it.
65 lpRes = LockResource (0);
66*/
67
68
69 // open file
70// m_pFile = _tfopen(szFileName, TEXT("rb"));
71 m_pFile = fopen(path, "rb");
72 if (!m_pFile) {
73 return FALSE;
74 }
75
76 // set file length
77 fseek(m_pFile, 0, SEEK_END);
78 m_nLength = ftell(m_pFile) - WF_HEADER_SIZE;
79
80 // set the format attribute members
81 fseek(m_pFile, 0, SEEK_SET);
82 fread(aHeader, 1, WF_HEADER_SIZE, m_pFile);
83 m_Format.wFormatTag = *((WORD*) (aHeader + WF_OFFSET_FORMATTAG));
84 m_Format.nChannels = *((WORD*) (aHeader + WF_OFFSET_CHANNELS));
85 m_Format.nSamplesPerSec = *((DWORD*) (aHeader + WF_OFFSET_SAMPLESPERSEC));
86 m_Format.nAvgBytesPerSec = *((DWORD*) (aHeader + WF_OFFSET_AVGBYTESPERSEC));
87 m_Format.nBlockAlign = *((WORD*) (aHeader + WF_OFFSET_BLOCKALIGN));
88 m_Format.wBitsPerSample = *((WORD*) (aHeader + WF_OFFSET_BITSPERSAMPLE));
89
90 return TRUE;
91}
92
93void CWaveFile::Close()
94{
95 fclose(m_pFile);
96}
97
98long CWaveFile::Read(char* pData, long nLength)
99{
100 return fread(pData, 1, nLength, m_pFile);
101}
102
103////////////////////////////////////////////////////////////////////////////////////////
104
105struct SkOSSoundWave {
106 HWAVEOUT hwo;
107 WAVEHDR whdr;
108 DWORD dwOldVolume;
109 CWaveFile waveFile;
110 HANDLE hDoneEvent;
111};
112
113static SkOSSoundWave gWave;
114static bool gWavePaused;
115static U8 gVolume;
116static bool gInited = false;
117
118static void init_wave()
119{
120 if (gInited == false)
121 {
122 gWave.hwo = nil;
123 gWavePaused = false;
124 gVolume = 0x80;
125 gInited = true;
126 }
127}
128
129MMRESULT StartWave(const char path[], SkOSSoundWave* wave, U32 vol);
130MMRESULT EndWave(SkOSSoundWave* wave);
131
132#define MAX_ERRMSG 256
133
134//#include "SkOSFile.h" // for utf16
135
136void SkOSSound::Play(const char path[])
137{
138 init_wave();
139
140 if (gWave.hwo != nil)
141 SkOSSound::Stop();
142
143 U32 v32 = (gVolume << 8) | gVolume; // fill it out to 16bits
144 v32 |= v32 << 16; // set the left and right channels
145
146 StartWave(path, &gWave, v32);
147 gWavePaused = false;
148}
149
150bool SkOSSound::TogglePause()
151{
152 init_wave();
153
154 if (gWavePaused)
155 SkOSSound::Resume();
156 else
157 SkOSSound::Pause();
158 return !gWavePaused;
159}
160
161
162void SkOSSound::Pause()
163{
164 init_wave();
165
166 if (gWave.hwo == nil || (gWave.whdr.dwFlags & WHDR_DONE))
167 return;
168 waveOutPause(gWave.hwo);
169 gWavePaused = true;
170}
171
172void SkOSSound::Resume()
173{
174 init_wave();
175
176 if (gWave.hwo == nil || (gWave.whdr.dwFlags & WHDR_DONE))
177 return;
178 waveOutRestart(gWave.hwo);
179 gWavePaused = false;
180}
181
182void SkOSSound::Stop()
183{
184 init_wave();
185
186// if (gWave.hwo == nil || (gWave.whdr.dwFlags & WHDR_DONE))
187 if (gWave.hwo == nil)
188 return;
189 waveOutReset(gWave.hwo);
190 EndWave(&gWave);
191 gWavePaused = false;
192 gWave.hwo = nil;
193}
194
195U8 SkOSSound::GetVolume()
196{
197 init_wave();
198 return gVolume;
199}
200
201void SkOSSound::SetVolume(U8CPU vol)
202{
203 if ((int)vol < 0)
204 vol = 0;
205 else if (vol > 255)
206 vol = 255;
207
208 init_wave();
209 gVolume = SkToU8(vol);
210
211 if (gWave.hwo)
212 {
213 unsigned long v32 = (vol << 8) | vol; // fill it out to 16bits
214 v32 |= v32 << 16; // set the left and right channels
215 waveOutSetVolume(gWave.hwo, v32);
216 }
217}
218
219#if 0
220unsigned long SoundManager::GetPosition()
221{
222 if (fWave.hwo == nil)
223 return 0;
224 MMTIME time;
225 time.wType = TIME_MS;
226 if (waveOutGetPosition(fWave.hwo, &time, sizeof(time)) == MMSYSERR_NOERROR &&
227 time.wType == TIME_MS)
228 {
229 return time.u.ms;
230 }
231 return 0;
232}
233#endif
234
235MMRESULT StartWave(const char path[], SkOSSoundWave* wave, U32 vol)
236{
237 HWAVEOUT hwo = nil;
238// WAVEHDR whdr;
239 MMRESULT mmres = 0;
240// CWaveFile waveFile;
241// HANDLE hDoneEvent = wave.hDoneEvent =
242// CreateEvent(NULL, FALSE, FALSE, TEXT("DONE_EVENT"));
243 UINT devId;
244// DWORD dwOldVolume;
245
246 // Open wave file
247 if (!wave->waveFile.Open(path)) {
248// TCHAR szErrMsg[MAX_ERRMSG];
249// _stprintf(szErrMsg, TEXT("Unable to open file: %s\n"), szWavFile);
250// MessageBox(NULL, szErrMsg, TEXT("File I/O Error"), MB_OK);
251 return MMSYSERR_NOERROR;
252 }
253
254 // Open audio device
255 for (devId = 0; devId < waveOutGetNumDevs(); devId++)
256 {
257 mmres = waveOutOpen(&hwo, devId, wave->waveFile.GetWaveFormat(), 0, 0, CALLBACK_NULL);
258 if (mmres == MMSYSERR_NOERROR)
259 {
260 wave->hwo = hwo;
261 break;
262 }
263 }
264 if (mmres != MMSYSERR_NOERROR)
265 {
266 SkDEBUGCODE(SkDebugf("waveOutOpen(%s) -> %d\n", path, mmres);)
267 return mmres;
268 }
269
270 // Set volume
271 mmres = waveOutGetVolume(hwo, &wave->dwOldVolume);
272 if (mmres != MMSYSERR_NOERROR) {
273 return mmres;
274 }
275
276 waveOutSetVolume(hwo, vol);
277 if (mmres != MMSYSERR_NOERROR) {
278 return mmres;
279 }
280
281 // Initialize wave header
282 ZeroMemory(&wave->whdr, sizeof(WAVEHDR));
283 wave->whdr.lpData = new char[wave->waveFile.GetLength()];
284 wave->whdr.dwBufferLength = wave->waveFile.GetLength();
285 wave->whdr.dwUser = 0;
286 wave->whdr.dwFlags = 0;
287 wave->whdr.dwLoops = 0;
288 wave->whdr.dwBytesRecorded = 0;
289 wave->whdr.lpNext = 0;
290 wave->whdr.reserved = 0;
291
292 // Play buffer
293 wave->waveFile.Read(wave->whdr.lpData, wave->whdr.dwBufferLength);
294
295 mmres = waveOutPrepareHeader(hwo, &wave->whdr, sizeof(WAVEHDR));
296 if (mmres != MMSYSERR_NOERROR) {
297 return mmres;
298 }
299
300 mmres = waveOutWrite(hwo, &wave->whdr, sizeof(WAVEHDR));
301// if (mmres != MMSYSERR_NOERROR) {
302 return mmres;
303// }
304}
305
306#if 0
307void IdleWave(Wave& wave)
308{
309 // Wait for audio to finish playing
310 while (!(wave.whdr.dwFlags & WHDR_DONE)) {
311 WaitForSingleObject(wave.hDoneEvent, INFINITE);
312 }
313}
314#endif
315
316MMRESULT EndWave(SkOSSoundWave* wave)
317{
318 HWAVEOUT hwo = wave->hwo;
319 MMRESULT mmres;
320 // Clean up
321 mmres = waveOutUnprepareHeader(hwo, &wave->whdr, sizeof(WAVEHDR));
322 if (mmres != MMSYSERR_NOERROR) {
323 return mmres;
324 }
325
326 waveOutSetVolume(hwo, wave->dwOldVolume);
327 if (mmres != MMSYSERR_NOERROR) {
328 return mmres;
329 }
330
331 mmres = waveOutClose(hwo);
332 if (mmres != MMSYSERR_NOERROR) {
333 return mmres;
334 }
335
336 delete [] wave->whdr.lpData;
337 wave->waveFile.Close();
338
339 return MMSYSERR_NOERROR;
340}
341
342#endif /* SK_BUILD_FOR_WIN */
343