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
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 = NULL;
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 != 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
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 == NULL || (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 == NULL || (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 == 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
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 == 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
235MMRESULT 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
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
344