Windows NT 4.0 source code leak
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.

994 lines
26 KiB

4 years ago
  1. /**********************************************************************
  2. Copyright (C) 1992-1993 Microsoft Corporation. All Rights Reserved.
  3. modfix.c
  4. DESCRIPTION:
  5. Fixed code for doing output mapping. KEEP THE SIZE OF THIS CODE
  6. TO A MINIMUM!
  7. HISTORY:
  8. 02/22/94 [jimge] created.
  9. *********************************************************************/
  10. #pragma warning(disable:4704)
  11. #include "preclude.h"
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #include <mmsystem.h>
  15. #include <mmddk.h>
  16. #include "idf.h"
  17. #include "midimap.h"
  18. #include "debug.h"
  19. extern HANDLE hMutexRefCnt; // Located in DRVPROC.C
  20. extern HANDLE hMutexConfig; // Located in DRVPROC.C
  21. #define MSG_UNKNOWN 0
  22. #define MSG_SHORT 1
  23. #define MSG_LONG 2
  24. INT FNLOCAL MapEvent (
  25. BYTE * pStatus,
  26. DWORD dwBuffSize,
  27. DWORD * pSkipBytes,
  28. DWORD * pShortMsg);
  29. DWORD FNLOCAL modMapLongMsg (
  30. PINSTANCE pinstance,
  31. LPMIDIHDR lpmh);
  32. /***************************************************************************
  33. @doc internal
  34. @api int | modMessage | Exported entry point for MIDI out messages.
  35. This function conforms to the definition in the MM DDK.
  36. @parm UINT | uid | Device ID within driver to open. For mapper, this
  37. should always be zero.
  38. @parm UINT | umsg | Message to process. This should be one of the
  39. #define'd MODM_xxx messages.
  40. @parm DWORD | dwUser | Points to a DWORD where the driver (us) can
  41. save instance data. This will store the near pointer to our
  42. instance. On every other message, this will contain the instance
  43. data.
  44. @parm DWORD | dwParam1 | Message specific parameters.
  45. @parm DWORD | dwParam2 | Message specific parameters.
  46. @comm This function MUST be in a fixed segment since short messages
  47. are allowed to be sent at interrupt time.
  48. @rdesc | MMSYSERR_xxx.
  49. ***************************************************************************/
  50. DWORD FNEXPORT modMessage(
  51. UINT uid,
  52. UINT umsg,
  53. DWORD dwUser,
  54. DWORD dwParam1,
  55. DWORD dwParam2)
  56. {
  57. BYTE bs;
  58. PINSTANCE pinstance;
  59. // UINT uDeviceID;
  60. PPORT pport;
  61. MMRESULT mmrc;
  62. MMRESULT mmrc2;
  63. DWORD dwResult;
  64. if (0 != uid)
  65. {
  66. DPF(1, TEXT ("Mapper called with non-zero uid!"));
  67. return MMSYSERR_BADDEVICEID;
  68. }
  69. pinstance = (PINSTANCE)(UINT)(dwUser);
  70. switch(umsg)
  71. {
  72. case MODM_GETDEVCAPS:
  73. return modGetDevCaps((LPMIDIOUTCAPS)dwParam1,
  74. dwParam2);
  75. case MODM_OPEN:
  76. return modOpen((LPDWORD)dwUser,
  77. (LPMIDIOPENDESC)dwParam1,
  78. dwParam2);
  79. case MODM_CLOSE:
  80. return modClose((PINSTANCE)dwUser);
  81. case MODM_DATA:
  82. assert(NULL != pinstance);
  83. // In cooked mode, don't allow non-status short messages.
  84. // Otherwise (packed mode) maintain running status.
  85. //
  86. // TESTTEST -- Make sure running status works properly in
  87. // MIDI_IO_PACKED - essential for backwards compatibility!!!
  88. //
  89. bs = MSG_STATUS(dwParam1);
  90. if (pinstance->fdwOpen & MIDI_IO_COOKED)
  91. {
  92. bs = MSG_STATUS(dwParam1);
  93. if (!IS_STATUS(bs))
  94. {
  95. DPF(1, TEXT ("Non-status short msg while opened in MIDI_IO_COOKED!"));
  96. return MMSYSERR_INVALPARAM;
  97. }
  98. }
  99. else
  100. {
  101. // Track running status
  102. //
  103. if (IS_STATUS(bs))
  104. pinstance->bRunningStatus = bs;
  105. else
  106. dwParam1 = (dwParam1 << 8) | (pinstance->bRunningStatus);
  107. }
  108. return MapSingleEvent((PINSTANCE)dwUser,
  109. dwParam1,
  110. MSE_F_SENDEVENT,
  111. NULL);
  112. case MODM_LONGDATA:
  113. assert(NULL != pinstance);
  114. // return modLongMsg(pinstance, (LPMIDIHDR)dwParam1);
  115. return modMapLongMsg (pinstance, (LPMIDIHDR)dwParam1);
  116. case MODM_PREPARE:
  117. assert(NULL != pinstance);
  118. return modPrepare((LPMIDIHDR)dwParam1);
  119. case MODM_UNPREPARE:
  120. assert(NULL != pinstance);
  121. return modUnprepare((LPMIDIHDR)dwParam1);
  122. case MODM_GETVOLUME:
  123. if (!IS_ALLOWVOLUME)
  124. return MMSYSERR_NOTSUPPORTED;
  125. *(LPDWORD)dwParam1 = gdwVolume;
  126. return MMSYSERR_NOERROR;
  127. case MODM_SETVOLUME:
  128. if (!IS_ALLOWVOLUME)
  129. return MMSYSERR_NOTSUPPORTED;
  130. gdwVolume = dwParam1;
  131. if (ghMidiStrm)
  132. return midiOutSetVolume((HMIDIOUT)ghMidiStrm, dwParam1);
  133. return modSetVolume(dwParam1);
  134. case MODM_PROPERTIES:
  135. assert(NULL != pinstance);
  136. return midiStreamProperty(ghMidiStrm, (LPVOID)dwParam1, dwParam2);
  137. case MODM_STRMDATA:
  138. assert(NULL != pinstance);
  139. return MapCookedBuffer(pinstance, (LPMIDIHDR)dwParam1);
  140. case MODM_RESET:
  141. assert(NULL != pinstance);
  142. if (ghMidiStrm)
  143. return midiOutReset((HMIDIOUT)ghMidiStrm);
  144. mmrc = MMSYSERR_NOERROR;
  145. for (pport = gpportList; pport; pport=pport->pNext)
  146. if (MMSYSERR_NOERROR != (mmrc2 =
  147. midiOutReset(pport->hmidi)))
  148. mmrc = mmrc2;
  149. return mmrc;
  150. case MODM_GETPOS:
  151. assert(NULL != pinstance);
  152. return modGetPosition((PINSTANCE)pinstance,
  153. (LPMMTIME)dwParam1,
  154. dwParam2 /* cbmmtime */);
  155. case MODM_PAUSE:
  156. assert(NULL != pinstance);
  157. return midiStreamPause(ghMidiStrm);
  158. case MODM_RESTART:
  159. assert(NULL != pinstance);
  160. return midiStreamRestart(ghMidiStrm);
  161. case MODM_STOP:
  162. assert(NULL != pinstance);
  163. return midiStreamStop(ghMidiStrm);
  164. case MODM_CACHEPATCHES:
  165. assert(NULL != pinstance);
  166. if (!IS_ALLOWCACHE)
  167. return MMSYSERR_NOTSUPPORTED;
  168. if (ghMidiStrm)
  169. return midiOutCachePatches(
  170. (HMIDIOUT)ghMidiStrm, // hmidi
  171. HIWORD(dwParam2), // wBank
  172. (WORD FAR *)dwParam1, // lpPatchArray
  173. LOWORD(dwParam2)); // wFlags
  174. mmrc = MMSYSERR_NOERROR;
  175. for (pport = gpportList; pport; pport=pport->pNext)
  176. if (MMSYSERR_NOERROR != (mmrc2 =
  177. midiOutCachePatches(
  178. pport->hmidi, // hmidi
  179. HIWORD(dwParam2), // wBank
  180. (WORD FAR *)dwParam1, // lpPatchArray
  181. LOWORD(dwParam2))) && // wFlags
  182. MMSYSERR_NOTSUPPORTED != mmrc2)
  183. mmrc = mmrc2;
  184. return mmrc;
  185. case MODM_CACHEDRUMPATCHES:
  186. assert(NULL != pinstance);
  187. if (!IS_ALLOWCACHE)
  188. return MMSYSERR_NOTSUPPORTED;
  189. if (ghMidiStrm)
  190. return midiOutCacheDrumPatches(
  191. (HMIDIOUT)ghMidiStrm, // hmidi
  192. HIWORD(dwParam2), // wBank
  193. (WORD FAR *)dwParam1, // lpKeyArray
  194. LOWORD(dwParam2)); // wFlags
  195. mmrc = MMSYSERR_NOERROR;
  196. for (pport = gpportList; pport; pport=pport->pNext)
  197. if (MMSYSERR_NOERROR != (mmrc2 =
  198. midiOutCacheDrumPatches(
  199. pport->hmidi, // hmidi
  200. HIWORD(dwParam2), // wBank
  201. (WORD FAR *)dwParam1, // lpKeyArray
  202. LOWORD(dwParam2))) && // wFlags
  203. MMSYSERR_NOTSUPPORTED != mmrc2)
  204. mmrc = mmrc2;
  205. return mmrc;
  206. case DRVM_MAPPER_RECONFIGURE:
  207. // Prevent Synchronization problems
  208. // During Configuration
  209. if (INVALID_HANDLE_VALUE != hMutexConfig)
  210. WaitForSingleObject (hMutexConfig, INFINITE);
  211. DPF(2, TEXT ("DRV_RECONFIGURE"));
  212. dwResult = UpdateInstruments(TRUE, dwParam2);
  213. if (INVALID_HANDLE_VALUE != hMutexConfig)
  214. ReleaseMutex (hMutexConfig);
  215. return dwResult;
  216. }
  217. return MMSYSERR_NOTSUPPORTED;
  218. }
  219. /***************************************************************************
  220. @doc internal
  221. @api void | modmCallback | Callback for completion of sending of
  222. long messages. This function conforms to the definition in the SDK.
  223. @parm HMIDIOUT | hmo | The MMSYSTEM handle of the device which
  224. complete sending.
  225. @parm WORD | wmsg | Contains a MOM_xxx code signifying what event
  226. occurred. We only care about MOM_DONE.
  227. @parm DWORD | dwInstance | DWORD of instance data given at open time;
  228. this contains the PPORT which owns the handle.
  229. @parm DWORD | dwParam1 | Message specific parameters. For MOM_DONE,
  230. this contains a far pointer to the header which completed.
  231. @parm DWORD | dwParam2 | Message specific parameters. Contains
  232. nothinf for MOM_DONE.
  233. @comm This function MUST be in a fixed segment since the driver
  234. may call it at interrupt time.
  235. ***************************************************************************/
  236. void CALLBACK _loadds modmCallback(
  237. HMIDIOUT hmo,
  238. WORD wmsg,
  239. DWORD dwInstance,
  240. DWORD dwParam1,
  241. DWORD dwParam2)
  242. {
  243. LPMIDIHDR lpmhShadow;
  244. LPMIDIHDR lpmhUser;
  245. PINSTANCE pinstance;
  246. PSHADOWBLOCK psb;
  247. LPMIDIHDR31 lpmh31;
  248. BOOL fNeedCB = FALSE;
  249. lpmhShadow = (LPMIDIHDR)dwParam1;
  250. if (wmsg == MOM_DONE && lpmhShadow)
  251. {
  252. DPF(1, TEXT ("Callback: MOM_DONE"));
  253. pinstance = (PINSTANCE)(UINT)lpmhShadow->dwReserved[MH_MAPINST];
  254. lpmhUser = (LPMIDIHDR)lpmhShadow->dwReserved[MH_SHADOWEE];
  255. if (ghMidiStrm)
  256. fNeedCB = TRUE;
  257. else
  258. {
  259. lpmh31 = (LPMIDIHDR31)lpmhUser;
  260. psb = (PSHADOWBLOCK)(UINT)lpmh31->reserved;
  261. if (0 == --psb->cRefCnt && !(lpmh31->dwFlags & MHDR_SENDING))
  262. fNeedCB = TRUE;
  263. }
  264. if (fNeedCB)
  265. {
  266. DPF(1, TEXT ("Callback: Propogating"));
  267. lpmhUser->dwFlags |= MHDR_DONE;
  268. lpmhUser->dwFlags &= ~MHDR_INQUEUE;
  269. DriverCallback(
  270. pinstance->dwCallback,
  271. HIWORD(pinstance->fdwOpen),
  272. (HANDLE)pinstance->hmidi,
  273. MM_MOM_DONE,
  274. pinstance->dwInstance,
  275. (DWORD)lpmhUser,
  276. 0L);
  277. }
  278. }
  279. else if (wmsg == MOM_POSITIONCB && lpmhShadow)
  280. {
  281. pinstance = (PINSTANCE)(UINT)lpmhShadow->dwReserved[MH_MAPINST];
  282. lpmhUser = (LPMIDIHDR)lpmhShadow->dwReserved[MH_SHADOWEE];
  283. if (!ghMidiStrm)
  284. {
  285. DPF(0, TEXT ("Got MOM_POSITIONCB on non-stream handle?"));
  286. return;
  287. }
  288. lpmhUser->dwOffset = lpmhShadow->dwOffset;
  289. DriverCallback(
  290. pinstance->dwCallback,
  291. HIWORD(pinstance->fdwOpen),
  292. (HANDLE)pinstance->hmidi,
  293. MM_MOM_POSITIONCB,
  294. pinstance->dwInstance,
  295. (DWORD)lpmhUser,
  296. 0L);
  297. }
  298. }
  299. /***************************************************************************
  300. @doc internal
  301. @api DWORD | MapSingleEvent | Map and possibly send a short message.
  302. @parm PINSTANCE | pinstance | Pointer to an open instance.
  303. @parm DWORD | dwData | Contains the short message to transmit.
  304. @parm DWORD | fdwFlags | One of the the following values:
  305. @flag MSE_F_SENDEVENT | Send the event to the physical channel
  306. @flag MSE_F_RETURNEVENT | Return the event to be re-packed into
  307. a buffer.
  308. @comm Running status should be taken care of before we get
  309. called.
  310. @rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
  311. mapped event if no error, 0L on error.
  312. ***************************************************************************/
  313. DWORD FNGLOBAL MapSingleEvent(
  314. PINSTANCE pinstance,
  315. DWORD dwData,
  316. DWORD fdwFlags,
  317. DWORD BSTACK * pdwStreamID)
  318. {
  319. BYTE bMsg;
  320. BYTE bChan;
  321. BYTE b1;
  322. BYTE b2;
  323. PCHANNEL pchannel;
  324. MMRESULT mmr;
  325. // Extract message type and channel number.
  326. //
  327. bMsg = MSG_STATUS(dwData);
  328. bChan = MSG_CHAN(bMsg);
  329. bMsg = MSG_EVENT(bMsg);
  330. if (MIDI_SYSEX == bMsg)
  331. return !(fdwFlags & MSE_F_RETURNEVENT) ? MMSYSERR_NOERROR : (((DWORD)MEVT_NOP)<<24);
  332. // BUGBUG -- invalid if this is SysEx!
  333. //
  334. if (NULL == (pchannel = gapChannel[bChan]))
  335. return !(fdwFlags & MSE_F_RETURNEVENT) ? MMSYSERR_NOERROR : (((DWORD)MEVT_NOP)<<24);
  336. bChan = (BYTE)pchannel->uChannel;
  337. if (pdwStreamID)
  338. *pdwStreamID = pchannel->dwStreamID;
  339. switch(bMsg)
  340. {
  341. case MIDI_NOTEOFF:
  342. case MIDI_NOTEON:
  343. b1 = MSG_PARM1(dwData);
  344. b2 = MSG_PARM2(dwData);
  345. if (NULL != pchannel->pbKeyMap)
  346. b1 = pchannel->pbKeyMap[b1];
  347. dwData = MSG_PACK2(bMsg|bChan, b1, b2);
  348. break;
  349. case MIDI_POLYPRESSURE:
  350. case MIDI_CONTROLCHANGE:
  351. case MIDI_PITCHBEND:
  352. b1 = MSG_PARM1(dwData);
  353. b2 = MSG_PARM2(dwData);
  354. dwData = MSG_PACK2(bMsg|bChan, b1, b2);
  355. break;
  356. case MIDI_PROGRAMCHANGE:
  357. b1 = MSG_PARM1(dwData);
  358. if (NULL != pchannel->pbPatchMap)
  359. b1 = pchannel->pbPatchMap[b1];
  360. dwData = MSG_PACK1(bMsg|bChan, b1);
  361. break;
  362. case MIDI_SYSEX:
  363. //
  364. // BUGBUG - Review: Should we allow SysEx through the mapper?
  365. //
  366. break;
  367. }
  368. if (!(fdwFlags & MSE_F_RETURNEVENT))
  369. {
  370. if (dwData)
  371. {
  372. if (ghMidiStrm)
  373. mmr = midiOutShortMsg((HMIDIOUT)ghMidiStrm, dwData);
  374. else
  375. mmr = midiOutShortMsg(pchannel->pport->hmidi, dwData);
  376. if (MMSYSERR_NOERROR != mmr)
  377. {
  378. DPF(1, TEXT ("midiOutShortMsg(%04X, %08lX) -> %u"), (WORD)(pchannel->pport->hmidi), dwData, (UINT)mmr);
  379. }
  380. }
  381. return mmr;
  382. }
  383. else
  384. return dwData;
  385. }
  386. /***************************************************************************
  387. @doc internal
  388. @api DWORD | modLongMsg | Handle MODM_LONGDATA in compatibility mode.
  389. @parm LPMIDIHDR | lpmh | The header to broadcast.
  390. @comm Propogate the header across all drivers. <f modmCallback> handles
  391. counting the returning callbacks and making sure the caller only gets
  392. one.
  393. @rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
  394. mapped event if no error, 0L on error.
  395. ***************************************************************************/
  396. DWORD FNLOCAL modLongMsg(
  397. PINSTANCE pinstance,
  398. LPMIDIHDR lpmh)
  399. {
  400. WORD wIntStat;
  401. LPMIDIHDR lpmhWork;
  402. PPORT pport;
  403. MMRESULT mmrc = MMSYSERR_NOERROR;
  404. BOOL fNeedCB = FALSE;
  405. LPMIDIHDR31 lpmh31 = (LPMIDIHDR31)lpmh;
  406. PSHADOWBLOCK psb;
  407. if (ghMidiStrm)
  408. psb = (PSHADOWBLOCK)(UINT)lpmh->dwReserved[MH_SHADOW];
  409. else
  410. psb = (PSHADOWBLOCK)(UINT)lpmh31->reserved;
  411. lpmhWork = psb->lpmhShadow;
  412. lpmhWork->dwReserved[MH_MAPINST] = (DWORD)(UINT)pinstance;
  413. if (ghMidiStrm)
  414. {
  415. lpmhWork->dwBufferLength = lpmh->dwBufferLength;
  416. return midiOutLongMsg((HMIDIOUT)ghMidiStrm,
  417. lpmhWork,
  418. sizeof(*lpmhWork));
  419. }
  420. lpmh->dwFlags |= MHDR_SENDING;
  421. psb->cRefCnt = 0;
  422. DPF(1, TEXT ("LongMsg: User hdr %08lX Shadow %08lX"), (DWORD)lpmh, (DWORD)lpmhWork);
  423. for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
  424. {
  425. lpmhWork->dwBufferLength = lpmh->dwBufferLength;
  426. mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
  427. if (MMSYSERR_NOERROR != mmrc)
  428. {
  429. // Don't turn off MHDR_SENDING; this will prevent any callbacks
  430. // from being propogated to the user.
  431. return mmrc;
  432. }
  433. ++psb->cRefCnt;
  434. }
  435. // Wait for synchronization object
  436. WaitForSingleObject (hMutexRefCnt, INFINITE);
  437. // Do we need to do callback
  438. if (0 == psb->cRefCnt)
  439. fNeedCB = TRUE;
  440. // Release synchronization object
  441. ReleaseMutex (hMutexRefCnt);
  442. if (fNeedCB)
  443. {
  444. lpmh->dwFlags |= MHDR_DONE;
  445. DriverCallback(
  446. pinstance->dwCallback,
  447. HIWORD(pinstance->fdwOpen),
  448. (HANDLE)pinstance->hmidi,
  449. MM_MOM_DONE,
  450. pinstance->dwInstance,
  451. (DWORD)lpmh,
  452. 0L);
  453. }
  454. return MMSYSERR_NOERROR;
  455. }
  456. /***************************************************************************
  457. @doc internal
  458. @api DWORD | modMapLongMsg | Handle MODM_LONGDATA in compatibility mode.
  459. @parm LPMIDIHDR | lpmh | The header to broadcast.
  460. @comm if a SYSEXE event Propogate the header across all drivers.
  461. <f modmCallback> handles counting the returning callbacks and making sure the caller only gets
  462. one. Otherwise, parse the Long Message into a bunch of short messages
  463. and Map each one individually.
  464. @rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
  465. mapped event if no error, 0L on error.
  466. ***************************************************************************/
  467. DWORD FNLOCAL modMapLongMsg (
  468. PINSTANCE pinstance,
  469. LPMIDIHDR lpmh)
  470. {
  471. WORD wIntStat;
  472. LPMIDIHDR lpmhWork;
  473. PPORT pport;
  474. MMRESULT mmrc = MMSYSERR_NOERROR;
  475. BOOL fNeedCB = FALSE;
  476. LPMIDIHDR31 lpmh31 = (LPMIDIHDR31)lpmh;
  477. PSHADOWBLOCK psb;
  478. LPBYTE pbData; // Pointer to Data
  479. BYTE bMsg;
  480. UINT uMessageLength;
  481. LPBYTE pbTrans; // Pointer to Translation Buffer
  482. DWORD dwCurr;
  483. DWORD dwLength;
  484. DWORD dwMsg;
  485. DWORD dwBuffLen;
  486. INT rMsg;
  487. // Get Shadow Block
  488. if (ghMidiStrm)
  489. psb = (PSHADOWBLOCK)(UINT)lpmh->dwReserved[MH_SHADOW];
  490. else
  491. psb = (PSHADOWBLOCK)(UINT)lpmh31->reserved;
  492. lpmhWork = psb->lpmhShadow;
  493. lpmhWork->dwReserved[MH_MAPINST] = (DWORD)(UINT)pinstance;
  494. // Check for MIDI streaming
  495. if (ghMidiStrm)
  496. {
  497. lpmhWork->dwBufferLength = lpmh->dwBufferLength;
  498. return midiOutLongMsg((HMIDIOUT)ghMidiStrm,
  499. lpmhWork,
  500. sizeof(*lpmhWork));
  501. }
  502. lpmh->dwFlags |= MHDR_SENDING;
  503. psb->cRefCnt = 0;
  504. DPF(1, TEXT ("MapLongMsg: User hdr %08lX Shadow %08lX"), (DWORD)lpmh, (DWORD)lpmhWork);
  505. pbData = lpmhWork->lpData;
  506. bMsg = MSG_EVENT(*pbData);
  507. if (MIDI_SYSEX == bMsg)
  508. {
  509. // Broadcast SYSEX message to all active ports
  510. for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
  511. {
  512. lpmhWork->dwBufferLength = lpmh->dwBufferLength;
  513. mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
  514. if (MMSYSERR_NOERROR != mmrc)
  515. {
  516. // Don't turn off MHDR_SENDING; this will prevent any callbacks
  517. // from being propogated to the user.
  518. return mmrc;
  519. }
  520. ++psb->cRefCnt;
  521. }
  522. }
  523. else
  524. {
  525. // Parse and Translate list of Short messages
  526. dwBuffLen = lpmh->dwBufferLength;
  527. // Grow Translation buffer to at least this size
  528. if (!GrowTransBuffer (pinstance, dwBuffLen))
  529. {
  530. // That didn't work !!!
  531. // Default to Broadcast messages to all active ports
  532. for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
  533. {
  534. lpmhWork->dwBufferLength = lpmh->dwBufferLength;
  535. mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
  536. if (MMSYSERR_NOERROR != mmrc)
  537. {
  538. // Don't turn off MHDR_SENDING; this will prevent any callbacks
  539. // from being propogated to the user.
  540. return mmrc;
  541. }
  542. ++psb->cRefCnt;
  543. }
  544. }
  545. else
  546. {
  547. // Copy buffer to translation buffer
  548. pbTrans = AccessTransBuffer (pinstance);
  549. CopyMemory (pbTrans, pbData, dwBuffLen);
  550. // Parse translation buffer
  551. dwCurr = 0L;
  552. while (dwBuffLen)
  553. {
  554. // Map Event
  555. rMsg = MapEvent (&pbTrans[dwCurr], dwBuffLen, &dwLength, &dwMsg);
  556. switch (rMsg)
  557. {
  558. case MSG_SHORT:
  559. // Send Short Message
  560. MapSingleEvent(pinstance,
  561. dwMsg,
  562. MSE_F_SENDEVENT,
  563. NULL);
  564. dwCurr += dwLength;
  565. break;
  566. case MSG_LONG:
  567. //
  568. // Bugbug: For completeness, we should probably broadcast
  569. // this, but for now assume that there are no embedded
  570. // SYSEX messages in the buffer and skip any we encounter
  571. //
  572. dwCurr += dwLength;
  573. break;
  574. default:
  575. dwCurr += dwLength;
  576. break;
  577. }
  578. dwBuffLen -= dwLength;
  579. } // End While
  580. // Release Translation Buffer
  581. ReleaseTransBuffer (pinstance);
  582. }
  583. }
  584. // Wait for synchronization object
  585. WaitForSingleObject (hMutexRefCnt, INFINITE);
  586. // Do we need to do callback
  587. if (0 == psb->cRefCnt)
  588. fNeedCB = TRUE;
  589. // Release synchronization object
  590. ReleaseMutex (hMutexRefCnt);
  591. if (fNeedCB)
  592. {
  593. lpmh->dwFlags |= MHDR_DONE;
  594. DriverCallback(
  595. pinstance->dwCallback,
  596. HIWORD(pinstance->fdwOpen),
  597. (HANDLE)pinstance->hmidi,
  598. MM_MOM_DONE,
  599. pinstance->dwInstance,
  600. (DWORD)lpmh,
  601. 0L);
  602. }
  603. return MMSYSERR_NOERROR;
  604. } // End modMapLongMsg
  605. // returns length of various MIDI messages in bytes
  606. INT FNLOCAL MapEvent (
  607. BYTE * pStatus,
  608. DWORD dwBuffSize,
  609. DWORD * pSkipBytes,
  610. DWORD * pShortMsg)
  611. {
  612. INT fResult = MSG_SHORT;
  613. BYTE bMsg = 0;
  614. BYTE bParam1 = 0;
  615. BYTE bParam2 = 0;
  616. bMsg = *pStatus;
  617. *pSkipBytes = 0;
  618. // Mask Off Channel bits
  619. switch (bMsg & 0xF0)
  620. {
  621. case MIDI_NOTEOFF:
  622. case MIDI_NOTEON:
  623. case MIDI_POLYPRESSURE:
  624. case MIDI_CONTROLCHANGE:
  625. bParam1 = *(pStatus+1);
  626. bParam2 = *(pStatus+2);
  627. *pShortMsg = MSG_PACK2(bMsg,bParam1,bParam2);
  628. *pSkipBytes = 3;
  629. break;
  630. case MIDI_PROGRAMCHANGE:
  631. case MIDI_CHANPRESSURE:
  632. bParam1 = *(pStatus+1);
  633. *pShortMsg = MSG_PACK1(bMsg,bParam1);
  634. *pSkipBytes = 2;
  635. break;
  636. case MIDI_PITCHBEND:
  637. bParam1 = *(pStatus+1);
  638. bParam2 = *(pStatus+2);
  639. *pShortMsg = MSG_PACK2(bMsg,bParam1,bParam2);
  640. *pSkipBytes = 3;
  641. break;
  642. case MIDI_SYSEX:
  643. // It's a system message
  644. // Keep counting system messages until
  645. // We don't find any more
  646. fResult = MSG_LONG;
  647. *pSkipBytes = 0;
  648. while (((bMsg & 0xF0) == 0xF0) &&
  649. (*pSkipBytes < dwBuffSize))
  650. {
  651. switch (bMsg)
  652. {
  653. case MIDI_SYSEX:
  654. // Find end of SysEx message
  655. *pSkipBytes ++;
  656. while ((*pSkipBytes < dwBuffSize) &&
  657. (pStatus[*pSkipBytes] != MIDI_SYSEXEND))
  658. {
  659. *pSkipBytes++;
  660. }
  661. break;
  662. case MIDI_QFRAME:
  663. *pSkipBytes += 2;
  664. break;
  665. case MIDI_SONGPOINTER:
  666. *pSkipBytes += 3;
  667. break;
  668. case MIDI_SONGSELECT:
  669. *pSkipBytes += 2;
  670. break;
  671. case MIDI_F4: // Undefined message
  672. case MIDI_F5: // Undefined message
  673. case MIDI_TUNEREQUEST:
  674. case MIDI_SYSEXEND: // Not really a message, but skip it
  675. case MIDI_TIMINGCLOCK:
  676. case MIDI_F9: // Undefined Message
  677. case MIDI_START:
  678. case MIDI_CONTINUE:
  679. case MIDI_STOP:
  680. case MIDI_FD: // Undefined Message
  681. case MIDI_ACTIVESENSING:
  682. case MIDI_META: // Is this how handle this message ?!?
  683. *pSkipBytes += 1;
  684. break;
  685. } // End Switch
  686. if (*pSkipBytes < dwBuffSize)
  687. bMsg = pStatus[*pSkipBytes];
  688. } // End While
  689. break;
  690. default:
  691. // Unknown just increment skip count
  692. fResult = MSG_UNKNOWN;
  693. *pSkipBytes = 1;
  694. break;
  695. } // End switch
  696. // Truncate to end of buffer
  697. if (*pSkipBytes > dwBuffSize)
  698. *pSkipBytes = dwBuffSize;
  699. return fResult;
  700. } // End MapEvent
  701. // Create Translation buffer
  702. BOOL FNGLOBAL InitTransBuffer (PINSTANCE pinstance)
  703. {
  704. if (!pinstance)
  705. return FALSE;
  706. InitializeCriticalSection (& (pinstance->csTrans));
  707. EnterCriticalSection (&(pinstance->csTrans));
  708. pinstance->pTranslate = (LPBYTE)LocalAlloc(LPTR, DEF_TRANS_SIZE);
  709. if (NULL == (pinstance->pTranslate))
  710. {
  711. LeaveCriticalSection (&(pinstance->csTrans));
  712. return FALSE;
  713. }
  714. pinstance->cbTransSize = DEF_TRANS_SIZE;
  715. pinstance->pTranslate = NULL;
  716. pinstance->cbTransSize = 0;
  717. LeaveCriticalSection (&(pinstance->csTrans));
  718. return TRUE;
  719. } // End InitTransBuffer
  720. // Cleanup Translation Buffer
  721. BOOL FNGLOBAL CleanupTransBuffer (PINSTANCE pinstance)
  722. {
  723. if (!pinstance)
  724. return FALSE;
  725. EnterCriticalSection (&(pinstance->csTrans));
  726. if (pinstance->pTranslate)
  727. {
  728. LocalFree((HLOCAL)(pinstance->pTranslate));
  729. pinstance->pTranslate = NULL;
  730. pinstance->cbTransSize = 0L;
  731. }
  732. LeaveCriticalSection (&(pinstance->csTrans));
  733. DeleteCriticalSection (&(pinstance->csTrans));
  734. return TRUE;
  735. } // End CleanupTransBuffer
  736. // Get Pointer to translation buffer
  737. LPBYTE AccessTransBuffer (PINSTANCE pinstance)
  738. {
  739. if (!pinstance)
  740. return NULL;
  741. EnterCriticalSection (&(pinstance->csTrans));
  742. return pinstance->pTranslate;
  743. } // End AccessTransBuffer
  744. // Release pointer to translation buffer
  745. void FNGLOBAL ReleaseTransBuffer (PINSTANCE pinstance)
  746. {
  747. if (!pinstance)
  748. return;
  749. LeaveCriticalSection (&(pinstance->csTrans));
  750. } // End ReleaseTransBuffer
  751. // Resize Translation buffer
  752. BOOL FNGLOBAL GrowTransBuffer (PINSTANCE pinstance, DWORD cbNewSize)
  753. {
  754. LPBYTE pNew;
  755. if (!pinstance)
  756. return FALSE;
  757. EnterCriticalSection (&(pinstance->csTrans));
  758. // Do we even need to grow buffer
  759. if (cbNewSize > pinstance->cbTransSize)
  760. {
  761. pNew = (LPBYTE)LocalAlloc(LPTR, cbNewSize);
  762. if (!pNew)
  763. {
  764. LeaveCriticalSection (&(pinstance->csTrans));
  765. return FALSE;
  766. }
  767. // Remove old translation buffer, if any
  768. if (pinstance->pTranslate)
  769. LocalFree ((HLOCAL)(pinstance->pTranslate));
  770. // Assign new buffer
  771. pinstance->pTranslate = pNew;
  772. pinstance->cbTransSize = cbNewSize;
  773. }
  774. LeaveCriticalSection (&(pinstance->csTrans));
  775. return TRUE;
  776. } // End GrowTransBuffer