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.

975 lines
27 KiB

  1. /*****************************************************************************
  2. map.c
  3. midi mapper run-time
  4. Copyright (c) Microsoft Corporation 1990-1991. All rights reserved
  5. *****************************************************************************/
  6. #include <windows.h>
  7. #include <string.h>
  8. #include <mmsystem.h>
  9. #if defined(WIN32)
  10. #include <port1632.h>
  11. #endif
  12. #include "hack.h"
  13. #include <mmddk.h>
  14. #include "midimap.h"
  15. #include "midi.h"
  16. #include "extern.h"
  17. #include "mmreg.h"
  18. #define ISSTATUS(bData) ((bData) & 0x80)
  19. #define FILTERCHANNEL(bStatus) ((BYTE)((bStatus) & 0xf0))
  20. #define FILTERSTATUS(bStatus) ((BYTE)((bStatus) & 0x0f))
  21. #define STATUS_NOTEOFF 0x80
  22. #define STATUS_NOTEON 0x90
  23. #define STATUS_POLYPHONICKEY 0xa0
  24. #define STATUS_CONTROLCHANGE 0xb0
  25. #define STATUS_PROGRAMCHANGE 0xc0
  26. #define STATUS_CHANNELPRESSURE 0xd0
  27. #define STATUS_PITCHBEND 0xe0
  28. #define STATUS_SYS 0xf0
  29. #define STATUS_SYSEX 0xf0
  30. #define STATUS_QFRAME 0xf1
  31. #define STATUS_SONGPOINTER 0xf2
  32. #define STATUS_SONGSELECT 0xf3
  33. #define STATUS_F4 0xf4
  34. #define STATUS_F5 0xf5
  35. #define STATUS_TUNEREQUEST 0xf6
  36. #define STATUS_EOX 0xf7
  37. #define STATUS_TIMINGCLOCK 0xf8
  38. #define STATUS_F9 0xf9
  39. #define STATUS_START 0xfa
  40. #define STATUS_CONTINUE 0xfb
  41. #define STATUS_STOP 0xfc
  42. #define STATUS_FD 0xfd
  43. #define STATUS_ACTIVESENSING 0xfe
  44. #define STATUS_SYSTEMRESET 0xff
  45. #define CONTROL_VOLUME 0x07
  46. #define MIDIDATABUFFER 512
  47. #define STATE_MAPNAILED 0x0001
  48. #define STATE_DATANAILED 0x0002
  49. #define STATE_CODENAILED 0x0004
  50. /*****************************************************************************
  51. local structures
  52. *****************************************************************************/
  53. typedef unsigned char huge * HPBYTE;
  54. #define DEV_PREPARED 0x0001
  55. typedef struct mididev_tag {
  56. WORD wDeviceID;
  57. WORD wChannel;
  58. WORD fwFlags;
  59. HMIDIOUT hMidi;
  60. } MIDIDEV;
  61. typedef MIDIDEV *PMIDIDEV;
  62. /*****************************************************************************
  63. local data
  64. *****************************************************************************/
  65. /*
  66. * critical section used to protect the open so that there is no
  67. * window in which two threads could open simultaneously - otherwise
  68. * with all these statics there would be a major accident
  69. */
  70. CRITICAL_SECTION MapperCritSec;
  71. static HGLOBAL hCurMap; // handle of current midi map
  72. static WORD wChannelMask; // which channels are on
  73. static UINT uPatchMask; // which channels have patch maps
  74. static MIDIDEV mapdevs[16]; // contains device info. for each midi device in the current map.
  75. static MIDIDEV chnldevs[16]; // map channels to midi devices.
  76. static LPMIDIPATCHMAP lpPMap; // current patch map
  77. static LPMIDIKEYMAP lpKMap; // current key map
  78. static BYTE curpatch[16]; // what is the currently selected patch for each channel
  79. static BYTE status; // virtual running status
  80. static BYTE bCurrentStatus; // Current message type
  81. static BYTE fActiveChannel; // Channel message to active channel
  82. static BYTE bCurrentLen; // Current message length, if any
  83. static DWORD_PTR OpenCallback; // Open Callback parameter
  84. static DWORD_PTR OpenInstance; // Open Instance parameter
  85. static DWORD OpenFlags; // Open Param2
  86. static HMIDIOUT hmidiMapper; // Handle of current mapper device
  87. static LPMIDIHDR pmidihdrMapper; // Buffer used for mapped devices
  88. static UINT ufStateFlags; // State flags for device
  89. extern BYTE FAR bMidiLengths[]; // Lengths in lengths.c
  90. extern BYTE FAR bSysLengths[]; // Lengths in lengths.c
  91. #define MIDILENGTH(bStatus) (bMidiLengths[((bStatus) & 0x70) >> 4])
  92. #define SYSLENGTH(bStatus) (bSysLengths[(bStatus) & 0x07])
  93. #define lpCurMap ((LPMIDIMAP)hCurMap) // pointer to current midi map
  94. UINT mapLockCount;
  95. UINT FAR PASCAL modGetDevCaps(LPMIDIOUTCAPSW lpCaps, UINT uSize);
  96. UINT FAR PASCAL modCachePatches(UINT msg, UINT uBank, LPPATCHARRAY lpPatchArray, UINT uFlags);
  97. static UINT FAR PASCAL midiReadCurrentSetup(LPMIDIOPENDESC lpOpen, DWORD dwParam2);
  98. LRESULT FAR PASCAL DriverProc(DWORD, HDRVR, UINT, LPARAM, LPARAM);
  99. static void NEAR PASCAL modShortData(LPBYTE pbData);
  100. static void NEAR PASCAL modLongData(HPBYTE pbData, DWORD dDataLength);
  101. static void NEAR PASCAL modTranslateEvent(LPBYTE pbData, BYTE bStart, BYTE bLength);
  102. DWORD FAR PASCAL _loadds modMessage(UINT id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2);
  103. static void PASCAL FAR CallbackNotification(UINT message, DWORD dwParam);
  104. static void NEAR PASCAL modSendLongData(UINT uMessageLength, BOOL fBroadcast, BOOL force);
  105. static BOOL NEAR PASCAL modHeaderDone(void);
  106. static void PASCAL NEAR ReleaseResources(void);
  107. static UINT PASCAL NEAR TranslateError(MMAPERR mmaperr)
  108. {
  109. switch (mmaperr) {
  110. case MMAPERR_INVALIDPORT:
  111. return MIDIERR_NODEVICE;
  112. case MMAPERR_MEMORY:
  113. return MMSYSERR_NOMEM;
  114. case MMAPERR_INVALIDSETUP:
  115. return MIDIERR_INVALIDSETUP;
  116. }
  117. return MIDIERR_NOMAP;
  118. }
  119. #if defined(WIN16)
  120. static BOOL NEAR PASCAL GlobalNail(
  121. HGLOBAL hSegment,
  122. UINT uFlag)
  123. {
  124. if (GlobalWire(hSegment)) {
  125. if (GlobalPageLock(hSegment)) {
  126. ufStateFlags |= uFlag;
  127. return TRUE;
  128. }
  129. GlobalUnWire(hSegment);
  130. }
  131. return FALSE;
  132. }
  133. static void NEAR PASCAL GlobalUnNail(
  134. HGLOBAL hSegment,
  135. UINT uFlag)
  136. {
  137. if (ufStateFlags & uFlag) {
  138. GlobalPageUnlock(hSegment);
  139. GlobalUnWire(hSegment);
  140. ufStateFlags &= ~uFlag;
  141. }
  142. }
  143. #endif //WIN16
  144. static void PASCAL NEAR ReleaseResources(void)
  145. {
  146. WORD wDevice;
  147. #ifdef WIN16
  148. GlobalUnNail((HGLOBAL)HIWORD((DWORD)(LPVOID)&hCurMap), STATE_DATANAILED);
  149. GlobalUnNail(hCurMap, STATE_MAPNAILED);
  150. GlobalUnNail((HGLOBAL)HIWORD(DriverProc), STATE_CODENAILED);
  151. #endif // WIN16
  152. for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++) {
  153. if (mapdevs[wDevice].hMidi) {
  154. midiOutReset(mapdevs[wDevice].hMidi);
  155. if (mapdevs[wDevice].fwFlags & DEV_PREPARED) {
  156. midiOutUnprepareHeader(mapdevs[wDevice].hMidi, pmidihdrMapper, sizeof(MIDIHDR));
  157. mapdevs[wDevice].fwFlags &= ~DEV_PREPARED;
  158. }
  159. midiOutClose(mapdevs[wDevice].hMidi);
  160. mapdevs[wDevice].hMidi = NULL;
  161. mapdevs[wDevice].wDeviceID = (WORD)(-1);
  162. }
  163. }
  164. if (hCurMap) {
  165. GlobalFree(hCurMap);
  166. hCurMap = NULL;
  167. }
  168. if (pmidihdrMapper) {
  169. HGLOBAL hmem = GlobalHandle( pmidihdrMapper );
  170. GlobalUnlock( hmem );
  171. GlobalFree( hmem );
  172. pmidihdrMapper = NULL;
  173. }
  174. }
  175. static UINT PASCAL FAR CloseMidiDevice(
  176. void)
  177. {
  178. ReleaseResources();
  179. CallbackNotification(MOM_CLOSE, 0);
  180. return 0;
  181. }
  182. static void PASCAL FAR CallbackNotification(
  183. UINT message,
  184. DWORD dwParam)
  185. {
  186. if (OpenCallback)
  187. DriverCallback( OpenCallback
  188. , HIWORD(OpenFlags) | DCB_NOSWITCH
  189. , (HANDLE)hmidiMapper
  190. , message
  191. , OpenInstance
  192. , dwParam
  193. , 0
  194. );
  195. }
  196. /***************************************************************************
  197. * @doc INTERNAL
  198. *
  199. * @api LRESULT | DriverProc | The entry point for an installable driver.
  200. *
  201. * @parm DWORD | dwDriverId | For most messages, <p dwDriverId> is the DWORD
  202. * value that the driver returns in response to a <m DRV_OPEN> message.
  203. * Each time that the driver is opened, through the <f DrvOpen> API,
  204. * the driver receives a <m DRV_OPEN> message and can return an
  205. * arbitrary, non-zero value. The installable driver interface
  206. * saves this value and returns a unique driver handle to the
  207. * application. Whenever the application sends a message to the
  208. * driver using the driver handle, the interface routes the message
  209. * to this entry point and passes the corresponding <p dwDriverId>.
  210. * This mechanism allows the driver to use the same or different
  211. * identifiers for multiple opens but ensures that driver handles
  212. * are unique at the application interface layer.
  213. *
  214. * The following messages are not related to a particular open
  215. * instance of the driver. For these messages, the dwDriverId
  216. * will always be zero.
  217. *
  218. * DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
  219. *
  220. * @parm HDRVR | hDriver | This is the handle returned to the
  221. * application by the driver interface.
  222. *
  223. * @parm UINT | wMessage | The requested action to be performed. Message
  224. * values below <m DRV_RESERVED> are used for globally defined messages.
  225. * Message values from <m DRV_RESERVED> to <m DRV_USER> are used for
  226. * defined driver protocols. Messages above <m DRV_USER> are used
  227. * for driver specific messages.
  228. *
  229. * @parm LPARAM | lParam1 | Data for this message. Defined separately for
  230. * each message
  231. *
  232. * @parm LPARAM | lParam2 | Data for this message. Defined separately for
  233. * each message
  234. *
  235. * @rdesc Defined separately for each message.
  236. ***************************************************************************/
  237. LRESULT FAR PASCAL DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT wMessage, LPARAM lParam1, LPARAM lParam2)
  238. {
  239. //
  240. // NOTE DS is not valid here.
  241. //
  242. switch (wMessage) {
  243. case DRV_LOAD:
  244. InitializeCriticalSection(&MapperCritSec);
  245. return (LRESULT)TRUE;
  246. case DRV_FREE:
  247. DeleteCriticalSection(&MapperCritSec);
  248. return (LRESULT)TRUE;
  249. case DRV_OPEN:
  250. case DRV_CLOSE:
  251. return (LRESULT)TRUE;
  252. case DRV_INSTALL:
  253. case DRV_REMOVE:
  254. return (LRESULT)DRVCNF_RESTART;
  255. default:
  256. return DefDriverProc(dwDriverID, hDriver, wMessage,lParam1,lParam2);
  257. }
  258. }
  259. DWORD FAR PASCAL _loadds modMessage(UINT id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
  260. {
  261. int i;
  262. DWORD dResult;
  263. // this driver only supports one device
  264. if (id != 0)
  265. return MMSYSERR_BADDEVICEID;
  266. switch (msg) {
  267. case MODM_GETNUMDEVS:
  268. return 1;
  269. case MODM_GETDEVCAPS:
  270. return modGetDevCaps((LPMIDIOUTCAPSW)dwParam1, LOWORD(dwParam2));
  271. case MODM_OPEN:
  272. EnterCriticalSection(&MapperCritSec);
  273. if( hCurMap || mapLockCount ) {
  274. dResult = MMSYSERR_ALLOCATED;
  275. } else {
  276. dResult = midiReadCurrentSetup((LPMIDIOPENDESC)dwParam1, dwParam2);
  277. }
  278. LeaveCriticalSection(&MapperCritSec);
  279. return dResult;
  280. case MODM_CLOSE:
  281. EnterCriticalSection(&MapperCritSec);
  282. dResult = CloseMidiDevice();
  283. LeaveCriticalSection(&MapperCritSec);
  284. return dResult;
  285. case MODM_CACHEPATCHES:
  286. case MODM_CACHEDRUMPATCHES:
  287. return modCachePatches(msg, HIWORD(dwParam2), (LPPATCHARRAY)dwParam1, LOWORD(dwParam2));
  288. ///////////////////////////////////////////////////////////////////////////
  289. //
  290. // INTERRUPT TIME CODE
  291. //
  292. // MODM_LONGDATA, MODM_DATA, and MODM_RESET are callable at interupt time!
  293. //
  294. ///////////////////////////////////////////////////////////////////////////
  295. case MODM_DATA:
  296. modShortData((LPBYTE)&dwParam1);
  297. return 0;
  298. case MODM_LONGDATA:
  299. modLongData( (HPBYTE)((LPMIDIHDR)dwParam1)->lpData
  300. , ((LPMIDIHDR)dwParam1)->dwBufferLength
  301. );
  302. ((LPMIDIHDR)dwParam1)->dwFlags |= MHDR_DONE;
  303. CallbackNotification(MOM_DONE, dwParam1);
  304. return 0;
  305. ///////////////////////////////////////////////////////////////////////////
  306. case MODM_PREPARE:
  307. case MODM_UNPREPARE:
  308. return MMSYSERR_NOTSUPPORTED;
  309. //case MODM_RESET:
  310. //case MODM_GETVOLUME:
  311. //case MODM_SETVOLUME:
  312. default:
  313. //
  314. // !!!this is in trouble if a map goes to multiple physical devices
  315. // we return the *last* dResult, this is
  316. // totally random for some messages (like MODM_GETVOLUME).
  317. // pass the message on un-translated to all mapped physical
  318. // devices.
  319. //
  320. for (dResult = 0, i = 0; i < 16 && mapdevs[i].hMidi; i++)
  321. switch (msg) {
  322. //
  323. // Avoid nasty overlaps with open devices
  324. //
  325. case MODM_GETVOLUME:
  326. dResult = midiOutGetVolume((HMIDIOUT)(mapdevs[i].wDeviceID), (LPDWORD)dwParam1);
  327. break;
  328. case MODM_SETVOLUME:
  329. dResult = midiOutSetVolume((HMIDIOUT)(mapdevs[i].wDeviceID), dwParam1);
  330. break;
  331. default:
  332. dResult = midiOutMessage(mapdevs[i].hMidi, msg, dwParam1, dwParam2);
  333. break;
  334. }
  335. return dResult;
  336. }
  337. }
  338. /*****************************************************************************
  339. * @doc EXTERNAL MIDI
  340. *
  341. * @api UINT | modGetDevCaps | This function returns the mappers device caps
  342. *
  343. * @parm LPMIDIOUTCAPS | lpCaps | Specifies a far pointer to a <t MIDIOUTCAPS>
  344. * structure. This structure is filled with information about the
  345. * capabilities of the device.
  346. *
  347. * @parm UINT | wSize | Specifies the size of the <t MIDIOUTCAPS> structure.
  348. *
  349. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  350. * an error number. Possible error returns are:
  351. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  352. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  353. *
  354. ****************************************************************************/
  355. UINT FAR PASCAL modGetDevCaps(LPMIDIOUTCAPSW lpCaps, UINT uSize)
  356. {
  357. MIDIOUTCAPSW mc;
  358. int i;
  359. if (uSize != 0) {
  360. i=LoadStringW( hLibInst,
  361. IDS_MIDIMAPPER,
  362. mc.szPname,
  363. sizeof(lpCaps->szPname) / sizeof(WCHAR) );
  364. mc.wMid = MM_MICROSOFT;
  365. mc.wPid = MM_MIDI_MAPPER;
  366. mc.vDriverVersion = 0x0100;
  367. mc.wTechnology = MOD_MAPPER;
  368. mc.wVoices = 0;
  369. mc.wNotes = 0;
  370. mc.wChannelMask = wChannelMask; // 0 if mapper not opened yet
  371. mc.dwSupport = MIDICAPS_CACHE;
  372. _fmemcpy((LPSTR)lpCaps, (LPSTR)&mc, min(uSize, sizeof(mc)));
  373. }
  374. return 0;
  375. }
  376. static void PASCAL NEAR TranslatePatchArray(
  377. LPPATCHARRAY lpSource,
  378. LPPATCHARRAY lpDest,
  379. BOOL fToMaps)
  380. {
  381. int i;
  382. _fmemset(lpDest, 0, sizeof(PATCHARRAY));
  383. for (i = 0; i < 16; i++) {
  384. UINT curmask;
  385. int j;
  386. curmask = 1 << i;
  387. if (uPatchMask & curmask) {
  388. lpPMap = (LPMIDIPATCHMAP)((LPSTR)lpCurMap + lpCurMap->chMap[i].oPMap);
  389. if (fToMaps)
  390. for (j = 0; j < MIDIPATCHSIZE; j++)
  391. lpDest[LOBYTE(lpPMap->wPMap[j])] |= (lpSource[j] & curmask) ? curmask : 0;
  392. else
  393. for (j = 0; j < MIDIPATCHSIZE; j++)
  394. lpDest[j] |= (lpSource[LOBYTE(lpPMap->wPMap[j])] & curmask) ? curmask : 0;
  395. } else
  396. for (j = 0; j < MIDIPATCHSIZE; j++)
  397. lpDest[j] |= (lpSource[j] & curmask) ? curmask : 0;
  398. }
  399. }
  400. UINT FAR PASCAL modCachePatches(UINT msg, UINT uBank, LPPATCHARRAY lpPatchArray, UINT uFlags)
  401. {
  402. int i;
  403. PATCHARRAY patchlist;
  404. PATCHARRAY retpatchlist;
  405. UINT uResult = 0;
  406. TranslatePatchArray(lpPatchArray, patchlist, TRUE);
  407. // send to drivers
  408. _fmemset(retpatchlist, 0, sizeof(PATCHARRAY));
  409. for( i = 0; ((i < 16) && (mapdevs[i].wDeviceID != (WORD)(-1))); i++ ) {
  410. PATCHARRAY curpatchlist;
  411. int j;
  412. for (j = 0; j < MIDIPATCHSIZE; j++ )
  413. curpatchlist[j] = patchlist[j] & mapdevs[i].wChannel;
  414. uResult = ( (msg == MODM_CACHEPATCHES)
  415. ? midiOutCachePatches( mapdevs[i].hMidi
  416. , uBank
  417. , curpatchlist
  418. , uFlags
  419. )
  420. : midiOutCacheDrumPatches( mapdevs[i].hMidi
  421. , uBank
  422. , curpatchlist
  423. , uFlags
  424. )
  425. );
  426. // combine the returned info
  427. for (j = 0; j < MIDIPATCHSIZE; j++ )
  428. retpatchlist[j] |= (curpatchlist[j] & mapdevs[i].wChannel);
  429. }
  430. TranslatePatchArray(retpatchlist, lpPatchArray, FALSE);
  431. return uResult;
  432. }
  433. ///////////////////////////////////////////////////////////////////////////
  434. //
  435. // INTERRUPT TIME CODE
  436. //
  437. // MODM_LONGDATA, and MODM_DATA are callable at interupt time!
  438. //
  439. ///////////////////////////////////////////////////////////////////////////
  440. static BOOL NEAR PASCAL modHeaderDone(
  441. void)
  442. {
  443. if (pmidihdrMapper->dwFlags & MHDR_DONE)
  444. return TRUE;
  445. else
  446. return FALSE;
  447. }
  448. static void NEAR PASCAL modSendLongData(
  449. UINT uMessageLength,
  450. BOOL fBroadcast,
  451. BOOL fForce) // Used on final invocation
  452. {
  453. static BYTE LongBuffer[200]; // Cache the stuff for performance
  454. static DWORD nLongData; // How much we've got
  455. static BOOL LastBroadcast; // What we were asked to do last time
  456. static BYTE LastStatus; // Last status we had
  457. if (nLongData &&
  458. (fForce ||
  459. FILTERSTATUS(status) != FILTERSTATUS(LastStatus) ||
  460. uMessageLength + nLongData > sizeof(LongBuffer) ||
  461. LastBroadcast != fBroadcast)) {
  462. LPBYTE lpSave = pmidihdrMapper->lpData;
  463. pmidihdrMapper->lpData = LongBuffer;
  464. pmidihdrMapper->dwBufferLength = nLongData;
  465. if (LastBroadcast) {
  466. WORD wDevice;
  467. for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++) {
  468. pmidihdrMapper->dwFlags &= ~MHDR_DONE;
  469. if (MMSYSERR_NOERROR ==
  470. midiOutLongMsg(mapdevs[wDevice].hMidi,
  471. pmidihdrMapper,
  472. sizeof(MIDIHDR))) {
  473. while (!modHeaderDone())
  474. Sleep(1);
  475. }
  476. }
  477. } else {
  478. pmidihdrMapper->dwFlags &= ~MHDR_DONE;
  479. if (MMSYSERR_NOERROR ==
  480. midiOutLongMsg(chnldevs[FILTERSTATUS(LastStatus)].hMidi,
  481. pmidihdrMapper,
  482. sizeof(MIDIHDR))) {
  483. while (!modHeaderDone())
  484. Sleep(1);
  485. }
  486. }
  487. pmidihdrMapper->lpData = lpSave;
  488. nLongData = 0;
  489. }
  490. //
  491. // Pull in our new data
  492. //
  493. LastStatus = status;
  494. LastBroadcast = fBroadcast;
  495. if (fBroadcast || fActiveChannel) {
  496. memcpy(LongBuffer + nLongData, pmidihdrMapper->lpData, uMessageLength);
  497. nLongData += uMessageLength;
  498. }
  499. }
  500. static void NEAR PASCAL modTranslateEvent(
  501. LPBYTE pbData,
  502. BYTE bStart,
  503. BYTE bLength)
  504. {
  505. static BYTE fControlVol;
  506. if (wChannelMask & (1 << FILTERSTATUS(status))) {
  507. fActiveChannel = TRUE;
  508. bCurrentStatus = FILTERCHANNEL(status) + (BYTE)lpCurMap->chMap[FILTERSTATUS(status)].wChannel;
  509. if (!bStart) {
  510. *(pbData++) = bCurrentStatus;
  511. bStart++;
  512. bLength--;
  513. if (!bLength)
  514. return;
  515. }
  516. if (uPatchMask & (1 << FILTERSTATUS(status))) {
  517. lpPMap = (LPMIDIPATCHMAP)((LPSTR)lpCurMap + lpCurMap->chMap[FILTERSTATUS(status)].oPMap);
  518. switch (FILTERCHANNEL(status)) {
  519. case STATUS_NOTEOFF:
  520. case STATUS_NOTEON:
  521. case STATUS_POLYPHONICKEY:
  522. if ((bStart > 1) || !lpPMap->okMaps[curpatch[FILTERSTATUS(status)]])
  523. break;
  524. lpKMap = (LPMIDIKEYMAP)((LPSTR)lpPMap + lpPMap->okMaps[curpatch[FILTERSTATUS(status)]]);
  525. *pbData = lpKMap->bKMap[*pbData];
  526. break;
  527. case STATUS_CONTROLCHANGE:
  528. if (bStart == 1) {
  529. if (*pbData != CONTROL_VOLUME)
  530. break;
  531. pbData++;
  532. bStart++;
  533. bLength--;
  534. fControlVol = TRUE;
  535. if (!bLength)
  536. return;
  537. }
  538. *pbData = (BYTE)((DWORD)*pbData * (DWORD)HIBYTE(lpPMap->wPMap[curpatch[FILTERSTATUS(status)]]) / lpPMap->bVMax);
  539. fControlVol = FALSE;
  540. break;
  541. case STATUS_PROGRAMCHANGE:
  542. curpatch[FILTERSTATUS(status)] = *pbData;
  543. *pbData = (BYTE)lpPMap->wPMap[*pbData];
  544. break;
  545. }
  546. }
  547. } else
  548. fActiveChannel = FALSE;
  549. }
  550. static void NEAR PASCAL modShortData( LPBYTE pbData)
  551. {
  552. BOOL fBroadcast;
  553. BYTE bStart = 0;
  554. BYTE bLength = 0;
  555. if (*pbData >= STATUS_TIMINGCLOCK)
  556. fBroadcast = TRUE;
  557. else {
  558. bCurrentLen = 0;
  559. if (ISSTATUS(*pbData)) {
  560. bCurrentStatus = *pbData;
  561. if (bCurrentStatus >= STATUS_SYSEX) {
  562. status = 0;
  563. fBroadcast = TRUE;
  564. } else {
  565. status = bCurrentStatus;
  566. bLength = MIDILENGTH(bCurrentStatus);
  567. fBroadcast = FALSE;
  568. bStart = 0;
  569. }
  570. } else if (!status)
  571. return;
  572. else {
  573. fBroadcast = FALSE;
  574. bLength = (BYTE)(MIDILENGTH(status) - 1);
  575. bStart = 1;
  576. }
  577. }
  578. if (fBroadcast) {
  579. WORD wDevice;
  580. for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++)
  581. midiOutShortMsg(mapdevs[wDevice].hMidi, *(LPDWORD)pbData);
  582. } else {
  583. modTranslateEvent(pbData, bStart, bLength);
  584. if (fActiveChannel)
  585. midiOutShortMsg(chnldevs[FILTERSTATUS(status)].hMidi, *(LPDWORD)pbData);
  586. }
  587. }
  588. static void NEAR PASCAL modLongData(
  589. HPBYTE pbData,
  590. DWORD dDataLength)
  591. {
  592. static BYTE bStart;
  593. UINT uMessageLength;
  594. LPBYTE pbHdrData;
  595. pbHdrData = pmidihdrMapper->lpData;
  596. uMessageLength = 0;
  597. for (; dDataLength;) {
  598. if (ISSTATUS(*pbData)) {
  599. if (bCurrentStatus == STATUS_SYSEX) {
  600. bCurrentStatus = *pbData;
  601. if ((bCurrentStatus == STATUS_EOX) || (bCurrentStatus == STATUS_SYSEX) || (bCurrentStatus >= STATUS_TIMINGCLOCK)) {
  602. *(pbHdrData++) = bCurrentStatus;
  603. dDataLength--;
  604. if (bCurrentStatus >= STATUS_TIMINGCLOCK)
  605. bCurrentStatus = STATUS_SYSEX;
  606. } else
  607. uMessageLength--;
  608. } else {
  609. if (bCurrentLen) {
  610. if (status) {
  611. BYTE bMessageLength;
  612. bMessageLength = (BYTE)(MIDILENGTH(status) - bCurrentLen - bStart);
  613. modTranslateEvent(pmidihdrMapper->lpData - bMessageLength, bStart, bMessageLength);
  614. }
  615. modSendLongData(uMessageLength, !status, FALSE);
  616. pbHdrData = pmidihdrMapper->lpData;
  617. uMessageLength = 0;
  618. }
  619. *pbHdrData = *(pbData++);
  620. dDataLength--;
  621. if (*pbHdrData >= STATUS_TIMINGCLOCK) {
  622. modSendLongData(1, TRUE, FALSE);
  623. continue;
  624. }
  625. bCurrentStatus = *(pbHdrData++);
  626. if (bCurrentStatus >= STATUS_SYSEX) {
  627. status = 0;
  628. bCurrentLen = (BYTE)(SYSLENGTH(bCurrentStatus) - 1);
  629. } else {
  630. status = bCurrentStatus;
  631. bCurrentLen = (BYTE)(MIDILENGTH(bCurrentStatus) - 1);
  632. bStart = 0;
  633. }
  634. }
  635. } else {
  636. *(pbHdrData++) = *(pbData++);
  637. dDataLength--;
  638. if (bCurrentLen)
  639. bCurrentLen--;
  640. else if (status) {
  641. bStart = 1;
  642. bCurrentLen = (BYTE)(MIDILENGTH(status) - 2);
  643. }
  644. }
  645. uMessageLength++;
  646. if (!bCurrentLen && ((bCurrentStatus != STATUS_SYSEX) || (uMessageLength == MIDIDATABUFFER))) {
  647. if (status) {
  648. BYTE bMessageLength;
  649. bMessageLength = (BYTE)(MIDILENGTH(status) - bStart);
  650. modTranslateEvent(pmidihdrMapper->lpData - bStart, bStart, bMessageLength);
  651. }
  652. modSendLongData(uMessageLength, !status, FALSE);
  653. pbHdrData = pmidihdrMapper->lpData;
  654. uMessageLength = 0;
  655. }
  656. }
  657. if (uMessageLength) {
  658. if (status) {
  659. BYTE bMessageLength;
  660. bMessageLength = (BYTE)(MIDILENGTH(status) - bCurrentLen - bStart);
  661. modTranslateEvent(pmidihdrMapper->lpData - bStart, bStart, bMessageLength);
  662. bStart += bMessageLength;
  663. }
  664. modSendLongData(uMessageLength, !status, FALSE);
  665. }
  666. modSendLongData(0, 0, TRUE);
  667. }
  668. /*****************************************************************************
  669. * @doc INTERNAL MIDI
  670. *
  671. * @api BOOL | mapLock | This function prevents anyone from opening the
  672. * mapper.
  673. *
  674. * @rdesc Returns TRUE if successful and FALSE otherwise (i.e. the mapper is
  675. * already open.
  676. *
  677. * @comm This is a private function for the control panel applet to call
  678. * while a setup is being edited. There is a lock count kept - you must
  679. * call mapUnlock once for each call to mapLock.
  680. ****************************************************************************/
  681. BOOL FAR PASCAL mapLock(VOID)
  682. {
  683. // if someone has the mapper open, return FALSE
  684. if( hCurMap )
  685. return FALSE;
  686. mapLockCount++;
  687. return TRUE;
  688. }
  689. /*****************************************************************************
  690. * @doc INTERNAL MIDI
  691. *
  692. * @api VOID | mapUnlock | This function unlocks the mapper if it's locked.
  693. *
  694. * @rdesc There is no return value.
  695. *
  696. * @comm This is a private function for the control panel applet to call
  697. * while a setup is being edited. There is a lock count kept but
  698. * underflow will not generate an error, and lock count will remain 0.
  699. ****************************************************************************/
  700. VOID FAR PASCAL mapUnlock(VOID)
  701. {
  702. if( mapLockCount )
  703. mapLockCount--;
  704. return;
  705. }
  706. /*****************************************************************************
  707. * @doc INTERNAL MIDI
  708. *
  709. * @api UINT | midiReadCurrentSetup | This function reads in the current setup.
  710. *
  711. * @parm DWORD | dwParam1 | The first DWORD from the <f midiOutOpen> call.
  712. *
  713. * @parm DWORD | dwParam2 | The second DWORD from the <f midiOutOpen> call.
  714. *
  715. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  716. * an error number.
  717. ****************************************************************************/
  718. static UINT FAR PASCAL midiReadCurrentSetup(LPMIDIOPENDESC lpOpen, DWORD dwParam2)
  719. {
  720. int i,j;
  721. WORD devid;
  722. MMAPERR mmaperr;
  723. DWORD dwSize;
  724. UINT uResult;
  725. char szCurSetup[MMAP_MAXNAME];
  726. WORD wChan;
  727. // get current setup
  728. mmaperr = mapGetCurrentSetup(szCurSetup, MMAP_MAXNAME);
  729. if (mmaperr != MMAPERR_SUCCESS)
  730. return TranslateError(mmaperr);
  731. dwSize = mapGetSize(MMAP_SETUP, szCurSetup);
  732. if (dwSize < (DWORD)MMAPERR_MAXERROR)
  733. return TranslateError((UINT)dwSize);
  734. // allocate memory
  735. hCurMap = GlobalAlloc(GMEM_MOVEABLE, dwSize);
  736. if( !hCurMap )
  737. return MMSYSERR_NOMEM;
  738. hCurMap = (HGLOBAL)GlobalLock(hCurMap);
  739. mmaperr = mapRead (MMAP_SETUP, szCurSetup, lpCurMap);
  740. if( mmaperr != MMAPERR_SUCCESS ) {
  741. ReleaseResources();
  742. return TranslateError(mmaperr);
  743. }
  744. // initialize channel and patch masks
  745. wChannelMask = 0;
  746. uPatchMask = 0;
  747. // initialize device list
  748. for (i = 0; i < 16; i++) {
  749. mapdevs[i].wDeviceID = (WORD)(-1);
  750. mapdevs[i].hMidi = NULL;
  751. mapdevs[i].fwFlags = 0;
  752. }
  753. // go through each source channel
  754. for( wChan = 0; wChan < 16; wChan++ ) {
  755. if( ((lpCurMap->chMap[wChan]).dwFlags) & MMAP_ACTIVE ) {
  756. // set channel mask
  757. wChannelMask |= (1 << wChan);
  758. // set patch mask
  759. if( ((lpCurMap->chMap[wChan]).dwFlags) & MMAP_PATCHMAP )
  760. uPatchMask |= (1 << wChan);
  761. // map device id
  762. devid = lpCurMap->chMap[wChan].wDeviceID;
  763. // save driver and device ids for channel messages
  764. chnldevs[wChan].wDeviceID = devid;
  765. // algorithm for device list
  766. // wChannel will have the channel mask for the device
  767. for( j = 0; j < 16; j++ ) {
  768. if( mapdevs[j].wDeviceID == devid ) {
  769. mapdevs[j].wChannel |= 0x0001 << wChan;
  770. break; // from for loop
  771. }
  772. if( mapdevs[j].wDeviceID == (WORD)(-1) ) {
  773. mapdevs[j].wDeviceID = devid;
  774. mapdevs[j].wChannel = (WORD)(1 << wChan); // first channel
  775. break;
  776. }
  777. }
  778. }
  779. }
  780. // create a long message buffer for translation of long messages.
  781. { HANDLE hMem;
  782. hMem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT
  783. , (LONG)(sizeof(MIDIHDR) + MIDIDATABUFFER)
  784. );
  785. if (hMem)
  786. pmidihdrMapper = ( hMem ? (LPMIDIHDR)GlobalLock(hMem) : NULL);
  787. }
  788. if (!pmidihdrMapper) {
  789. ReleaseResources();
  790. return MMSYSERR_NOMEM;
  791. }
  792. pmidihdrMapper->lpData = (LPSTR)(pmidihdrMapper + 1);
  793. pmidihdrMapper->dwBufferLength = MIDIDATABUFFER;
  794. // open all devices in new map
  795. for( i = 0; ((i < 16) && (mapdevs[i].wDeviceID != (WORD)(-1)) ); i++ ) {
  796. uResult = midiOutOpen(&mapdevs[i].hMidi,
  797. mapdevs[i].wDeviceID,
  798. 0,
  799. 0,
  800. dwParam2 & ~CALLBACK_TYPEMASK);
  801. if(uResult != 0 ){ // if any opens fail, return now
  802. ReleaseResources();
  803. return uResult;
  804. }
  805. uResult = midiOutPrepareHeader(mapdevs[i].hMidi, pmidihdrMapper, sizeof(MIDIHDR));
  806. if (uResult) {
  807. ReleaseResources();
  808. return uResult;
  809. }
  810. mapdevs[i].fwFlags |= DEV_PREPARED;
  811. for( j = 0; j < 16; j++ ) {
  812. if( mapdevs[i].wDeviceID == chnldevs[j].wDeviceID )
  813. chnldevs[j].hMidi = mapdevs[i].hMidi;
  814. }
  815. }
  816. OpenCallback = lpOpen->dwCallback;
  817. OpenInstance = lpOpen->dwInstance;
  818. OpenFlags = dwParam2;
  819. hmidiMapper = (HMIDIOUT)lpOpen->hMidi;
  820. status = 0;
  821. bCurrentLen = 0;
  822. bCurrentStatus = 0;
  823. #if defined(WIN16)
  824. if ( GlobalNail((HGLOBAL)HIWORD(DriverProc), STATE_CODENAILED)
  825. && GlobalNail(hCurMap, STATE_MAPNAILED)
  826. && GlobalNail((HGLOBAL)HIWORD((DWORD)(LPVOID)&hCurMap), STATE_DATANAILED)
  827. )
  828. {
  829. #endif //WIN16
  830. CallbackNotification(MOM_OPEN, 0);
  831. return MMSYSERR_NOERROR;
  832. #if defined(WIN16)
  833. }
  834. ReleaseResources();
  835. return MMSYSERR_NOMEM;
  836. #endif //WIN16
  837. }