This is winmidi.c in view mode; [Download] [Up]
/************************************************************************ winmidi.c - Midi DLL for Common Music Copyright (c) 1993 Joseph Fosco This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author may be reached (Email) at the address b38669@anl.gov, or (US mail) at 15508 Brianne Lane, Oak Forest, IL 60452 *************************************************************************/ /*------------------------------------------------------------------ WINMIDI.C -- Dynamic Link Library module for Windows Multimedia MIDI FUNCTIONS TO BE CALLED FROM COMMON MUSIC (LISP) ------------------------------------------------------------------*/ #include <windows.h> #include <windowsx.h> #include <mmsystem.h> #define MIDI_NOTE_ON 0x90 #define MIDI_NOTE_OFF 0x80 #define MIDI_ACTIVE_SENSING 0xFE #define FF_MIDI_SUCCESS 0 #define MAX_TIMER_ACCURACY 0 #define MAX_WRITE_QUEUE_ITEMS 4000 #define MAX_READ_QUEUE_ITEMS 4000 #define MAX_SCHED_TIME 0xFFFFFFFF typedef union { DWORD dwMidiMsg; BYTE byMidiByte[4]; } MIDI_DATA; typedef struct read_queue_item{ MIDI_DATA MidiReadData; /* midi data received */ DWORD dwMidiTime; /* midi time this message was received */ WORD wLongMsg; /* indicates MIDI_DATA points to a buffer containing a long midi message (sysex) */ /* currently tnis is not used */ } READ_QUEUE_ITEM; typedef READ_QUEUE_ITEM FAR *LPREAD_QUEUE_ITEM; typedef struct read_queue_hdr{ LPREAD_QUEUE_ITEM lpReadQueue; /* Start of Midi In Buffer */ LPREAD_QUEUE_ITEM lpReadQueueEnd; /* End of Buffer (Last Byte+1) */ LPREAD_QUEUE_ITEM lpFirstOpenReadItem; /* Next Item to fill */ LPREAD_QUEUE_ITEM lpFirstNewReadItem; /* Next Item to read */ int iReadCount; /* Number of Items in Buffer */ } READ_QUEUE_HDR; typedef READ_QUEUE_HDR FAR *LPREAD_QUEUE_HDR; #if 0 typedef struct write_queue_item{ MIDI_DATA MidiWriteData; DWORD dwQuantaTime; int iNextEvent; int iPrevEvent; int iNextOpenItem; BYTE bFill1; BYTE bFill2; } WRITE_QUEUE_ITEM ; typedef struct{ struct write_queue_item Item[]; } WRITE_QUEUE; #endif typedef struct{ MIDI_DATA MidiWriteData; /* midi data to send */ DWORD dwQuantaTime; /* quanta time this event should occur at */ int iNextEvent; int iPrevEvent; int iNextOpenItem; BYTE bFill1; /* Filler to make this structure length */ BYTE bFill2; /* equal a power of 2 (for allocating > 64k) */ } WRITE_QUEUE_ITEM ; typedef struct{ WRITE_QUEUE_ITEM Item[]; }WRITE_QUEUE; typedef struct { WORD total_midi_in; WORD total_midi_out; }TOTAL_MIDI_PORTS_STRUCT ; WORD FAR PASCAL _export midiclose() ; void FAR PASCAL _export timer_callback(UINT wID, UINT wMsg, DWORD dwUser, DWORD dw1, DWORD dw2) ; void FAR PASCAL _export midi_in_callback(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, MIDI_DATA MidiInMsg, DWORD dwParam2); void FAR PASCAL _export midi_out_callback(HMIDIOUT hMidiOut, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) ; WORD FAR PASCAL _export midiflushreceive() ; WORD FAR PASCAL _export midiflushtransmit() ; WORD FAR PASCAL _export midiallnotesoff(DWORD qtime) ; void PASCAL SetMidiOutOpenItems(); TIMECAPS tc; WORD wTimerId = NULL; HMIDIOUT hMidiOut = NULL; HMIDIIN hMidiIn = NULL; WORD wQuantaSize = 1000; DWORD dwQuantaTime = 0; /* Current Quanta Time */ DWORD dwBaseTime = 0; /* Time (in milliseconds) when the Common Music timer was started */ DWORD dwMidiBaseTime = 0; /* Time (in milliseconds) when MIDI input was started. */ BOOL bTimerStarted = FALSE; /* TRUE when the timer is running */ BOOL bScheduling = FALSE; /* TRUE when pointers are being updated to schedule another event. When TRUE, MIDI output is disabled to avoid loosing events */ WRITE_QUEUE FAR * lpWriteQueue = NULL; int iFirstOpenWriteItem; int iLastOpenWriteItem; int iNextSchedEvent = -1; DWORD dwNextSchedTime = MAX_SCHED_TIME; int iLastSchedEvent = -1; DWORD dwLastSchedTime = 0; LPREAD_QUEUE_HDR lpFirstReadQueueHdr = NULL; int FAR PASCAL LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine) { /* Do not unlock data segment ! */ if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOCANDO) return(0); return(1); } int FAR PASCAL _export WEP (int nParam) { if (bTimerStarted) { timeKillEvent(wTimerId); timeEndPeriod(tc.wPeriodMin); } if (hMidiOut != NULL) midiclose(); return(1); } WORD FAR PASCAL _export midistarttimer() { if (1000000 / wQuantaSize > 1000 / tc.wPeriodMin) return(1); /* Timer can't handle requested resolution */ if (bTimerStarted) return(2); /* Timer already started */ if (timeBeginPeriod(tc.wPeriodMin) == TIMERR_NOCANDO) return(3); /* Cannot set timer resolution */ wTimerId = timeSetEvent((wQuantaSize / 1000), MAX_TIMER_ACCURACY, timer_callback, NULL, TIME_PERIODIC); if (!wTimerId) return(4); dwBaseTime = timeGetTime(); bTimerStarted = TRUE; return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midistoptimer() { if (!bTimerStarted) return(1); /* Timer is not running */ timeKillEvent(wTimerId); wTimerId = NULL; timeEndPeriod(wQuantaSize / 1000); bTimerStarted = FALSE; dwBaseTime = 0; dwQuantaTime = 0; return(FF_MIDI_SUCCESS); } DWORD FAR PASCAL _export midigettime() { if (bTimerStarted) return (dwQuantaTime); else return (0); } WORD FAR PASCAL _export midisettime(DWORD new_time) { if (!bTimerStarted) return(1); /* Timer must be running to set time */ dwBaseTime = timeGetTime() - (new_time * (wQuantaSize / 1000)); dwQuantaTime = new_time; return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midisetquantasize (DWORD new_quanta_size) { if (bTimerStarted) return (1); /* can't change wQuantaSize while timer is running */ /* Check if new_quanta_size is within the capabilites of the */ /* computer. Compare interrupts per second with interrupts */ /* per second. */ if (1000000/ new_quanta_size > 1000/ tc.wPeriodMin) return(2); else { wQuantaSize = new_quanta_size; return(FF_MIDI_SUCCESS); } } WORD FAR PASCAL _export midiopen(WORD portnum) { HANDLE hQueue; LPREAD_QUEUE_ITEM lpRdQ; LPREAD_QUEUE_HDR lpRdQHdr; WORD rtn; /* Allocate storage for queue for outgoing midi data */ lpWriteQueue = (WRITE_QUEUE FAR *) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, ((DWORD)sizeof(WRITE_QUEUE_ITEM) * MAX_WRITE_QUEUE_ITEMS)); if (!lpWriteQueue) return(100); /* Global storage accessed at interrupt time mest be Page locked */ if (GlobalPageLock(HIWORD(lpWriteQueue)) == 0) return(110); iFirstOpenWriteItem = 0; iLastOpenWriteItem = MAX_WRITE_QUEUE_ITEMS - 1; SetMidiOutOpenItems(); /* Allocate storage for incoming midi data */ /* First allocate storage for the header */ /* Then allocate storage for the incoming midi data queue */ hQueue = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)sizeof(READ_QUEUE_HDR)); if (hQueue == (HANDLE)NULL) return(150); lpRdQHdr = (LPREAD_QUEUE_HDR)GlobalLock(hQueue); if (lpRdQHdr == (LPREAD_QUEUE_HDR)NULL) { GlobalFree(hQueue); return(152); } /* Global storage accessed at interrupt time mest be Page locked */ if (GlobalPageLock(HIWORD(lpRdQHdr)) == 0) { GlobalFreePtr(lpRdQHdr); return(154); } hQueue = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)(sizeof(READ_QUEUE_ITEM) * MAX_READ_QUEUE_ITEMS)); if (hQueue == (HANDLE)NULL) { GlobalPageUnlock(HIWORD(lpRdQHdr)); GlobalFreePtr(lpRdQHdr); return(156); } lpRdQ = (LPREAD_QUEUE_ITEM)GlobalLock(hQueue); if (lpRdQ == (LPREAD_QUEUE_ITEM)NULL) { GlobalFree(hQueue); GlobalPageUnlock(HIWORD(lpRdQHdr)); GlobalFreePtr(lpRdQHdr); return(158); } /* Global storage accessed at interrupt time mest be Page locked */ if (GlobalPageLock(HIWORD(lpRdQ)) == 0) { GlobalFreePtr(lpRdQ); GlobalPageUnlock(HIWORD(lpRdQHdr)); GlobalFreePtr(lpRdQHdr); return(160); } /* Save pointer to first READ_QUEUE_HDR and */ /* initialize READ_QUEUE_HDR */ lpFirstReadQueueHdr = lpRdQHdr; lpFirstReadQueueHdr->lpReadQueue = lpRdQ; lpFirstReadQueueHdr->lpReadQueueEnd = lpRdQ + MAX_READ_QUEUE_ITEMS; lpFirstReadQueueHdr->iReadCount = 0; lpFirstReadQueueHdr->lpFirstOpenReadItem = lpRdQ; lpFirstReadQueueHdr->lpFirstNewReadItem = lpRdQ; /* Open Midi input and output ports and start midi input */ rtn = midiOutOpen((LPHMIDIOUT) &hMidiOut, portnum, (DWORD)midi_out_callback, NULL, CALLBACK_FUNCTION); if (rtn) return(200 + rtn); rtn = midiInOpen((LPHMIDIIN) &hMidiIn, portnum, (DWORD)midi_in_callback, (DWORD)(LPVOID)lpRdQHdr, CALLBACK_FUNCTION); if (rtn) return(300 + rtn); dwMidiBaseTime = timeGetTime(); rtn = midiInStart(hMidiIn); if (rtn) return(400 + rtn); rtn = midistarttimer(); if (rtn) return(500+rtn); rtn = midisettime((DWORD)0); if (rtn) return(600+rtn); return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midiclose() { WORD rtn; iNextSchedEvent = -1; dwNextSchedTime = MAX_SCHED_TIME; iLastSchedEvent = -1; dwLastSchedTime = 0; /* if (bTimerStarted) { midisettime(0); dwMidiBaseTime = 0; wQuantaSize = 1000; return(FF_MIDI_SUCCESS); } */ midistoptimer(); if (!hMidiOut) return(FF_MIDI_SUCCESS); rtn = midiOutClose(hMidiOut); if (rtn) return(100 + rtn); else hMidiOut = NULL; rtn = midiInClose(hMidiIn); if (rtn) return(200 + rtn); else hMidiIn = NULL; /* Release storage for MIDI input and output queues */ GlobalPageUnlock(HIWORD(lpWriteQueue)); lpWriteQueue = (WRITE_QUEUE FAR *)GlobalFreePtr(lpWriteQueue); GlobalPageUnlock(HIWORD(lpFirstReadQueueHdr->lpReadQueue)); GlobalFreePtr(lpFirstReadQueueHdr->lpReadQueue); GlobalPageUnlock(HIWORD(lpFirstReadQueueHdr)); lpFirstReadQueueHdr = (LPREAD_QUEUE_HDR)GlobalFreePtr(lpFirstReadQueueHdr); return(FF_MIDI_SUCCESS); } #if 0 WORD FAR PASCAL _export midireadmessages (void (FAR * lisp_read_func)(DWORD)) { unsigned int wNextItem; MIDI_DATA CMMidiData; /* MidiMessage formatted for Common Music */ /* Check to be sure midi port has been opened and storage allocated */ if (!lpReadQueue) return(100); if (iLastOpenReadItem == MAX_READ_QUEUE_ITEMS - 1) wNextItem = 0; else wNextItem = iLastOpenReadItem + 1; while (wNextItem != iFirstOpenReadItem) { /* Format Midi Message for Common Music */ CMMidiData.byMidiByte[3] = 0; CMMidiData.byMidiByte[2] = lpReadQueue->Item[wNextItem].MidiReadData.byMidiByte[0]; CMMidiData.byMidiByte[1] = lpReadQueue->Item[wNextItem].MidiReadData.byMidiByte[1]; CMMidiData.byMidiByte[0] = lpReadQueue->Item[wNextItem].MidiReadData.byMidiByte[2]; if (iFirstOpenReadItem == -1) iFirstOpenReadItem = wNextItem; iLastOpenReadItem = wNextItem; (*lisp_read_func)(CMMidiData.dwMidiMsg); if (wNextItem == MAX_READ_QUEUE_ITEMS - 1) wNextItem = 0; else wNextItem++; } return(FF_MIDI_SUCCESS); } #endif #if 0 WORD FAR PASCAL _export midireadmessages (void (FAR * lisp_read_func)(DWORD)) { DWORD val = 1; (*lisp_read_func)(val); return(FF_MIDI_SUCCESS); } #endif WORD FAR PASCAL _export midiwritemessage(MIDI_DATA CMMidiMsg, DWORD qtime) { WORD rtn; MIDI_DATA WndwMidiData; /* MIDI data formatted for Windows */ int iCurItem, iChkItem; /* Format MIDI data for Windows */ WndwMidiData.byMidiByte[3] = 0; WndwMidiData.byMidiByte[2] = CMMidiMsg.byMidiByte[0]; WndwMidiData.byMidiByte[1] = CMMidiMsg.byMidiByte[1]; WndwMidiData.byMidiByte[0] = CMMidiMsg.byMidiByte[2]; if (qtime <= dwQuantaTime) { rtn = midiOutShortMsg(hMidiOut, WndwMidiData.dwMidiMsg); return(rtn); } if (iFirstOpenWriteItem < 0) /* Return an error if there is no more */ return(101); /* space in the queue! */ bScheduling = TRUE; /* Disable MIDI Output while scheduling */ iCurItem = iFirstOpenWriteItem; iFirstOpenWriteItem = lpWriteQueue->Item[iCurItem].iNextOpenItem; if (iLastOpenWriteItem == iCurItem) /* if this was the only open item */ iLastOpenWriteItem = -1; /* indicate no more open items */ lpWriteQueue->Item[iCurItem].MidiWriteData.dwMidiMsg = WndwMidiData.dwMidiMsg; lpWriteQueue->Item[iCurItem].dwQuantaTime = qtime; lpWriteQueue->Item[iCurItem].iNextOpenItem = -1; if (dwNextSchedTime >= qtime) /* Add to Front of Queue */ { lpWriteQueue->Item[iCurItem].iNextEvent = iNextSchedEvent; lpWriteQueue->Item[iCurItem].iPrevEvent = -1; if (iNextSchedEvent >= 0) lpWriteQueue->Item[iNextSchedEvent].iPrevEvent = iCurItem; iNextSchedEvent = iCurItem; dwNextSchedTime = qtime; if (iLastSchedEvent == -1) { iLastSchedEvent = iCurItem; dwLastSchedTime = qtime; } } else if (dwLastSchedTime <= qtime) /* Add to end of Queue */ { lpWriteQueue->Item[iCurItem].iNextEvent = -1; lpWriteQueue->Item[iCurItem].iPrevEvent = iLastSchedEvent; if (iLastSchedEvent >= 0) lpWriteQueue->Item[iLastSchedEvent].iNextEvent = iCurItem; iLastSchedEvent = iCurItem; dwLastSchedTime = qtime; } else /* Add to middle of Queue */ { iChkItem = iNextSchedEvent; while (lpWriteQueue->Item[iChkItem].dwQuantaTime < qtime) iChkItem = lpWriteQueue->Item[iChkItem].iNextEvent; lpWriteQueue->Item[iCurItem].iNextEvent = iChkItem; lpWriteQueue->Item[iCurItem].iPrevEvent = lpWriteQueue->Item[iChkItem].iPrevEvent; lpWriteQueue->Item[iChkItem].iPrevEvent = iCurItem; lpWriteQueue-> Item[lpWriteQueue->Item[iCurItem].iPrevEvent].iNextEvent = iCurItem; } bScheduling = FALSE; /* Enable MIDI Output */ return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midihush() { WORD rtn; rtn = midiflushtransmit(); if (rtn) return(rtn + 500); rtn = midiallnotesoff((DWORD) 0); if (rtn) return(rtn + 600); rtn = midiflushreceive(); if (rtn) return(rtn + 700); return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midiflushtransmit() { if (!lpWriteQueue) return(100); bScheduling = TRUE; /* Disable MIDI Output while scheduling */ iNextSchedEvent = -1; dwNextSchedTime = MAX_SCHED_TIME; iLastSchedEvent = -1; dwLastSchedTime = 0; iFirstOpenWriteItem = 0; iLastOpenWriteItem = MAX_WRITE_QUEUE_ITEMS - 1; SetMidiOutOpenItems(); bScheduling = FALSE; /* Enable MIDI Output */ return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midiflushreceive() { if (!lpFirstReadQueueHdr) return(100); #if 0 iFirstOpenReadItem = 0; iLastOpenReadItem = MAX_READ_QUEUE_ITEMS - 1; #endif return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export midiallnotesoff(DWORD qtime) { int chnl, note; MIDI_DATA CMMidiData; WORD rtn; /* Send a note off message for all notes on all channels */ for (chnl=0; chnl<16; chnl++) for (note=0; note<128; note++) { CMMidiData.byMidiByte[3] = 0; CMMidiData.byMidiByte[2] = MIDI_NOTE_OFF | chnl; CMMidiData.byMidiByte[1] = note; CMMidiData.byMidiByte[0] = 0x40; rtn = midiwritemessage(CMMidiData, qtime); if (rtn != FF_MIDI_SUCCESS) return(rtn); } return(FF_MIDI_SUCCESS); } WORD FAR PASCAL _export miditotalports (TOTAL_MIDI_PORTS_STRUCT * total_midi_ports) { total_midi_ports->total_midi_in = midiInGetNumDevs(); total_midi_ports->total_midi_out = midiOutGetNumDevs(); return(FF_MIDI_SUCCESS); } DWORD FAR PASCAL _export totalopen() { DWORD opncnt=0; int chksub; chksub = iFirstOpenWriteItem; while (chksub != -1) { opncnt++; chksub = lpWriteQueue->Item[chksub].iNextOpenItem; } return(opncnt); } DWORD FAR PASCAL _export checkread() { return((DWORD)lpFirstReadQueueHdr->lpFirstOpenReadItem); } void PASCAL SetMidiOutOpenItems() { int cnt; for (cnt = 0; cnt < MAX_WRITE_QUEUE_ITEMS - 1; cnt++) { lpWriteQueue->Item[cnt].iNextOpenItem = cnt + 1; } lpWriteQueue->Item[MAX_WRITE_QUEUE_ITEMS - 1].iNextOpenItem = -1; return; } void FAR PASCAL _export midi_out_callback(HMIDIOUT hMidiOut, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { return ; } void FAR PASCAL _export midi_in_callback(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, MIDI_DATA MidiInMsg, DWORD dwParam2) { /* static LPREAD_QUEUE_HDR lpRdQHdr = NULL; */ if (wMsg != MIM_DATA) return; /* Ignore Active Sensing messages */ if (MidiInMsg.byMidiByte[0] == MIDI_ACTIVE_SENSING) return; #if 0 lpRdQHdr = (LPREAD_QUEUE_HDR)dwInstance; /* return if there is no space left in the read (input) queue */ if (lpRdQHdr->iReadCount >= MAX_READ_QUEUE_ITEMS) return; lpRdQHdr->lpFirstOpenReadItem->MidiReadData.dwMidiMsg = MidiInMsg.dwMidiMsg; lpRdQHdr->lpFirstOpenReadItem->dwMidiTime = dwParam2; ++lpRdQHdr->iReadCount; ++lpRdQHdr->lpFirstOpenReadItem; if (lpRdQHdr->lpFirstOpenReadItem == lpRdQHdr->lpReadQueueEnd) lpRdQHdr->lpFirstOpenReadItem = lpRdQHdr->lpReadQueue; #endif if (lpFirstReadQueueHdr->iReadCount >= MAX_READ_QUEUE_ITEMS) return; #if 0 lpFirstReadQueueHdr->lpFirstOpenReadItem-> MidiReadData.dwMidiMsg = MidiInMsg.dwMidiMsg; #endif lpFirstReadQueueHdr->lpFirstOpenReadItem->dwMidiTime = dwParam2; ++lpFirstReadQueueHdr->iReadCount; ++lpFirstReadQueueHdr->lpFirstOpenReadItem; if (lpFirstReadQueueHdr->lpFirstOpenReadItem >= lpFirstReadQueueHdr->lpReadQueueEnd) lpFirstReadQueueHdr->lpFirstOpenReadItem = lpFirstReadQueueHdr->lpReadQueue; return; } void FAR PASCAL _export timer_callback(UINT wID, UINT wMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { dwQuantaTime += 1; if (bScheduling) /* Don't send output while scheduling */ return; while (dwNextSchedTime <= dwQuantaTime) { midiOutShortMsg (hMidiOut, lpWriteQueue->Item[iNextSchedEvent].MidiWriteData.dwMidiMsg); /* Make this write queue item the last open write queue item */ if (iLastOpenWriteItem != -1) lpWriteQueue->Item[iLastOpenWriteItem].iNextOpenItem = iNextSchedEvent; iLastOpenWriteItem = iNextSchedEvent; if (iFirstOpenWriteItem == -1) iFirstOpenWriteItem = iNextSchedEvent; /* Check for next event */ if (lpWriteQueue->Item[iNextSchedEvent].iNextEvent == -1) { /* no more events scheduled. */ iNextSchedEvent = -1; dwNextSchedTime = MAX_SCHED_TIME; iLastSchedEvent = -1; dwLastSchedTime = 0; } else /* Schedule next event */ { iNextSchedEvent = lpWriteQueue->Item[iNextSchedEvent].iNextEvent; dwNextSchedTime = lpWriteQueue->Item[iNextSchedEvent].dwQuantaTime; } } return ; } #if 0 extern "C" { WORD FAR PASCAL _export midistarttimer(); WORD FAR PASCAL _export midistarttimer(); WORD FAR PASCAL _export midistoptimer(); DWORD FAR PASCAL _export midigettime(); WORD FAR PASCAL _export midisettime(DWORD); WORD FAR PASCAL _export midisetquantasize(DWORD); WORD FAR PASCAL _export miditotalports(TOTAL_MIDI_PORTS_STRUCT FAR *); WORD FAR PASCAL _export midiopen(WORD); WORD FAR PASCAL _export midiclose(); WORD FAR PASCAL _export midireadmessages(void (FAR *)(DWORD)); WORD FAR PASCAL _export midiwritemessage(MIDI_DATA, DWORD); WORD FAR PASCAL _export midihush(); WORD FAR PASCAL _export midiflushtransmit(); WORD FAR PASCAL _export midiflushreceive(); WORD FAR PASCAL _export midiallnotesoff(DWORD); void FAR PASCAL _export midi_out_callback(HMIDIOUT, WORD, DWORD, DWORD, DWORD); void FAR PASCAL _export midi_in_callback(HMIDIIN, WORD, DWORD, MIDI_DATA, DWORD); void FAR PASCAL _export timer_callback(UINT, UINT, DWORD, DWORD, DWORD); DWORD FAR PASCAL _export totalopen(); DWORD FAR PASCAL _export checkread(); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.