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