Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
8.6 KiB

  1. #include "precomp.h"
  2. #include "WaveDev.h"
  3. #include "WaveIo.h"
  4. // utility function for both waveIndev and waveOutdev
  5. // builds a PCM WaveFormatEx structure for a given sampling rate and size
  6. static MMRESULT MakeWaveFormat(WAVEFORMATEX *pWF, int hertz, int bps)
  7. {
  8. WAVEFORMATEX waveFormat;
  9. if ((bps != 8) && (bps != 16))
  10. {
  11. return WAVERR_BADFORMAT;
  12. }
  13. waveFormat.wFormatTag = WAVE_FORMAT_PCM;
  14. waveFormat.nChannels = 1;
  15. waveFormat.nSamplesPerSec = hertz;
  16. waveFormat.nAvgBytesPerSec = hertz * bps/8;
  17. waveFormat.nBlockAlign = bps/8;
  18. waveFormat.wBitsPerSample = (WORD)bps;
  19. waveFormat.cbSize = 0;
  20. *pWF = waveFormat;
  21. return MMSYSERR_NOERROR;
  22. }
  23. waveInDev::waveInDev(UINT uDevId, HANDLE hEvent) :
  24. m_devID(uDevId), m_hwi(NULL), m_bOpen(FALSE), m_fAllowMapper(TRUE),
  25. m_hEvent(hEvent)
  26. {
  27. ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
  28. return;
  29. }
  30. waveInDev::~waveInDev()
  31. {
  32. Close();
  33. }
  34. MMRESULT waveInDev::Open(int hertz, int bps)
  35. {
  36. MMRESULT mmr;
  37. WAVEFORMATEX waveFormat;
  38. DWORD dwCallbackType = (m_hEvent ? CALLBACK_EVENT : CALLBACK_NULL );
  39. if (m_bOpen == TRUE)
  40. return MMSYSERR_NOERROR;
  41. mmr = MakeWaveFormat(&waveFormat, hertz, bps);
  42. if (mmr != MMSYSERR_NOERROR)
  43. {
  44. return mmr;
  45. }
  46. mmr = waveInOpen(&m_hwi, m_devID, &waveFormat, (DWORD_PTR)m_hEvent, 0, dwCallbackType);
  47. // begin hack, try to open wave_mapper
  48. // this may end up opening a different device!
  49. if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper))
  50. {
  51. mmr = waveInOpen(&m_hwi, WAVE_MAPPER, &waveFormat, (DWORD_PTR)m_hEvent,
  52. 0, dwCallbackType);
  53. }
  54. if (mmr == MMSYSERR_NOERROR)
  55. m_bOpen = TRUE;
  56. waveInStart(m_hwi);
  57. m_waveFormat = waveFormat;
  58. return mmr;
  59. }
  60. MMRESULT waveInDev::PrepareHeader(WAVEHDR *pWaveHdr)
  61. {
  62. MMRESULT mmr;
  63. if (m_bOpen == FALSE)
  64. return MMSYSERR_INVALHANDLE;
  65. mmr = waveInPrepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
  66. return mmr;
  67. }
  68. MMRESULT waveInDev::UnPrepareHeader(WAVEHDR *pWaveHdr)
  69. {
  70. MMRESULT mmr;
  71. if (m_bOpen == FALSE)
  72. return MMSYSERR_INVALHANDLE;
  73. mmr = waveInUnprepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
  74. return mmr;
  75. }
  76. MMRESULT waveInDev::Reset()
  77. {
  78. MMRESULT mmr;
  79. if (m_bOpen == FALSE)
  80. return MMSYSERR_NOERROR;
  81. mmr = waveInReset(m_hwi);
  82. return mmr;
  83. }
  84. MMRESULT waveInDev::Close()
  85. {
  86. MMRESULT mmr;
  87. if (m_bOpen == FALSE)
  88. return MMSYSERR_NOERROR;
  89. waveInReset(m_hwi);
  90. mmr = waveInClose(m_hwi);
  91. if (mmr == MMSYSERR_NOERROR)
  92. m_bOpen = FALSE;
  93. return mmr;
  94. }
  95. MMRESULT waveInDev::Record(WAVEHDR *pHdr)
  96. {
  97. MMRESULT mmr;
  98. if (m_bOpen == FALSE)
  99. {
  100. return MMSYSERR_INVALHANDLE;
  101. }
  102. mmr = waveInAddBuffer(m_hwi, pHdr, sizeof(WAVEHDR));
  103. return mmr;
  104. }
  105. void waveInDev::AllowMapper(BOOL fAllowMapper)
  106. {
  107. m_fAllowMapper = fAllowMapper;
  108. }
  109. waveOutDev::waveOutDev(UINT uDevID, HWND hwnd)
  110. : m_devID(uDevID), m_hwo(NULL), m_bOpen(FALSE), m_hWnd(hwnd),
  111. m_pfBuffer(NULL), m_nBufferSize(0), m_fFileBufferValid(FALSE),
  112. m_fAllowMapper(TRUE)
  113. {
  114. ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
  115. ZeroMemory(m_szPlayFile, sizeof(m_szPlayFile));
  116. ZeroMemory(&m_waveHdr, sizeof(m_waveHdr));
  117. if (hwnd == NULL)
  118. {
  119. m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  120. if (m_hEvent == NULL)
  121. {
  122. ERROR_OUT(("waveOutDev::waveOutDev - Unable to create event"));
  123. }
  124. }
  125. else
  126. m_hEvent = NULL;
  127. }
  128. waveOutDev::~waveOutDev()
  129. {
  130. Close();
  131. if (m_hEvent)
  132. CloseHandle(m_hEvent);
  133. if (m_pfBuffer)
  134. LocalFree(m_pfBuffer);
  135. }
  136. MMRESULT waveOutDev::Open(int hertz, int bps)
  137. {
  138. MMRESULT mmr;
  139. WAVEFORMATEX waveFormat;
  140. mmr = MakeWaveFormat(&waveFormat, hertz, bps);
  141. if (mmr != MMSYSERR_NOERROR)
  142. {
  143. return mmr;
  144. }
  145. return Open(&waveFormat);
  146. }
  147. MMRESULT waveOutDev::Open(WAVEFORMATEX *pWaveFormat)
  148. {
  149. MMRESULT mmr;
  150. m_waveFormat = *pWaveFormat;
  151. if (m_bOpen == TRUE)
  152. return MMSYSERR_NOERROR;
  153. if (m_hWnd == NULL)
  154. {
  155. mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hEvent,
  156. 0, CALLBACK_EVENT);
  157. }
  158. else
  159. {
  160. mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hWnd,
  161. 0, CALLBACK_WINDOW);
  162. }
  163. // begin hack, try to open wave_mapper
  164. // this may end up opening a different device!
  165. if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper))
  166. {
  167. if (m_hWnd == NULL)
  168. {
  169. mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat,
  170. (DWORD_PTR)m_hEvent, 0, CALLBACK_EVENT);
  171. }
  172. else
  173. {
  174. mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat,
  175. (DWORD_PTR)m_hWnd, 0, CALLBACK_WINDOW);
  176. }
  177. }
  178. if (mmr == MMSYSERR_NOERROR)
  179. m_bOpen = TRUE;
  180. return mmr;
  181. }
  182. MMRESULT waveOutDev::Close()
  183. {
  184. MMRESULT mmr;
  185. if (m_bOpen == FALSE)
  186. return MMSYSERR_NOERROR;
  187. waveOutReset(m_hwo);
  188. if (m_waveHdr.dwFlags & WHDR_PREPARED)
  189. {
  190. waveOutUnprepareHeader(m_hwo, &m_waveHdr, sizeof(m_waveHdr));
  191. m_waveHdr.dwFlags = 0;
  192. }
  193. mmr = waveOutClose(m_hwo);
  194. if (mmr == MMSYSERR_NOERROR)
  195. m_bOpen = FALSE;
  196. else
  197. ERROR_OUT(("ATW:Close failed"));
  198. return mmr;
  199. }
  200. MMRESULT waveOutDev::PrepareHeader(WAVEHDR *pWhdr, SHORT *shBuffer, int numSamples)
  201. {
  202. MMRESULT mmr;
  203. if (m_bOpen == FALSE)
  204. return MMSYSERR_INVALHANDLE;
  205. // if shBuffer is not NULL, we assume the caller wants us to fill in the
  206. // WAVEHDR struct
  207. if (shBuffer)
  208. {
  209. ZeroMemory(pWhdr, sizeof(WAVEHDR));
  210. pWhdr->lpData = (LPSTR)shBuffer;
  211. pWhdr->dwBufferLength = numSamples * m_waveFormat.nBlockAlign;
  212. }
  213. mmr = waveOutPrepareHeader(m_hwo, pWhdr, sizeof(WAVEHDR));
  214. return mmr;
  215. }
  216. MMRESULT waveOutDev::UnprepareHeader(WAVEHDR *pWaveHdr)
  217. {
  218. MMRESULT mmr;
  219. if (m_bOpen == FALSE)
  220. return MMSYSERR_INVALHANDLE;
  221. mmr = waveOutUnprepareHeader(m_hwo, pWaveHdr, sizeof(WAVEHDR));
  222. return mmr;
  223. }
  224. MMRESULT waveOutDev::Play(WAVEHDR *pWaveHdr)
  225. {
  226. MMRESULT mmr;
  227. DWORD dwTimeOut;
  228. DWORD dwRet;
  229. int numSamples;
  230. if (m_bOpen == FALSE)
  231. return MMSYSERR_INVALHANDLE;
  232. if (m_hEvent)
  233. ResetEvent(m_hEvent);
  234. mmr = waveOutWrite(m_hwo, pWaveHdr, sizeof(WAVEHDR));
  235. if (mmr != MMSYSERR_NOERROR)
  236. return mmr;
  237. if (m_hEvent)
  238. {
  239. numSamples = pWaveHdr->dwBufferLength / m_waveFormat.nBlockAlign;
  240. dwTimeOut = 5 * ((1000 * numSamples) / m_waveFormat.nSamplesPerSec);
  241. dwRet = WaitForSingleObject(m_hEvent, dwTimeOut);
  242. if ((dwRet != WAIT_ABANDONED) && (dwRet != WAIT_OBJECT_0))
  243. {
  244. ERROR_OUT(("waveOutDev::Play() - WaitForSingleObject Failed"));
  245. return WAVERR_LASTERROR + 1;
  246. }
  247. }
  248. return MMSYSERR_NOERROR;
  249. }
  250. // File io errors or anything unexpected results in -1 being returned
  251. // Otherwise, returns the MMRESULT of the last waveOut call made
  252. MMRESULT waveOutDev::PlayFile(LPCTSTR szFileName)
  253. {
  254. MMRESULT mmr;
  255. WAVEIOCB waveiocb;
  256. WIOERR werr;
  257. DWORD dwSize;
  258. PCHAR pBuffer;
  259. // quick optimization
  260. // if the same file is being played twice in a row
  261. // the just replay the buffer
  262. if ((m_fFileBufferValid) && (0 == lstrcmp(szFileName, m_szPlayFile)))
  263. {
  264. Close();
  265. mmr = Open(&m_PlayFileWf);
  266. if (mmr == MMSYSERR_NOERROR)
  267. {
  268. mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer, m_nBufferSize / m_PlayFileWf.nBlockAlign);
  269. if (mmr == MMSYSERR_NOERROR)
  270. {
  271. mmr = Play(&m_waveHdr);
  272. }
  273. }
  274. m_fFileBufferValid = (mmr == MMSYSERR_NOERROR);
  275. return mmr;
  276. }
  277. ZeroMemory(&waveiocb, sizeof(waveiocb));
  278. werr = wioFileOpen(&waveiocb, szFileName, 0);
  279. if (werr == WIOERR_NOERROR)
  280. {
  281. // prepare to read the samples!
  282. // quick hack, if the file to play was the same as the last,
  283. // then use the same buffer
  284. m_fFileBufferValid = FALSE;
  285. if (m_pfBuffer == NULL)
  286. {
  287. m_pfBuffer = (char *)LocalAlloc(LPTR, waveiocb.dwDataBytes);
  288. }
  289. else
  290. {
  291. pBuffer = (char*)LocalReAlloc(m_pfBuffer, waveiocb.dwDataBytes, LMEM_MOVEABLE |LMEM_ZEROINIT);
  292. if(NULL != pBuffer)
  293. {
  294. m_pfBuffer = pBuffer;
  295. }
  296. else
  297. {
  298. // Failed to reallocate buffer, make sure to clean up
  299. LocalFree(m_pfBuffer);
  300. m_pfBuffer = NULL;
  301. }
  302. }
  303. if (m_pfBuffer == NULL)
  304. {
  305. wioFileClose(&waveiocb, 0);
  306. return -1;
  307. }
  308. // read
  309. mmioSeek(waveiocb.hmmio, waveiocb.dwDataOffset, SEEK_SET);
  310. dwSize = mmioRead(waveiocb.hmmio, m_pfBuffer, waveiocb.dwDataBytes);
  311. if (dwSize == 0)
  312. return -1;
  313. Close();
  314. mmr = Open(waveiocb.pwfx);
  315. if (mmr != MMSYSERR_NOERROR)
  316. {
  317. wioFileClose(&waveiocb, 0);
  318. return mmr;
  319. }
  320. // mmr = Play((short *)m_pfBuffer, dwSize / (waveiocb.pwfx)->nBlockAlign);
  321. mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer,
  322. dwSize / (waveiocb.pwfx)->nBlockAlign);
  323. if (mmr == MMSYSERR_NOERROR)
  324. {
  325. mmr = Play(&m_waveHdr);
  326. }
  327. m_fFileBufferValid = (mmr == MMSYSERR_NOERROR);
  328. if (m_fFileBufferValid)
  329. {
  330. m_PlayFileWf = *(waveiocb.pwfx);
  331. lstrcpy(m_szPlayFile, szFileName);
  332. m_nBufferSize = dwSize;
  333. }
  334. wioFileClose(&waveiocb, 0);
  335. return mmr;
  336. }
  337. return -1;
  338. }
  339. void waveOutDev::AllowMapper(BOOL fAllowMapper)
  340. {
  341. m_fAllowMapper = fAllowMapper;
  342. }