1 #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
20 class CWaveFile {
21 public:
22 BOOL Open(const char path[]);
23 void Close();
24
25 long Read(char* pData, long nLength);
26
GetLength() const27 long GetLength() const {return m_nLength;}
GetWaveFormat()28 WAVEFORMATEX* GetWaveFormat() {return (&m_Format);}
29
30 protected:
31 FILE* m_pFile;
32 long m_nLength;
33 WAVEFORMATEX m_Format;
34
35 private:
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
Open(const char path[])49 BOOL 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
Close()93 void CWaveFile::Close()
94 {
95 fclose(m_pFile);
96 }
97
Read(char * pData,long nLength)98 long CWaveFile::Read(char* pData, long nLength)
99 {
100 return fread(pData, 1, nLength, m_pFile);
101 }
102
103 ////////////////////////////////////////////////////////////////////////////////////////
104
105 struct SkOSSoundWave {
106 HWAVEOUT hwo;
107 WAVEHDR whdr;
108 DWORD dwOldVolume;
109 CWaveFile waveFile;
110 HANDLE hDoneEvent;
111 };
112
113 static SkOSSoundWave gWave;
114 static bool gWavePaused;
115 static U8 gVolume;
116 static bool gInited = false;
117
init_wave()118 static void init_wave()
119 {
120 if (gInited == false)
121 {
122 gWave.hwo = NULL;
123 gWavePaused = false;
124 gVolume = 0x80;
125 gInited = true;
126 }
127 }
128
129 MMRESULT StartWave(const char path[], SkOSSoundWave* wave, U32 vol);
130 MMRESULT EndWave(SkOSSoundWave* wave);
131
132 #define MAX_ERRMSG 256
133
134 //#include "SkOSFile.h" // for utf16
135
Play(const char path[])136 void SkOSSound::Play(const char path[])
137 {
138 init_wave();
139
140 if (gWave.hwo != NULL)
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
TogglePause()150 bool SkOSSound::TogglePause()
151 {
152 init_wave();
153
154 if (gWavePaused)
155 SkOSSound::Resume();
156 else
157 SkOSSound::Pause();
158 return !gWavePaused;
159 }
160
161
Pause()162 void SkOSSound::Pause()
163 {
164 init_wave();
165
166 if (gWave.hwo == NULL || (gWave.whdr.dwFlags & WHDR_DONE))
167 return;
168 waveOutPause(gWave.hwo);
169 gWavePaused = true;
170 }
171
Resume()172 void SkOSSound::Resume()
173 {
174 init_wave();
175
176 if (gWave.hwo == NULL || (gWave.whdr.dwFlags & WHDR_DONE))
177 return;
178 waveOutRestart(gWave.hwo);
179 gWavePaused = false;
180 }
181
Stop()182 void SkOSSound::Stop()
183 {
184 init_wave();
185
186 // if (gWave.hwo == NULL || (gWave.whdr.dwFlags & WHDR_DONE))
187 if (gWave.hwo == NULL)
188 return;
189 waveOutReset(gWave.hwo);
190 EndWave(&gWave);
191 gWavePaused = false;
192 gWave.hwo = NULL;
193 }
194
GetVolume()195 U8 SkOSSound::GetVolume()
196 {
197 init_wave();
198 return gVolume;
199 }
200
SetVolume(U8CPU vol)201 void 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
220 unsigned long SoundManager::GetPosition()
221 {
222 if (fWave.hwo == NULL)
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
StartWave(const char path[],SkOSSoundWave * wave,U32 vol)235 MMRESULT StartWave(const char path[], SkOSSoundWave* wave, U32 vol)
236 {
237 HWAVEOUT hwo = NULL;
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
307 void 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
EndWave(SkOSSoundWave * wave)316 MMRESULT 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
344