diff options
author | N.N. <matju@users.sourceforge.net> | 2010-01-05 22:49:36 +0000 |
---|---|---|
committer | N.N. <matju@users.sourceforge.net> | 2010-01-05 22:49:36 +0000 |
commit | 8dbec761cf858ea65900c8a094599857208d8c3a (patch) | |
tree | 3228c023f87f23a354da3b57fdc2afe5b7052032 /desiredata/src/s_midi_mmio.c | |
parent | 529e59635598e2d90a7a49f6b4c676f8366109ba (diff) |
svn path=/trunk/; revision=12907
Diffstat (limited to 'desiredata/src/s_midi_mmio.c')
-rw-r--r-- | desiredata/src/s_midi_mmio.c | 487 |
1 files changed, 0 insertions, 487 deletions
diff --git a/desiredata/src/s_midi_mmio.c b/desiredata/src/s_midi_mmio.c deleted file mode 100644 index fc30be4b..00000000 --- a/desiredata/src/s_midi_mmio.c +++ /dev/null @@ -1,487 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -#include "desire.h" -#include <stdio.h> -#include <windows.h> -#include <mmsystem.h> -using namespace desire; - -/* ------------- MIDI time stamping from audio clock ------------ */ -#ifdef MIDI_TIMESTAMP - -static double msw_hibuftime; -static double initsystime = -1; - -/* call this whenever we reset audio */ -static void msw_resetmidisync() { - initsystime = clock_getsystime(); - msw_hibuftime = sys_getrealtime(); -} - -/* call this whenever we're idled waiting for audio to be ready. The routine maintains a high and low water point - for the difference between real and DAC time. */ -static void msw_midisync() { - if (initsystime == -1) msw_resetmidisync(); - double jittersec = max(msw_dacjitterbufsallowed,msw_adcjitterbufsallowed) * REALDACBLKSIZE / sys_getsr(); - double diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); - if (diff > msw_hibuftime) msw_hibuftime = diff; - if (diff < msw_hibuftime - jittersec) { - post("jitter excess %d %f", dac, diff); - msw_resetmidisync(); - } -} - -static double msw_midigettimefor(LARGE_INTEGER timestamp) { - /* this is broken now... used to work when "timestamp" was derived from QueryPerformanceCounter() instead of - the MS-approved timeGetSystemTime() call in the MIDI callback routine below. */ - return msw_tixtotime(timestamp) - msw_hibuftime; -} -#endif /* MIDI_TIMESTAMP */ - -/* ------------------------- MIDI output -------------------------- */ -static void msw_midiouterror(const char *s, int err) { - char t[256]; - midiOutGetErrorText(err, t, 256); - error(s,t); -} - -static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */ -static int msw_nmidiout; /* number of devices */ - -static void msw_open_midiout(int nmidiout, int *midioutvec) { - UINT result, wRtn; - MIDIOUTCAPS midioutcaps; - if (nmidiout > MAXMIDIOUTDEV) nmidiout = MAXMIDIOUTDEV; - int dev = 0; - for (int i=0; i<nmidiout; i++) { - MIDIOUTCAPS m; - int devno = midioutvec[i]; - result = midiOutOpen(&hMidiOut[dev], devno, 0, 0, CALLBACK_NULL); - wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &m, sizeof(m)); - if (result != MMSYSERR_NOERROR) { - error("midiOutOpen: %s",midioutcaps.szPname); - msw_midiouterror("midiOutOpen: %s", result); - } else { - if (sys_verbose) error("midiOutOpen: Open %s as Port %d", midioutcaps.szPname, dev); - dev++; - } - } - msw_nmidiout = dev; -} - -static void msw_close_midiout() { - for (int i=0; i<msw_nmidiout; i++) { - midiOutReset(hMidiOut[i]); - midiOutClose(hMidiOut[i]); - } - msw_nmidiout = 0; -} - -/* -------------------------- MIDI input ---------------------------- */ - -#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events - -static void msw_midiinerror(const char *s, int err) { - char t[256]; - midiInGetErrorText(err, t, 256); - error(s,t); -} - -/* Structure to represent a single MIDI event. */ -#define EVNT_F_ERROR 0x00000001L -typedef struct evemsw_tag { - DWORD fdwEvent; - DWORD dwDevice; - LARGE_INTEGER timestamp; - DWORD data; -} EVENT; -typedef EVENT FAR *LPEVENT; - -/* Structure to manage the circular input buffer. */ -typedef struct circularBuffer_tag { - HANDLE hSelf; /* handle to this structure */ - HANDLE hBuffer; /* buffer handle */ - WORD wError; /* error flags */ - DWORD dwSize; /* buffer size (in EVENTS) */ - DWORD dwCount; /* byte count (in EVENTS) */ - LPEVENT lpStart; /* ptr to start of buffer */ - LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */ - LPEVENT lpHead; /* ptr to head (next location to fill) */ - LPEVENT lpTail; /* ptr to tail (next location to empty) */ -} CIRCULARBUFFER; -typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER; - -/* Structure to pass instance data from the application to the low-level callback function. */ -typedef struct callbackInstance_tag { - HANDLE hSelf; - DWORD dwDevice; - LPCIRCULARBUFFER lpBuf; -} CALLBACKINSTANCEDATA; -typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA; - -/* Function prototypes */ -LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(); -void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf); -LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize); -void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf); -WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent); - -// Callback instance data pointers -LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV]; - -UINT wNumDevices = 0; // Number of MIDI input devices opened -BOOL bRecordingEnabled = 1; // Enable/disable recording flag -int nNumBufferLines = 0; // Number of lines in display buffer -RECT rectScrollClip; // Clipping rectangle for scrolling -LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure -EVENT incomingEvent; // Incoming MIDI event structure -MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures -HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles - -/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA structure. This structure is used to pass information - to the low-level callback function, each time it receives a message. Because this structure is accessed by the - low-level callback function, it must be allocated using GlobalAlloc() with the GMEM_SHARE and GMEM_MOVEABLE flags - and page-locked with GlobalPageLock(). - Return: A pointer to the allocated CALLBACKINSTANCE data structure. */ -LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData() { - HANDLE hMem; - LPCALLBACKINSTANCEDATA lpBuf; - /* Allocate and lock global memory. */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CALLBACKINSTANCEDATA)); - if(!hMem) return 0; - lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem); - if(!lpBuf) {GlobalFree(hMem); return 0;} - /* Page lock the memory. */ - //GlobalPageLock((HGLOBAL)HIWORD(lpBuf)); - /* Save the handle. */ - lpBuf->hSelf = hMem; - return lpBuf; -} - -/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure. - * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed. */ -void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf) { - HANDLE hMem; - /* Save the handle until we're through here. */ - hMem = lpBuf->hSelf; - /* Free the structure. */ - //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf)); - GlobalUnlock(hMem); - GlobalFree(hMem); -} - -/* AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure - * and a buffer of the specified size. Each memory block is allocated - * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked - * with GlobalLock(), and page-locked with GlobalPageLock(). - * Params: dwSize - The size of the buffer, in events. - * Return: A pointer to a CIRCULARBUFFER structure identifying the allocated display buffer. NULL if the buffer could not be allocated. */ - -LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize) { - HANDLE hMem; - LPCIRCULARBUFFER lpBuf; - LPEVENT lpMem; - /* Allocate and lock a CIRCULARBUFFER structure. */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CIRCULARBUFFER)); - if(!hMem) return 0; - lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem); - if(!lpBuf) {GlobalFree(hMem); return 0;} - /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */ -#ifndef _WIN32 - GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf)); -#endif - /* Save the memory handle. */ - lpBuf->hSelf = hMem; - /* Allocate and lock memory for the actual buffer. */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT)); - if(!hMem) { -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(lpBuf->hSelf); - GlobalFree(lpBuf->hSelf); - return 0; - } - lpMem = (LPEVENT)GlobalLock(hMem); - if(!lpMem) { - GlobalFree(hMem); -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(lpBuf->hSelf); - GlobalFree(lpBuf->hSelf); - return NULL; - } - /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */ -#ifndef _WIN32 - GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem)); -#endif - /* Set up the CIRCULARBUFFER structure. */ - lpBuf->hBuffer = hMem; - lpBuf->wError = 0; - lpBuf->dwSize = dwSize; - lpBuf->dwCount = 0L; - lpBuf->lpStart = lpMem; - lpBuf->lpEnd = lpMem + dwSize; - lpBuf->lpTail = lpMem; - lpBuf->lpHead = lpMem; - return lpBuf; -} - -/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER structure and the memory for the buffer it references. - * Params: lpBuf - Points to the CIRCULARBUFFER to be freed. */ -void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf) { - HANDLE hMem; - /* Free the buffer itself. */ -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart)); -#endif - GlobalUnlock(lpBuf->hBuffer); - GlobalFree(lpBuf->hBuffer); - /* Free the CIRCULARBUFFER structure. */ - hMem = lpBuf->hSelf; -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(hMem); - GlobalFree(hMem); -} - -/* GetEvent - Gets a MIDI event from the circular input buffer. Events - * are removed from the buffer. The corresponding PutEvent() function - * is called by the low-level callback function, so it must reside in - * the callback DLL. PutEvent() is defined in the CALLBACK.C module. - * - * Params: lpBuf - Points to the circular buffer. - * lpEvent - Points to an EVENT structure that is filled with the retrieved event. - * Return: Returns non-zero if successful, zero if there are no events to get. */ -WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) { - /* If no event available, return */ - if (!wNumDevices || lpBuf->dwCount <= 0) return 0; - /* Get the event. */ - *lpEvent = *lpBuf->lpTail; - /* Decrement the byte count, bump the tail pointer. */ - --lpBuf->dwCount; - ++lpBuf->lpTail; - /* Wrap the tail pointer, if necessary. */ - if (lpBuf->lpTail >= lpBuf->lpEnd) lpBuf->lpTail = lpBuf->lpStart; - return 1; -} - -/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full, - * it sets the wError element of the CIRCULARBUFFER structure - * to be non-zero. - * - * Params: lpBuf - Points to the CIRCULARBUFFER. - * lpEvent - Points to the EVENT. */ - -void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) { - /* If the buffer is full, set an error and return. */ - if(lpBuf->dwCount >= lpBuf->dwSize){ - lpBuf->wError = 1; - return; - } - /* Put the event in the buffer, bump the head pointer and the byte count. */ - *lpBuf->lpHead = *lpEvent; - ++lpBuf->lpHead; - ++lpBuf->dwCount; - /* Wrap the head pointer, if necessary. */ - if(lpBuf->lpHead >= lpBuf->lpEnd) lpBuf->lpHead = lpBuf->lpStart; -} - -/* midiInputHandler - Low-level callback function to handle MIDI input. - * Installed by midiInOpen(). The input handler takes incoming - * MIDI events and places them in the circular input buffer. It then - * notifies the application by posting a MM_MIDIINPUT message. - * - * This function is accessed at interrupt time, so it should be as - * fast and efficient as possible. You can't make any - * Windows calls here, except PostMessage(). The only Multimedia - * Windows call you can make are timeGetSystemTime(), midiOutShortMsg(). - * - * Param: hMidiIn - Handle for the associated input device. - * wMsg - One of the MIM_***** messages. - * dwInstance - Points to CALLBACKINSTANCEDATA structure. - * dwParam1 - MIDI data. - * dwParam2 - Timestamp (in milliseconds) */ -void FAR PASCAL midiInputHandler(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { - EVENT event; - switch(wMsg) { - case MIM_OPEN: break; - /* The only error possible is invalid MIDI data, so just pass the invalid data on so we'll see it. */ - case MIM_ERROR: - case MIM_DATA: - event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0; - event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice; - event.data = dwParam1; -#ifdef MIDI_TIMESTAMP - event.timestamp = timeGetSystemTime(); -#endif - /* Put the MIDI event in the circular input buffer. */ - PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf, (LPEVENT)&event); - break; - default: break; - } -} - -void msw_open_midiin(int nmidiin, int *midiinvec) { - UINT wRtn; - unsigned int i; - unsigned int ndev = 0; - /* Allocate a circular buffer for low-level MIDI input. This buffer is filled by the low-level callback function - and emptied by the application. */ - lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE)); - if (!lpInputBuffer) { - printf("Not enough memory available for input buffer.\n"); - return; - } - /* Open all MIDI input devices after allocating and setting up instance data for each device. The instance data is - used to pass buffer management information between the application and the low-level callback function. It also - includes a device ID, a handle to the MIDI Mapper, and a handle to the application's display window, so the callback - can notify the window when input data is available. A single callback function is used to service all opened input devices. */ - for (i=0; (i<(unsigned)nmidiin) && (i<MAXMIDIINDEV); i++) { - if ((lpCallbackInstanceData[ndev] = AllocCallbackInstanceData()) == NULL) { - printf("Not enough memory available.\n"); - FreeCircularBuffer(lpInputBuffer); - return; - } - lpCallbackInstanceData[i]->dwDevice = i; - lpCallbackInstanceData[i]->lpBuf = lpInputBuffer; - wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev], midiinvec[i], (DWORD)midiInputHandler, - (DWORD)lpCallbackInstanceData[ndev], CALLBACK_FUNCTION); - if (wRtn) { - FreeCallbackInstanceData(lpCallbackInstanceData[ndev]); - msw_midiinerror("midiInOpen: %s", wRtn); - } else ndev++; - } - /* Start MIDI input. */ - for (i=0; i<ndev; i++) { - if (hMidiIn[i]) midiInStart(hMidiIn[i]); - } - wNumDevices = ndev; -} - -static void msw_close_midiin() { - unsigned int i; - /* Stop, reset, close MIDI input. Free callback instance data. */ - for (i=0; (i<wNumDevices) && (i<MAXMIDIINDEV); i++) { - if (hMidiIn[i]) { - if (sys_verbose) post("closing MIDI input %d...", i); - midiInStop(hMidiIn[i]); - midiInReset(hMidiIn[i]); - midiInClose(hMidiIn[i]); - FreeCallbackInstanceData(lpCallbackInstanceData[i]); - } - } - /* Free input buffer. */ - if (lpInputBuffer) FreeCircularBuffer(lpInputBuffer); - if (sys_verbose) post("...done"); - wNumDevices = 0; -} - -/* ------------------- public routines -------------------------- */ - -void sys_putmidimess(int portno, int a, int b, int c) { - DWORD foo; - MMRESULT res; - if (portno >= 0 && portno < msw_nmidiout) { - foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16); - res = midiOutShortMsg(hMidiOut[portno], foo); - if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res); - } -} - -void sys_putmidibyte(int portno, int byte) { - MMRESULT res; - if (portno >= 0 && portno < msw_nmidiout) { - res = midiOutShortMsg(hMidiOut[portno], byte); - if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res); - } -} - -void sys_poll_midi() { - static EVENT msw_nextevent; - static int msw_isnextevent; -#ifdef MIDI_TIMESTAMP - static double msw_nexteventtime; -#endif - while (1) { - if (!msw_isnextevent) { - if (!GetEvent(lpInputBuffer, &msw_nextevent)) break; - msw_isnextevent = 1; -#ifdef MIDI_TIMESTAMP - msw_nexteventtime = msw_midigettimefor(&foo.timestamp); -#endif - } -#ifdef MIDI_TIMESTAMP - if (0.001 * clock_gettimesince(initsystime) >= msw_nexteventtime) -#endif - { - int msgtype = ((msw_nextevent.data & 0xf0) >> 4) - 8; - int commandbyte = msw_nextevent.data & 0xff; - int byte1 = (msw_nextevent.data >> 8) & 0xff; - int byte2 = (msw_nextevent.data >> 16) & 0xff; - int portno = msw_nextevent.dwDevice; - switch (msgtype) { - case 0: case 1: case 2: case 3: case 6: - sys_midibytein(portno, commandbyte); - sys_midibytein(portno, byte1); - sys_midibytein(portno, byte2); - break; - case 4: case 5: - sys_midibytein(portno, commandbyte); - sys_midibytein(portno, byte1); - break; - case 7: - sys_midibytein(portno, commandbyte); - break; - } - msw_isnextevent = 0; - } - } -} - -void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) { - if (nmidiout) msw_open_midiout(nmidiout, midioutvec); - if (nmidiin) { - post("Warning: midi input is dangerous in Microsoft Windows; see Pd manual)"); - msw_open_midiin(nmidiin, midiinvec); - } -} - -void sys_close_midi() { - msw_close_midiin(); - msw_close_midiout(); -} - -#if 0 -/* list the audio and MIDI device names */ -void sys_listmididevs() { - /* for MIDI and audio in and out, get the number of devices. Then get the capabilities of each device and print its description. */ - UINT ndevices = midiInGetNumDevs(); - for (unsigned i=0; i<ndevices; i++) { - MIDIINCAPS m; UINT wRtn = midiInGetDevCaps( i, (LPMIDIINCAPS) &m, sizeof(m)); - if (wRtn) msw_midiinerror("midiInGetDevCaps: %s", wRtn); else error("MIDI input device #%d: %s", i+1, m.szPname); - } - ndevices = midiOutGetNumDevs(); - for (unsigned i=0; i<devices; i++) { - MIDIOUTCAPS m; UINT wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &m, sizeof(m)); - if (wRtn) msw_midiouterror("midiOutGetDevCaps: %s", wRtn); else error("MIDI output device #%d: %s", i+1, m.szPname); - } -} -#endif - -void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) { - int nin = min(maxndev,int( midiInGetNumDevs())); - int nout = min(maxndev,int(midiOutGetNumDevs())); - for (int i=0; i<nin; i++) { - MIDIINCAPS m; UINT wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &m, sizeof(m)); - strncpy(indevlist + i*devdescsize, (wRtn ? "???" : m.szPname), devdescsize); indevlist[(i+1)*devdescsize - 1] = 0;} - for (int i=0; i<nout; i++) { - MIDIOUTCAPS m; UINT wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &m, sizeof(m)); - strncpy(outdevlist + i*devdescsize, (wRtn ? "???" : m.szPname), devdescsize); outdevlist[(i+1)*devdescsize - 1] = 0;} - *nindevs = nin; - *noutdevs = nout; -} |