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.

1579 lines
49 KiB

  1. /****************************************************************************
  2. *
  3. * mididd.c
  4. *
  5. * Multimedia kernel driver support component (mmdrv)
  6. *
  7. * Copyright (c) 1991-1998 Microsoft Corporation
  8. *
  9. * Driver for midi input and output devices
  10. *
  11. * -- Midi driver entry points (modMessage, midMessage)
  12. * -- Auxiliary task (necessary for receiving Apcs and generating
  13. * callbacks ASYNCRHONOUSLY)
  14. * -- Interface to kernel driver (NtDeviceIoControlFile)
  15. * -- Midi parsing code (ported from Windows 3.1).
  16. *
  17. * History
  18. * 01-Feb-1992 - Robin Speed (RobinSp) wrote it
  19. *
  20. ***************************************************************************/
  21. #include "mmdrv.h"
  22. #include <ntddmidi.h>
  23. /*****************************************************************************
  24. internal declarations
  25. ****************************************************************************/
  26. #define D1 dprintf1
  27. #define D2 dprintf2
  28. #define D3 dprintf3
  29. //
  30. // Stack size for our auxiliary task
  31. //
  32. #define MIDI_STACK_SIZE 300
  33. #define SYSEX_ERROR 0xFF // internal error for sysex's on input
  34. //
  35. // Functions for auxiliary thread to perform
  36. //
  37. typedef enum {
  38. MidiThreadInvalid,
  39. MidiThreadAddBuffer,
  40. MidiThreadSetState,
  41. MidiThreadSetData,
  42. MidiThreadClose,
  43. MidiThreadTerminate
  44. } MIDITHREADFUNCTION;
  45. //
  46. // Our local buffers for interfacing to midi input
  47. //
  48. #define LOCAL_MIDI_DATA_SIZE 20
  49. typedef struct _LOCALMIDIHDR {
  50. OVERLAPPED Ovl;
  51. DWORD BytesReturned;
  52. struct _LOCALMIDIHDR *lpNext; // Queueing (really debug only)
  53. BOOL Done; // Driver completed buffer
  54. PVOID pClient; // Our instance data for Apcs
  55. MIDI_DD_INPUT_DATA MidiData; // What the driver wants to process
  56. BYTE ExtraData[LOCAL_MIDI_DATA_SIZE - sizeof(ULONG)];
  57. // The rest of our input buffer
  58. } LOCALMIDIHDR, *PLOCALMIDIHDR;
  59. //
  60. // Midi input data
  61. //
  62. #define NUMBER_OF_LOCAL_MIDI_BUFFERS 8
  63. typedef struct {
  64. //
  65. // Static data for managing midi input
  66. //
  67. BOOL fMidiInStarted; // Do we think midi in is running ?
  68. DWORD dwMsg; // Current short msg
  69. DWORD dwCurData; // Position in long message
  70. BYTE status; // Running status byte
  71. BOOLEAN fSysex; // Processing extended message
  72. BOOLEAN Bad; // Input not working properly
  73. BYTE bBytesLeft; // Bytes left in short message
  74. BYTE bBytePos; // Position in short message
  75. DWORD dwCurTime; // Latest time from driver
  76. DWORD dwMsgTime; // Time to insert into message
  77. // in milliseconds since device
  78. // was opened
  79. PLOCALMIDIHDR DeviceQueue; // Keep track of what the device
  80. // has (debugging only)
  81. LOCALMIDIHDR // Driver interface buffers
  82. Bufs[NUMBER_OF_LOCAL_MIDI_BUFFERS];// When input is active these
  83. // are queued on the device
  84. // except while data is being
  85. // processed from them
  86. } LOCALMIDIDATA, *PLOCALMIDIDATA;
  87. //
  88. // per allocation structure for Midi
  89. //
  90. typedef struct tag_MIDIALLOC {
  91. struct tag_MIDIALLOC *Next; // Chain of devices
  92. UINT DeviceNumber; // Number of device
  93. UINT DeviceType; // MidiInput or MidiOutput
  94. DWORD_PTR dwCallback; // client's callback
  95. DWORD_PTR dwInstance; // client's instance data
  96. HMIDI hMidi; // handle for stream
  97. HANDLE hDev; // Midi device handle
  98. LPMIDIHDR lpMIQueue; // Buffers sent to device
  99. // This is only required so that
  100. // CLOSE knows when things have
  101. // really finished.
  102. // notify. This is only accessed
  103. // on the device thread and its
  104. // apcs so does not need any
  105. // synchronized access.
  106. HANDLE Event; // Event for driver syncrhonization
  107. // and notification of auxiliary
  108. // task operation completion.
  109. MIDITHREADFUNCTION AuxFunction; // Function for thread to perform
  110. union {
  111. LPMIDIHDR pHdr; // Buffer to pass in aux task
  112. ULONG State; // State to set
  113. struct {
  114. ULONG Function; // IOCTL to use
  115. PBYTE pData; // Data to set or get
  116. ULONG DataLen; // Length of data
  117. } GetSetData;
  118. } AuxParam;
  119. // 0 means terminate task.
  120. HANDLE ThreadHandle; // Handle for termination ONLY
  121. HANDLE AuxEvent1; // Aux thread waits on this
  122. HANDLE AuxEvent2; // Aux thread caller waits on this
  123. DWORD AuxReturnCode; // Return code from Aux task
  124. DWORD dwFlags; // Open flags
  125. PLOCALMIDIDATA Mid; // Extra midi input structures
  126. int l; // Helper global for modMidiLength
  127. } MIDIALLOC, *PMIDIALLOC;
  128. PMIDIALLOC MidiHandleList; // Our chain of wave handles
  129. /*****************************************************************************
  130. internal function prototypes
  131. ****************************************************************************/
  132. STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
  133. DWORD dwSize);
  134. STATIC DWORD midiThread(LPVOID lpParameter);
  135. STATIC void midiCleanUp(PMIDIALLOC pClient);
  136. STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient);
  137. STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State);
  138. STATIC void midiInOvl(DWORD dwRet, DWORD dwBytes, LPOVERLAPPED pOverlap);
  139. STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient);
  140. STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient);
  141. STATIC void midiBlockFinished(LPMIDIHDR lpHdr, DWORD MsgId);
  142. STATIC void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD_PTR dw1, DWORD_PTR dw2);
  143. STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b);
  144. STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte);
  145. STATIC void midSendPartBuffer(PMIDIALLOC pClient);
  146. STATIC void midFreeQ(PMIDIALLOC pClient);
  147. STATIC void midiFlush(PMIDIALLOC pClient);
  148. /****************************************************************************
  149. * @doc INTERNAL
  150. *
  151. * @api VOID | TerminateMidi | Free all midi resources for mmdrv.dll
  152. *
  153. * @rdesc None
  154. ***************************************************************************/
  155. VOID TerminateMidi(VOID)
  156. {
  157. //
  158. // Don't do any cleanup - Midi input resources cleaned up on Close.
  159. //
  160. }
  161. /****************************************************************************
  162. * @doc INTERNAL
  163. *
  164. * @api void | midiGetDevCaps | Get the device capabilities.
  165. *
  166. * @parm DWORD | id | Device id
  167. *
  168. * @parm UINT | DeviceType | type of device
  169. *
  170. * @parm LPBYTE | lpCaps | Far pointer to a MIDIOUTCAPS structure to
  171. * receive the information.
  172. *
  173. * @parm DWORD | dwSize | Size of the MIDIOUTCAPS structure.
  174. *
  175. * @rdesc There is no return value.
  176. ***************************************************************************/
  177. STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType,
  178. LPBYTE lpCaps, DWORD dwSize)
  179. {
  180. return sndGetData(DeviceType, id, dwSize, lpCaps,
  181. IOCTL_MIDI_GET_CAPABILITIES);
  182. }
  183. /****************************************************************************
  184. * @doc INTERNAL
  185. *
  186. * @api DWORD | midiOpen | Open midi device and set up logical device data
  187. * and auxilary task for issuing requests and servicing Apc's
  188. *
  189. * @parm MIDIDEVTYPE | DeviceType | Whether it's a midi input or output device
  190. *
  191. * @parm DWORD | id | The device logical id
  192. *
  193. * @parm DWORD | msg | Input parameter to modMessage
  194. *
  195. * @parm DWORD | dwUser | Input parameter to modMessage - pointer to
  196. * application's handle (generated by this routine)
  197. *
  198. * @parm DWORD | dwParam1 | Input parameter to modMessage
  199. *
  200. * @parm DWORD | dwParam2 | Input parameter to modMessage
  201. *
  202. * @rdesc modMessage return code.
  203. ***************************************************************************/
  204. STATIC DWORD midiOpen(UINT DeviceType,
  205. DWORD id,
  206. DWORD_PTR dwUser,
  207. DWORD_PTR dwParam1,
  208. DWORD_PTR dwParam2)
  209. {
  210. PMIDIALLOC pClient; // pointer to client information structure
  211. MMRESULT mRet;
  212. // dwParam1 contains a pointer to a MIDIOPENDESC
  213. // dwParam2 contains midi driver specific flags in the LOWORD
  214. // and generic driver flags in the HIWORD
  215. //
  216. // allocate my per-client structure
  217. //
  218. if (DeviceType == MidiOutDevice) {
  219. pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0, sizeof(MIDIALLOC));
  220. if (pClient != NULL) {
  221. memset(pClient, 0, sizeof(MIDIALLOC));
  222. }
  223. } else {
  224. WinAssert(DeviceType == MidiInDevice);
  225. pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0,
  226. sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
  227. if (pClient != NULL) {
  228. memset(pClient, 0, sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
  229. }
  230. }
  231. if (pClient == NULL) {
  232. return MMSYSERR_NOMEM;
  233. }
  234. if (DeviceType == MidiInDevice) {
  235. int i;
  236. pClient->Mid = (PLOCALMIDIDATA)(pClient + 1);
  237. for (i = 0 ;i < NUMBER_OF_LOCAL_MIDI_BUFFERS ; i++) {
  238. pClient->Mid->Bufs[i].pClient = pClient;
  239. }
  240. }
  241. //
  242. // and fill it with info
  243. //
  244. // (note that setting everything to 0 correctly initialized our
  245. // midi input processing static data).
  246. pClient->DeviceType = DeviceType;
  247. pClient->dwCallback = ((LPMIDIOPENDESC)dwParam1)->dwCallback;
  248. pClient->dwInstance = ((LPMIDIOPENDESC)dwParam1)->dwInstance;
  249. pClient->hMidi = ((LPMIDIOPENDESC)dwParam1)->hMidi;
  250. pClient->dwFlags = (DWORD)dwParam2;
  251. //
  252. // See if we can open our device
  253. // If it's only a query be sure only to open for read, otherwise
  254. // we could get STATUS_BUSY if someone else is writing to the
  255. // device.
  256. //
  257. mRet = sndOpenDev(DeviceType,
  258. id,
  259. &pClient->hDev,
  260. (GENERIC_READ | GENERIC_WRITE));
  261. if (mRet != MMSYSERR_NOERROR) {
  262. midiCleanUp(pClient);
  263. return mRet;
  264. }
  265. //
  266. // Create our event for syncrhonization with the device driver
  267. //
  268. pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
  269. if (pClient->Event == NULL) {
  270. midiCleanUp(pClient);
  271. return MMSYSERR_NOMEM;
  272. }
  273. if (DeviceType == MidiInDevice) {
  274. //
  275. // Create our event pair for synchronization with the auxiliary
  276. // thread
  277. //
  278. pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
  279. if (pClient->AuxEvent1 == NULL) {
  280. midiCleanUp(pClient);
  281. return MMSYSERR_NOMEM;
  282. }
  283. pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
  284. if (pClient->AuxEvent2 == NULL) {
  285. midiCleanUp(pClient);
  286. return MMSYSERR_NOMEM;
  287. }
  288. //
  289. // Create our auxiliary thread for sending buffers to the driver
  290. // and collecting Apcs
  291. //
  292. mRet = mmTaskCreate((LPTASKCALLBACK)midiThread,
  293. &pClient->ThreadHandle,
  294. (DWORD_PTR)pClient);
  295. if (mRet != MMSYSERR_NOERROR) {
  296. midiCleanUp(pClient);
  297. return MMSYSERR_NOMEM;
  298. }
  299. //
  300. // Make sure the thread has really started
  301. //
  302. WaitForSingleObject(pClient->AuxEvent2, INFINITE);
  303. }
  304. //
  305. // give the client my driver dw
  306. //
  307. {
  308. PMIDIALLOC *pUserHandle;
  309. pUserHandle = (PMIDIALLOC *)dwUser;
  310. *pUserHandle = pClient;
  311. }
  312. //
  313. // sent client his OPEN callback message
  314. //
  315. midiCallback(pClient, DeviceType == MidiOutDevice ? MOM_OPEN : MIM_OPEN,
  316. 0L, 0L);
  317. return MMSYSERR_NOERROR;
  318. }
  319. /****************************************************************************
  320. * @doc INTERNAL
  321. *
  322. * @api void | midiCleanUp | Free resources for a midi device
  323. *
  324. * @parm PMIDIALLOC | pClient | Pointer to a MIDIALLOC structure describing
  325. * resources to be freed.
  326. *
  327. * @rdesc There is no return value.
  328. *
  329. * @comm If the pointer to the resource is NULL then the resource has not
  330. * been allocated.
  331. ***************************************************************************/
  332. STATIC void midiCleanUp(PMIDIALLOC pClient)
  333. {
  334. if (pClient->hDev != INVALID_HANDLE_VALUE) {
  335. CloseHandle(pClient->hDev);
  336. }
  337. if (pClient->AuxEvent1) {
  338. CloseHandle(pClient->AuxEvent1);
  339. }
  340. if (pClient->AuxEvent2) {
  341. CloseHandle(pClient->AuxEvent2);
  342. }
  343. if (pClient->Event) {
  344. CloseHandle(pClient->Event);
  345. }
  346. HeapFree(hHeap, 0, (LPSTR)pClient);
  347. }
  348. /****************************************************************************
  349. * @doc INTERNAL
  350. *
  351. * @api DWORD | midiOutWrite | Synchronously process a midi output
  352. * buffer.
  353. *
  354. * @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
  355. *
  356. * @parm PMIDIALLOC | pClient | The data associated with the logical midi
  357. * device.
  358. *
  359. * @rdesc A MMSYS... type return code for the application.
  360. ***************************************************************************/
  361. STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient)
  362. {
  363. DWORD BytesReturned;
  364. //
  365. // Try passing the request to our driver
  366. // We operate synchronously but allow for the driver to operate
  367. // asynchronously by waiting on an event.
  368. //
  369. if (!DeviceIoControl(
  370. pClient->hDev,
  371. IOCTL_MIDI_PLAY,
  372. (PVOID)pData, // Input buffer
  373. Len, // Input buffer size
  374. NULL, // Output buffer
  375. 0, // Output buffer size
  376. &BytesReturned,
  377. NULL)) {
  378. return sndTranslateStatus();
  379. }
  380. return MMSYSERR_NOERROR;
  381. }
  382. /****************************************************************************
  383. * @doc INTERNAL
  384. *
  385. * @api DWORD | midiInPutBuffer | Pass a buffer to receive midi input
  386. *
  387. * @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
  388. *
  389. * @parm PMIDIALLOC | pClient | The data associated with the logical midi
  390. * device.
  391. *
  392. * @rdesc A MMSYS... type return code for the application.
  393. ***************************************************************************/
  394. STATIC MMRESULT midiInPutBuffer(PLOCALMIDIHDR pHdr, PMIDIALLOC pClient)
  395. {
  396. DWORD BytesReturned;
  397. BOOL Result;
  398. WinAssert(!pHdr->Done); // Flag should be clear ready for setting by Apc
  399. //
  400. // midiMessages serializes these calls using ENTER_MM_HANDLE
  401. //
  402. //
  403. // Try passing the request to our driver
  404. // We operate synchronously but allow for the driver to operate
  405. // asynchronously by waiting on an event.
  406. //
  407. Result = ReadFileEx(
  408. pClient->hDev,
  409. (LPVOID)&pHdr->MidiData,
  410. sizeof(pHdr->ExtraData) +
  411. sizeof(MIDI_DD_INPUT_DATA),
  412. &pHdr->Ovl,
  413. midiInOvl);
  414. //
  415. // Put the buffer in our queue
  416. //
  417. if (Result || GetLastError() == ERROR_IO_PENDING) {
  418. PLOCALMIDIHDR *ppHdr;
  419. pHdr->lpNext = NULL;
  420. ppHdr = &pClient->Mid->DeviceQueue;
  421. while (*ppHdr) {
  422. ppHdr = &(*ppHdr)->lpNext;
  423. }
  424. *ppHdr = pHdr;
  425. return MMSYSERR_NOERROR;
  426. }
  427. return sndTranslateStatus();
  428. }
  429. /****************************************************************************
  430. * @doc INTERNAL
  431. *
  432. * @api DWORD | midiInWrite | Pass a new buffer to the Auxiliary thread for
  433. * a midi device.
  434. *
  435. * @parm LPMIDIHDR | pHdr | Pointer to a midit buffer
  436. *
  437. * @parm PMIDIALLOC | pClient | The data associated with the logical midi
  438. * device.
  439. *
  440. * @rdesc A MMSYS... type return code for the application.
  441. *
  442. * @comm The buffer flags are set and the buffer is passed to the auxiliary
  443. * device task for processing.
  444. ***************************************************************************/
  445. STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient)
  446. {
  447. //
  448. // Put the request at the end of our queue.
  449. //
  450. pHdr->dwFlags |= MHDR_INQUEUE;
  451. pHdr->dwFlags &= ~MHDR_DONE;
  452. pClient->AuxParam.pHdr = pHdr;
  453. return midiThreadCall(MidiThreadAddBuffer, pClient);
  454. }
  455. /****************************************************************************
  456. * @doc INTERNAL
  457. *
  458. * @api DWORD | midiSetState | Set a midi device to a given state
  459. *
  460. * @parm PMIDIALLOC | pClient | The data associated with the logical midi
  461. * output device.
  462. *
  463. * @parm ULONG | State | The new state
  464. *
  465. * @rdesc A MMSYS... type return code for the application.
  466. ***************************************************************************/
  467. STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State)
  468. {
  469. MMRESULT mRc;
  470. mRc = sndSetHandleData(pClient->hDev,
  471. sizeof(State),
  472. &State,
  473. IOCTL_MIDI_SET_STATE,
  474. pClient->Event);
  475. midiFlush(pClient);
  476. return mRc;
  477. }
  478. /****************************************************************************
  479. * @doc INTERNAL
  480. *
  481. * @api DWORD | midiThreadCall | Set the function for the thread to perform
  482. * and 'call' the thread using the event pair mechanism.
  483. *
  484. * @parm MIDITHREADFUNCTION | Function | The function to perform
  485. *
  486. * @parm PMIDIALLOC | Our logical device data
  487. *
  488. * @rdesc An MMSYS... type return value suitable for returning to the
  489. * application
  490. *
  491. * @comm The AuxParam field in the device data is the 'input' to
  492. * the function processing loop in MidiThread().
  493. ***************************************************************************/
  494. STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient)
  495. {
  496. //
  497. // Set the function code
  498. //
  499. pClient->AuxFunction = Function;
  500. //
  501. // Kick off the thread
  502. //
  503. SetEvent(pClient->AuxEvent1);
  504. //
  505. // Wait for it to complete
  506. //
  507. WaitForSingleObject(pClient->AuxEvent2, INFINITE);
  508. //
  509. // Return the return code that our task set.
  510. //
  511. return pClient->AuxReturnCode;
  512. }
  513. /****************************************************************************
  514. * @doc INTERNAL
  515. *
  516. * @api void | midiInApc | Apc routine. Called when a kernel sound driver
  517. * completes processing of a midi buffer.
  518. *
  519. * @parm PVOID | ApcContext | The Apc parameter. In our case this is a
  520. * pointer to our midi device data.
  521. *
  522. * @parm PIO_STATUS_BLOCK | pIosb | Pointer to the Io status block
  523. * used for the request.
  524. *
  525. * @rdesc There is no return code.
  526. ***************************************************************************/
  527. STATIC void midiInOvl(DWORD dwRet, DWORD dwBytesReturned, LPOVERLAPPED pOverlap)
  528. {
  529. PLOCALMIDIHDR pHdr;
  530. pHdr = ((PLOCALMIDIHDR)pOverlap);
  531. WinAssert(((PMIDIALLOC)pHdr->pClient)->DeviceType == MidiInDevice);
  532. //
  533. // Note that the buffer is complete. We don't do anything else here
  534. // because funny things happen if we call the client's callback
  535. // routine from within an Apc.
  536. //
  537. pHdr->BytesReturned = dwBytesReturned;
  538. pHdr->Done = TRUE;
  539. }
  540. /****************************************************************************
  541. * @doc INTERNAL
  542. *
  543. * @api void | midiFlush | Buffer completion routine. This completes
  544. * the work of the Apc routine at below Apc priority. This gets
  545. * round the nasty situations arising when the user's callback
  546. * causes more apcs to run (I strongly suspect this is a kernel
  547. * but).
  548. *
  549. * @parm PMIDIALLOC | pClient | The client's handle data
  550. *
  551. * @rdesc There is no return code.
  552. ***************************************************************************/
  553. STATIC void midiFlush(PMIDIALLOC pClient)
  554. {
  555. //
  556. // Process any completed buffers - the Apc routine
  557. // set the 'Done' flag in any completed requests.
  558. // Note that the call to the user's callback can
  559. // cause more requests to become complete
  560. //
  561. if (pClient->DeviceType == MidiInDevice) { // Output is synchronous
  562. while (pClient->Mid->DeviceQueue &&
  563. pClient->Mid->DeviceQueue->Done) {
  564. PLOCALMIDIHDR pHdr;
  565. pHdr = pClient->Mid->DeviceQueue;
  566. //
  567. // Clear our flag ready for next time
  568. //
  569. pHdr->Done = FALSE;
  570. //
  571. // Take buffer off the device queue
  572. //
  573. pClient->Mid->DeviceQueue = pHdr->lpNext;
  574. //
  575. // Grab the latest time estimate - convert from 100ns units
  576. // to milliseconds
  577. //
  578. pClient->Mid->dwCurTime =
  579. (DWORD)(pHdr->MidiData.Time.QuadPart / 10000);
  580. //
  581. // Complete our buffer
  582. //
  583. if (!pClient->Mid->Bad) {
  584. int i;
  585. for (i = 0;
  586. i + sizeof(LARGE_INTEGER) < pHdr->BytesReturned;
  587. i++) {
  588. midByteRec(pClient, pHdr->MidiData.Data[i]);
  589. }
  590. //
  591. // Requeue our buffer if we're still recording
  592. //
  593. if (pClient->Mid->fMidiInStarted) {
  594. if (midiInPutBuffer(pHdr, pClient) != MMSYSERR_NOERROR) {
  595. pClient->Mid->Bad = TRUE;
  596. }
  597. }
  598. }
  599. } // End of processing completed buffers
  600. }
  601. }
  602. /****************************************************************************
  603. * @doc INTERNAL
  604. *
  605. * @api DWORD | midiThread | Midi device auxiliary thread.
  606. *
  607. * @parm LPVOID | lpParameter | The thread parameter. In our case this is a
  608. * pointer to our midi device data.
  609. *
  610. * @rdesc Thread return code.
  611. ***************************************************************************/
  612. STATIC DWORD midiThread(LPVOID lpParameter)
  613. {
  614. PMIDIALLOC pClient;
  615. BOOL Close;
  616. Close = FALSE;
  617. pClient = (PMIDIALLOC)lpParameter;
  618. //
  619. // Set our thread to high priority so we don't fail to pass
  620. // new buffers to the device when we get them back. Also
  621. // we don't want any gaps if callbacks are meant to play
  622. // notes just received.
  623. //
  624. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  625. //
  626. // We start notifying our creator we have started and
  627. // waiting for something to do.
  628. //
  629. SetEvent(pClient->AuxEvent2);
  630. WaitForSingleObject(pClient->AuxEvent1, INFINITE);
  631. //
  632. // Now we're going
  633. //
  634. for(;;) {
  635. //
  636. // Initialize our return code
  637. //
  638. pClient->AuxReturnCode = MMSYSERR_NOERROR;
  639. //
  640. // Decode function number to perform
  641. //
  642. switch (pClient->AuxFunction) {
  643. case MidiThreadAddBuffer:
  644. //
  645. // Add the buffer to our list to be processed
  646. //
  647. {
  648. LPMIDIHDR *pHdrSearch;
  649. pClient->AuxParam.pHdr->lpNext = NULL;
  650. pHdrSearch = &pClient->lpMIQueue;
  651. while (*pHdrSearch) {
  652. pHdrSearch = &(*pHdrSearch)->lpNext;
  653. }
  654. *pHdrSearch = pClient->AuxParam.pHdr;
  655. }
  656. break;
  657. case MidiThreadSetState:
  658. switch (pClient->AuxParam.State) {
  659. case MIDI_DD_RECORD:
  660. //
  661. // Start means we must add our buffers to the driver's list
  662. //
  663. if (!pClient->Mid->fMidiInStarted && !pClient->Mid->Bad) {
  664. int i;
  665. for (i = 0; i < NUMBER_OF_LOCAL_MIDI_BUFFERS; i++) {
  666. pClient->AuxReturnCode =
  667. midiInPutBuffer(&pClient->Mid->Bufs[i], pClient);
  668. if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
  669. //
  670. // Failed to add our buffer so give up and
  671. // get our buffers back !
  672. //
  673. pClient->Mid->Bad = TRUE;
  674. break;
  675. }
  676. }
  677. //
  678. // Set Device state. By issuing state changes on THIS
  679. // thread the calling thread can be sure that all Apc's
  680. // generated by buffer completions will complete
  681. // BEFORE this function completes.
  682. //
  683. pClient->AuxReturnCode =
  684. midiSetState(pClient, pClient->AuxParam.State);
  685. //
  686. // If this failed then get our buffers back,
  687. // otherwise set our new state
  688. //
  689. if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
  690. pClient->Mid->Bad = TRUE;
  691. } else {
  692. pClient->Mid->fMidiInStarted = TRUE;
  693. }
  694. } else {
  695. //
  696. // Already started or bad
  697. //
  698. }
  699. break;
  700. case MIDI_DD_STOP:
  701. //
  702. // Set Device state. By issuing state changes on THIS
  703. // thread the calling thread can be sure that all Apc's
  704. // generated by buffer completions will complete
  705. // BEFORE this function completes.
  706. //
  707. if (pClient->Mid->fMidiInStarted) {
  708. pClient->Mid->fMidiInStarted = FALSE;
  709. //
  710. // RESET so we get our buffers back
  711. //
  712. pClient->AuxReturnCode =
  713. midiSetState(pClient, MIDI_DD_RESET);
  714. WinAssert(!pClient->Mid->DeviceQueue);
  715. if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
  716. midSendPartBuffer(pClient);
  717. }
  718. }
  719. break;
  720. case MIDI_DD_RESET:
  721. //
  722. // Set Device state. By issuing state changes on THIS
  723. // thread the calling thread can be sure that all Apc's
  724. // generated by buffer completions will complete
  725. // BEFORE this function completes.
  726. //
  727. if (pClient->Mid->fMidiInStarted) {
  728. pClient->Mid->fMidiInStarted = FALSE;
  729. pClient->AuxReturnCode =
  730. midiSetState(pClient, pClient->AuxParam.State);
  731. WinAssert(!pClient->Mid->DeviceQueue);
  732. if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
  733. pClient->Mid->Bad = FALSE; // Recovered !!
  734. midSendPartBuffer(pClient);
  735. }
  736. }
  737. //
  738. // We zero the input queue anyway - compatibility with
  739. // windows 3.1
  740. //
  741. midFreeQ(pClient);
  742. break;
  743. }
  744. break;
  745. case MidiThreadSetData:
  746. {
  747. pClient->AuxReturnCode =
  748. sndSetHandleData(pClient->hDev,
  749. pClient->AuxParam.GetSetData.DataLen,
  750. pClient->AuxParam.GetSetData.pData,
  751. pClient->AuxParam.GetSetData.Function,
  752. pClient->Event);
  753. }
  754. break;
  755. case MidiThreadClose:
  756. //
  757. // Try to complete.
  758. // If we're completed all our buffers then we can.
  759. // otherwise we can't
  760. //
  761. if (pClient->lpMIQueue == NULL) {
  762. pClient->AuxReturnCode = MMSYSERR_NOERROR;
  763. Close = TRUE;
  764. } else {
  765. pClient->AuxReturnCode = MIDIERR_STILLPLAYING;
  766. }
  767. break;
  768. default:
  769. WinAssert(FALSE); // Invalid call
  770. break;
  771. }
  772. //
  773. // Trap invalid callers
  774. //
  775. pClient->AuxFunction = MidiThreadInvalid;
  776. //
  777. // See if apcs completed
  778. //
  779. midiFlush(pClient);
  780. //
  781. // Release the caller
  782. //
  783. SetEvent(pClient->AuxEvent2);
  784. //
  785. // Complete ?
  786. //
  787. if (Close) {
  788. break;
  789. }
  790. //
  791. // Wait for more !
  792. //
  793. while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
  794. WAIT_IO_COMPLETION) {
  795. //
  796. // Complete buffers whose Apcs ran
  797. //
  798. midiFlush(pClient);
  799. }
  800. }
  801. //
  802. // We've been asked to terminte
  803. //
  804. return 1;
  805. }
  806. /****************************************************************************
  807. * @doc INTERNAL
  808. *
  809. * @api void | midiCallback | This calls DriverCallback for a MIDIHDR.
  810. *
  811. * @parm PMIDIALLOC | pMidi | Pointer to midi device.
  812. *
  813. * @parm DWORD | msg | The message.
  814. *
  815. * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
  816. *
  817. * @rdesc There is no return value.
  818. ***************************************************************************/
  819. void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD_PTR dw1, DWORD_PTR dw2)
  820. {
  821. // invoke the callback function, if it exists. dwFlags contains
  822. // midi driver specific flags in the LOWORD and generic driver
  823. // flags in the HIWORD
  824. if (pMidi->dwCallback)
  825. DriverCallback(pMidi->dwCallback, // user's callback DWORD
  826. HIWORD(pMidi->dwFlags), // callback flags
  827. (HDRVR)pMidi->hMidi, // handle to the midi device
  828. msg, // the message
  829. pMidi->dwInstance, // user's instance data
  830. dw1, // first DWORD
  831. dw2); // second DWORD
  832. }
  833. /****************************************************************************
  834. This function conforms to the standard Midi input driver message proc
  835. (midMessage), which is documented in mmddk.d.
  836. ****************************************************************************/
  837. DWORD APIENTRY midMessage(DWORD id, DWORD msg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  838. {
  839. PMIDIALLOC pInClient;
  840. switch (msg) {
  841. case MIDM_GETNUMDEVS:
  842. D2(("MIDM_GETNUMDEVS"));
  843. return sndGetNumDevs(MidiInDevice);
  844. case MIDM_GETDEVCAPS:
  845. D2(("MIDM_GETDEVCAPS"));
  846. return midiGetDevCaps(id, MidiInDevice, (LPBYTE)dwParam1,
  847. (DWORD)dwParam2);
  848. case MIDM_OPEN:
  849. D2(("MIDM_OPEN"));
  850. return midiOpen(MidiInDevice, id, dwUser, dwParam1, dwParam2);
  851. case MIDM_CLOSE:
  852. D2(("MIDM_CLOSE"));
  853. pInClient = (PMIDIALLOC)dwUser;
  854. //
  855. // Call our task to see if it's ready to complete
  856. //
  857. if (midiThreadCall(MidiThreadClose, pInClient) != 0L) {
  858. return MIDIERR_STILLPLAYING;
  859. }
  860. //
  861. // Wait for our thread to terminate and close our device
  862. //
  863. WaitForSingleObject(pInClient->ThreadHandle, INFINITE);
  864. CloseHandle(pInClient->ThreadHandle);
  865. //
  866. // Tell the caller we're done
  867. //
  868. midiCallback(pInClient, MIM_CLOSE, 0L, 0L);
  869. midiCleanUp(pInClient);
  870. return MMSYSERR_NOERROR;
  871. case MIDM_ADDBUFFER:
  872. D2(("MIDM_ADDBUFFER"));
  873. // check if it's been prepared
  874. if (!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_PREPARED))
  875. return MIDIERR_UNPREPARED;
  876. WinAssert(!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE));
  877. // if it is already in our Q, then we cannot do this
  878. if ( ((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE )
  879. return ( MIDIERR_STILLPLAYING );
  880. // store the pointer to my MIDIALLOC structure in the midihdr
  881. pInClient = (PMIDIALLOC)dwUser;
  882. ((LPMIDIHDR)dwParam1)->reserved = (DWORD_PTR)(LPSTR)pInClient;
  883. return midiInWrite((LPMIDIHDR)dwParam1, pInClient);
  884. case MIDM_STOP:
  885. D2(("MIDM_PAUSE"));
  886. pInClient = (PMIDIALLOC)dwUser;
  887. pInClient->AuxParam.State = MIDI_DD_STOP;
  888. return midiThreadCall(MidiThreadSetState, pInClient);
  889. case MIDM_START:
  890. D2(("MIDM_RESTART"));
  891. pInClient = (PMIDIALLOC)dwUser;
  892. pInClient->AuxParam.State = MIDI_DD_RECORD;
  893. return midiThreadCall(MidiThreadSetState, pInClient);
  894. case MIDM_RESET:
  895. D2(("MIDM_RESET"));
  896. pInClient = (PMIDIALLOC)dwUser;
  897. pInClient->AuxParam.State = MIDI_DD_RESET;
  898. return midiThreadCall(MidiThreadSetState, pInClient);
  899. default:
  900. return MMSYSERR_NOTSUPPORTED;
  901. }
  902. //
  903. // Should not get here
  904. //
  905. WinAssert(0);
  906. return MMSYSERR_NOTSUPPORTED;
  907. }
  908. /****************************************************************************
  909. This function conforms to the standard Midi output driver message proc
  910. (modMessage), which is documented in mmddk.d.
  911. ****************************************************************************/
  912. DWORD APIENTRY modMessage(DWORD id, DWORD msg, DWORD_PTR dwUser, DWORD_PTR dwParam1,
  913. DWORD_PTR dwParam2)
  914. {
  915. PMIDIALLOC pOutClient;
  916. switch (msg) {
  917. case MODM_GETNUMDEVS:
  918. D2(("MODM_GETNUMDEVS"));
  919. return sndGetNumDevs(MidiOutDevice);
  920. case MODM_GETDEVCAPS:
  921. D2(("MODM_GETDEVCAPS"));
  922. return midiGetDevCaps(id, MidiOutDevice, (LPBYTE)dwParam1,
  923. (DWORD)dwParam2);
  924. case MODM_OPEN:
  925. D2(("MODM_OPEN"));
  926. return midiOpen(MidiOutDevice, id, dwUser, dwParam1, dwParam2);
  927. case MODM_CLOSE:
  928. D2(("MODM_CLOSE"));
  929. pOutClient = (PMIDIALLOC)dwUser;
  930. midiCallback(pOutClient, MOM_CLOSE, 0L, 0L);
  931. //
  932. // Close our device
  933. //
  934. midiCleanUp(pOutClient);
  935. return MMSYSERR_NOERROR;
  936. case MODM_DATA:
  937. D2(("MODM_DATA"));
  938. {
  939. int i;
  940. BYTE b[4];
  941. for (i = 0; i < 4; i ++) {
  942. b[i] = (BYTE)(dwParam1 % 256);
  943. dwParam1 /= 256;
  944. }
  945. return midiOutWrite(b, modMIDIlength((PMIDIALLOC)dwUser, b[0]),
  946. (PMIDIALLOC)dwUser);
  947. }
  948. case MODM_LONGDATA:
  949. D2(("MODM_LONGDATA"));
  950. pOutClient = (PMIDIALLOC)dwUser;
  951. {
  952. LPMIDIHDR lpHdr;
  953. MMRESULT mRet;
  954. //
  955. // check if it's been prepared
  956. //
  957. lpHdr = (LPMIDIHDR)dwParam1;
  958. if (!(lpHdr->dwFlags & MHDR_PREPARED)) {
  959. return MIDIERR_UNPREPARED;
  960. }
  961. //
  962. //
  963. //
  964. mRet = midiOutWrite(lpHdr->lpData, lpHdr->dwBufferLength,
  965. pOutClient);
  966. // note that clearing the done bit or setting the inqueue bit
  967. // isn't necessary here since this function is synchronous -
  968. // the client will not get control back until it's done.
  969. lpHdr->dwFlags |= MHDR_DONE;
  970. // notify client
  971. if (mRet == MMSYSERR_NOERROR) {
  972. midiCallback(pOutClient, MOM_DONE, (DWORD_PTR)lpHdr, 0L);
  973. }
  974. return mRet;
  975. }
  976. case MODM_RESET:
  977. D2(("MODM_RESET"));
  978. return midiSetState((PMIDIALLOC)dwUser, MIDI_DD_RESET);
  979. case MODM_SETVOLUME:
  980. D2(("MODM_SETVOLUME"));
  981. //pOutClient = (PMIDIALLOC)dwUser;
  982. //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
  983. //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
  984. //pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_SET_VOLUME;
  985. //return midiThreadCall(MidiThreadSetData, pOutClient);
  986. return sndSetData(MidiOutDevice, id, sizeof(DWORD),
  987. (PBYTE)&dwParam1, IOCTL_MIDI_SET_VOLUME);
  988. case MODM_GETVOLUME:
  989. D2(("MODM_GETVOLUME"));
  990. //pOutClient = (PMIDIALLOC)dwUser;
  991. //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
  992. //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
  993. //pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_GET_VOLUME;
  994. //return midiThreadCall(MidiThreadGetData, pOutClient);
  995. return sndGetData(MidiOutDevice, id, sizeof(DWORD),
  996. (PBYTE)dwParam1, IOCTL_MIDI_GET_VOLUME);
  997. case MODM_CACHEPATCHES:
  998. D2(("MODM_CACHEPATCHES"));
  999. pOutClient = (PMIDIALLOC)dwUser;
  1000. {
  1001. MIDI_DD_CACHE_PATCHES AppData;
  1002. DWORD BytesReturned;
  1003. AppData.Bank = HIWORD(dwParam2);
  1004. AppData.Flags = LOWORD(dwParam2);
  1005. memcpy(AppData.Patches, (PVOID)dwParam1, sizeof(AppData.Patches));
  1006. return DeviceIoControl(
  1007. pOutClient->hDev,
  1008. IOCTL_MIDI_CACHE_PATCHES,
  1009. (PVOID)&AppData,
  1010. sizeof(AppData),
  1011. NULL,
  1012. 0,
  1013. &BytesReturned,
  1014. NULL) ?
  1015. MMSYSERR_NOERROR :
  1016. sndTranslateStatus();
  1017. }
  1018. case MODM_CACHEDRUMPATCHES:
  1019. D2(("MODM_CACHEDRUMPATCHES"));
  1020. pOutClient = (PMIDIALLOC)dwUser;
  1021. {
  1022. MIDI_DD_CACHE_DRUM_PATCHES AppData;
  1023. DWORD BytesReturned;
  1024. AppData.Patch = HIWORD(dwParam2);
  1025. AppData.Flags = LOWORD(dwParam2);
  1026. memcpy(AppData.DrumPatches, (PVOID)dwParam1,
  1027. sizeof(AppData.DrumPatches));
  1028. return DeviceIoControl(
  1029. pOutClient->hDev,
  1030. IOCTL_MIDI_CACHE_DRUM_PATCHES,
  1031. (PVOID)&AppData,
  1032. sizeof(AppData),
  1033. NULL,
  1034. 0,
  1035. &BytesReturned,
  1036. NULL) ?
  1037. MMSYSERR_NOERROR :
  1038. sndTranslateStatus();
  1039. }
  1040. default:
  1041. return MMSYSERR_NOTSUPPORTED;
  1042. }
  1043. //
  1044. // Should not get here
  1045. //
  1046. WinAssert(0);
  1047. return MMSYSERR_NOTSUPPORTED;
  1048. }
  1049. /***********************************************************************
  1050. UTILITY ROUTINES PORTED DIRECTLY FROM WIN 3.1
  1051. ***********************************************************************/
  1052. /****************************************************************************
  1053. * @doc INTERNAL
  1054. *
  1055. * @api int | modMIDIlength | Get the length of a short midi message.
  1056. *
  1057. * @parm DWORD | dwMessage | The message.
  1058. *
  1059. * @rdesc Returns the length of the message.
  1060. ***************************************************************************/
  1061. STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b)
  1062. {
  1063. if (b >= 0xF8) { // system realtime
  1064. /* for realtime messages, leave running status untouched */
  1065. return 1; // write one byte
  1066. }
  1067. switch (b) {
  1068. case 0xF0: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
  1069. pClient->l = 1;
  1070. return pClient->l;
  1071. case 0xF1: case 0xF3:
  1072. pClient->l = 2;
  1073. return pClient->l;
  1074. case 0xF2:
  1075. pClient->l = 3;
  1076. return pClient->l;
  1077. }
  1078. switch (b & 0xF0) {
  1079. case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0:
  1080. pClient->l = 3;
  1081. return pClient->l;
  1082. case 0xC0: case 0xD0:
  1083. pClient->l = 2;
  1084. return pClient->l;
  1085. }
  1086. return (pClient->l - 1); // uses previous value if data byte (running status)
  1087. }
  1088. /****************************************************************************
  1089. * @doc INTERNAL
  1090. *
  1091. * @api void | midBufferWrite | This function writes a byte into the long
  1092. * message buffer. If the buffer is full or a SYSEX_ERROR or
  1093. * end-of-sysex byte is received, the buffer is marked as 'done' and
  1094. * it's owner is called back.
  1095. *
  1096. * @parm BYTE | byte | The byte received.
  1097. *
  1098. * @rdesc There is no return value
  1099. ***************************************************************************/
  1100. STATIC void midBufferWrite(PMIDIALLOC pClient, BYTE byte)
  1101. {
  1102. LPMIDIHDR lpmh;
  1103. UINT msg;
  1104. // if no buffers, nothing happens
  1105. if (pClient->lpMIQueue == NULL)
  1106. return;
  1107. lpmh = pClient->lpMIQueue;
  1108. if (byte == SYSEX_ERROR) {
  1109. D2(("sysexerror"));
  1110. msg = MIM_LONGERROR;
  1111. }
  1112. else {
  1113. D2(("bufferwrite"));
  1114. msg = MIM_LONGDATA;
  1115. *((LPSTR)(lpmh->lpData) + pClient->Mid->dwCurData++) = byte;
  1116. }
  1117. // if end of sysex, buffer full or error, send them back the buffer
  1118. if ((byte == SYSEX_ERROR) || (byte == 0xF7) || (pClient->Mid->dwCurData >= lpmh->dwBufferLength)) {
  1119. D2(("bufferdone"));
  1120. pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
  1121. lpmh->dwBytesRecorded = pClient->Mid->dwCurData;
  1122. pClient->Mid->dwCurData = 0L;
  1123. lpmh->dwFlags |= MHDR_DONE;
  1124. lpmh->dwFlags &= ~MHDR_INQUEUE;
  1125. midiCallback(pClient, msg, (DWORD_PTR)lpmh, pClient->Mid->dwMsgTime);
  1126. }
  1127. return;
  1128. }
  1129. /****************************************************************************
  1130. * @doc INTERNAL
  1131. *
  1132. * @api void | midByteRec | This function constructs the complete midi
  1133. * messages from the individual bytes received and passes the message
  1134. * to the client via his callback.
  1135. *
  1136. * @parm WORD | word | The byte received is in the low order byte.
  1137. *
  1138. * @rdesc There is no return value
  1139. *
  1140. * @comm Note that currently running status isn't turned off on errors.
  1141. ***************************************************************************/
  1142. STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte)
  1143. {
  1144. if (!pClient->Mid->fMidiInStarted)
  1145. return;
  1146. // if it's a system realtime message, send it
  1147. // this does not affect running status or any current message
  1148. if (byte >= 0xF8) {
  1149. D2((" rt"));
  1150. midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwCurTime);
  1151. }
  1152. // else if it's a system common message
  1153. else if (byte >= 0xF0) {
  1154. if (pClient->Mid->fSysex) { // if we're in a sysex
  1155. pClient->Mid->fSysex = FALSE; // status byte during sysex ends it
  1156. if (byte == 0xF7)
  1157. {
  1158. midBufferWrite(pClient, 0xF7); // write in long message buffer
  1159. return;
  1160. }
  1161. else
  1162. midBufferWrite(pClient, SYSEX_ERROR); // secret code indicating error
  1163. }
  1164. if (pClient->Mid->dwMsg) { // throw away any incomplete short data
  1165. midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
  1166. pClient->Mid->dwMsg = 0L;
  1167. }
  1168. pClient->Mid->status = 0; // kill running status
  1169. pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
  1170. switch(byte) {
  1171. case 0xF0:
  1172. D2((" F0"));
  1173. pClient->Mid->fSysex = TRUE;
  1174. midBufferWrite(pClient, 0xF0);
  1175. break;
  1176. case 0xF7:
  1177. D2((" F7"));
  1178. if (!pClient->Mid->fSysex)
  1179. midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
  1180. // else already took care of it above
  1181. break;
  1182. case 0xF4: // system common, no data bytes
  1183. case 0xF5:
  1184. case 0xF6:
  1185. D2((" status0"));
  1186. midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwMsgTime);
  1187. pClient->Mid->bBytePos = 0;
  1188. break;
  1189. case 0xF1: // system common, one data byte
  1190. case 0xF3:
  1191. D2((" status1"));
  1192. pClient->Mid->dwMsg |= byte;
  1193. pClient->Mid->bBytesLeft = 1;
  1194. pClient->Mid->bBytePos = 1;
  1195. break;
  1196. case 0xF2: // system common, two data bytes
  1197. D2((" status2"));
  1198. pClient->Mid->dwMsg |= byte;
  1199. pClient->Mid->bBytesLeft = 2;
  1200. pClient->Mid->bBytePos = 1;
  1201. break;
  1202. }
  1203. }
  1204. // else if it's a channel message
  1205. else if (byte >= 0x80) {
  1206. if (pClient->Mid->fSysex) { // if we're in a sysex
  1207. pClient->Mid->fSysex = FALSE; // status byte during sysex ends it
  1208. midBufferWrite(pClient, SYSEX_ERROR); // secret code indicating error
  1209. }
  1210. if (pClient->Mid->dwMsg) { // throw away any incomplete data
  1211. midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
  1212. pClient->Mid->dwMsg = 0L;
  1213. }
  1214. pClient->Mid->status = byte; // save for running status
  1215. pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
  1216. pClient->Mid->dwMsg |= byte;
  1217. pClient->Mid->bBytePos = 1;
  1218. switch(byte & 0xF0) {
  1219. case 0xC0: // channel message, one data byte
  1220. case 0xD0:
  1221. D2((" status1"));
  1222. pClient->Mid->bBytesLeft = 1;
  1223. break;
  1224. case 0x80: // channel message, two data bytes
  1225. case 0x90:
  1226. case 0xA0:
  1227. case 0xB0:
  1228. case 0xE0:
  1229. D2((" status2"));
  1230. pClient->Mid->bBytesLeft = 2;
  1231. break;
  1232. }
  1233. }
  1234. // else if it's an expected data byte for a long message
  1235. else if (pClient->Mid->fSysex) {
  1236. D2((" sxdata"));
  1237. midBufferWrite(pClient, byte); // write in long message buffer
  1238. }
  1239. // else if it's an expected data byte for a short message
  1240. else if (pClient->Mid->bBytePos != 0) {
  1241. D2((" data"));
  1242. if ((pClient->Mid->status) && (pClient->Mid->bBytePos == 1)) { // if running status
  1243. pClient->Mid->dwMsg |= pClient->Mid->status;
  1244. pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
  1245. }
  1246. pClient->Mid->dwMsg += (DWORD)byte << ((pClient->Mid->bBytePos++) * 8);
  1247. if (--pClient->Mid->bBytesLeft == 0) {
  1248. midiCallback(pClient, MIM_DATA, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
  1249. pClient->Mid->dwMsg = 0L;
  1250. if (pClient->Mid->status) {
  1251. pClient->Mid->bBytesLeft = pClient->Mid->bBytePos - (BYTE)1;
  1252. pClient->Mid->bBytePos = 1;
  1253. }
  1254. else {
  1255. pClient->Mid->bBytePos = 0;
  1256. }
  1257. }
  1258. }
  1259. // else if it's an unexpected data byte
  1260. else {
  1261. D2((" baddata"));
  1262. midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
  1263. }
  1264. return;
  1265. }
  1266. /****************************************************************************
  1267. * @doc INTERNAL
  1268. *
  1269. * @api void | midFreeQ | Free all buffers in the MIQueue.
  1270. *
  1271. * @comm Currently this is only called after sending off any partially filled
  1272. * buffers, so all buffers here are empty. The timestamp value is 0 in
  1273. * this case.
  1274. *
  1275. * @rdesc There is no return value.
  1276. ***************************************************************************/
  1277. STATIC void midFreeQ(PMIDIALLOC pClient)
  1278. {
  1279. LPMIDIHDR lpH, lpN;
  1280. lpH = pClient->lpMIQueue; // point to top of the queue
  1281. pClient->lpMIQueue = NULL; // mark the queue as empty
  1282. pClient->Mid->dwCurData = 0L;
  1283. while (lpH) {
  1284. lpN = lpH->lpNext;
  1285. lpH->dwFlags |= MHDR_DONE;
  1286. lpH->dwFlags &= ~MHDR_INQUEUE;
  1287. lpH->dwBytesRecorded = 0;
  1288. midiCallback(pClient, MIM_LONGDATA, (DWORD_PTR)lpH,
  1289. pClient->Mid->dwCurTime);
  1290. lpH = lpN;
  1291. }
  1292. }
  1293. /****************************************************************************
  1294. * @doc INTERNAL
  1295. *
  1296. * @api void | midSendPartBuffer | This function is called from midStop().
  1297. * It looks at the buffer at the head of the queue and, if it contains
  1298. * any data, marks it as done as sends it back to the client.
  1299. *
  1300. * @rdesc The return value is the number of bytes transfered. A value of zero
  1301. * indicates that there was no more data in the input queue.
  1302. ***************************************************************************/
  1303. STATIC void midSendPartBuffer(PMIDIALLOC pClient)
  1304. {
  1305. LPMIDIHDR lpH;
  1306. if (pClient->lpMIQueue && pClient->Mid->dwCurData) {
  1307. lpH = pClient->lpMIQueue;
  1308. pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
  1309. lpH->dwFlags |= MHDR_DONE;
  1310. lpH->dwFlags &= ~MHDR_INQUEUE;
  1311. pClient->Mid->dwCurData = 0L;
  1312. midiCallback(pClient, MIM_LONGERROR, (DWORD_PTR)lpH,
  1313. pClient->Mid->dwMsgTime);
  1314. }
  1315. }