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 27 long GetLength() const {return m_nLength;} 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 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 93 void CWaveFile::Close() 94 { 95 fclose(m_pFile); 96 } 97 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 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 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 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 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 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 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 195 U8 SkOSSound::GetVolume() 196 { 197 init_wave(); 198 return gVolume; 199 } 200 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 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 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