📄 midimgr.c
字号:
Init.portType = midiPortTypeOutput; Init.timeBase = TimeRefNum; Init.offsetTime = midiGetCurrent; Init.readHook = NULL; Init.refCon = refCon0; C2PStrCpy("OutputPort", Init.name); TheErr = MIDIAddPort(CMTclientID, outputPortBuffSize, &OutputRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { printf("Not enough room in heap zone to add output port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } if (GManualPatch) { PatchPorts(); /* connect ports as they were */ } /* to clean this up (later) call finish_midimgr() */ cu_register((cu_fn_type) finish_midimgr, (cu_parm_type) finish_midimgr); /* Start our Clock. */ MIDIStartTime(TimeRefNum); }/* The Read Hook Function. *//* 1st 4 bytes of sysex message get saved here and enqueued later */char save_sysex_head[4];int save_sysex_head_x = 0;void sysex_insert(unsigned char data) { if (save_sysex_head_x < 4) { save_sysex_head[save_sysex_head_x++] = data; } xbuff[xbuftail++] = data; xbuftail &= xbufmask; if (xbuftail == xbufhead) { set_error(SYSEXOVFL); } if (data == MIDI_EOX) { /* we're done with the message */ *((long *) (((byte *) buff) + bufftail)) = *((long *)save_sysex_head); bufftail = (bufftail + 4) & BUFF_MASK; if (bufftail == buffhead) { set_error(BUFFOVFL); } }}/* Read all incomming MIDI data. */pascal short CMTreader(MIDIPacket *ThePacketPtr, long TheRefCon){ /* Set up our A5 world. */ long SysA5 = SetA5(TheRefCon); short RetVal = midiMorePacket, i, j; unsigned char *mm_data = ThePacketPtr->data; register byte data1 = mm_data[1]; if (midi_read_lock) { /* Don't want to read packet now, get it later */ /* DOES THIS REALLY WORK? WHAT WILL CAUSE AN INTERRUPT * TO OCCUR LATER? THIS IS ONLY USED BY midi_flush, IS * BASED ON THE MidiArp CODE FROM APPLE, AND IS UNTESTED - RBD */ RetVal = midiKeepPacket; goto alldone; } /* see if Packet is an error message */ if (((ThePacketPtr->flags & midiTypeMask) == midiMgrType) && *((short *) (&(ThePacketPtr->data))) < midiMaxErr) { set_error(MIDIMGRERR); goto alldone; } /* filter out control changes */ if (ctrlFilter) { register int hibits = *mm_data & 0xF0; if (hibits == 0xD0 || /* Chan Pressure */ hibits == 0xE0 || /* Pitch Bend */ hibits == 0xA0 || /* Poly Pressure */ ((hibits == 0xB0) && /* Control change (don't count switches) */ ((data1 < 64) || (data1 > 121)))) { /* CONTROL MESSAGE HAS BEEN FILTERED */ goto alldone; } } else if (realFilter) { register int hibits = *mm_data & 0xF0; if (hibits >= 0xF8) goto alldone; } /* if not a continuation, copy the data into cmt_data */ /* The logic to detect a non-continued * packet or a first packet is: "flags bit 1 is clear". */ if ((((ThePacketPtr->flags & midiContMask) == midiNoCont)) && (*mm_data != MIDI_SYSEX)) { register byte *cmt_data = ((byte *) buff) + bufftail; *((long *) cmt_data) = *((long *) mm_data); bufftail = (bufftail + 4) & BUFF_MASK; if (bufftail == buffhead) { /* filled buffer faster than client emptied it */ set_error(BUFFOVFL); } } /* see if we have a sysex message to copy to buffer */ if (xbuff && !exclFilter && ((ThePacketPtr->flags & midiContMask) || *mm_data == MIDI_SYSEX)) { int i; register byte *x_data = xbuff + xbuftail; /* iterate over data in message */ /* NOTE: in the previous implementation, I thought Sysex messages were * always starting at the beginning of the buffer, but that didn't work. * This implementation assumes nothing -- it is slower because of additional * testing and parsing inside the loop, but seems to work. */ for (i = ThePacketPtr->len - 6; i > 0; i--) { if (xbuf_flush) { /* we're searching for beginning of message */ if (*mm_data == MIDI_SYSEX) { xbuf_flush = false; sysex_insert(MIDI_SYSEX); } } else { /* we're scanning to the end of the message */ if (*mm_data == MIDI_SYSEX) { /* found it, insert proper EOX */ sysex_insert(MIDI_EOX); sysex_insert(MIDI_SYSEX); } else if (*mm_data == MIDI_EOX) { /* found it */ sysex_insert(MIDI_EOX); xbuf_flush = true; } else sysex_insert(*mm_data); } mm_data++; } }alldone: /* Restore the systems A5 world. */ SetA5(SysA5); return(RetVal);}/* Sign out from the MIDI Manager. */void finish_midimgr(void){ if (GManualPatch && patch_flag) { SavePatch(timePortID, timePortResInfoID, "timePortInfo"); SavePatch(inputPortID, inputPortResInfoID, "inputPortInfo"); SavePatch(outputPortID, outputPortResInfoID, "outputPortInfo"); } MIDISignOut(CMTclientID);}/* Alert user to Resource Manager Error. */voidReportResError(char *Msg){ OSErr TheErr; char Buf[256]; if ( (TheErr = ResError()) != noErr) { gprintf(ERROR, "ResError %d: %s...Aborting.", TheErr, Msg); EXIT(1); } else { /* gprintf(ERROR, "%s OK\n", Msg); */ }}/***************************************************************************** error handling* Effect:* various error conditions are flagged by setting bits in* the global midi_error_flags. it is up to the client to clear this * word when necessary.****************************************************************************/private void set_error(int bit){ midi_error_flags |= (1 << bit);}void midi_show_errors(){ if (midi_error_flags & (1<<BUFFOVFL)) gprintf(ERROR, "Midi Buffer Overflow Error\n"); if (midi_error_flags & (1<<MIDIMGRERR)) gprintf(ERROR, "Midi Manager Error\n"); if (midi_error_flags & (1<<SYSEXOVFL)) gprintf(ERROR, "Midi Sysex Overflow Error\n");}/**************** PATCHING CODE ***************//* MIDIArp Time, Input, and Output Port Info Record Resource ID's.*//* Get previously saved port connections (port info records) *//* from application's 'port' resource. */voidPatchPorts(void){ MIDIPortInfoHdl PortInfoH; /* Handle to port info record. */ MIDIPortInfoPtr PortInfoP; /* Pointer to port info record. */ short i, TheErr; patch_flag = cl_switch("patch"); /* SET UP TIME PORT CONNECTIONS. */ if (patch_flag) PortInfoH = (MIDIPortInfoHdl) GetResource(portResType, timePortResInfoID); if (!patch_flag || PortInfoH == NULL) { MIDIIDListHdl clients, ports; OSErr err; gprintf(TRANS, "Connecting to MIDI IN and OUT\n");#ifdef MIDIMGR_VERBOSE clients = MIDIGetClients(); gprintf(TRANS, "clients = %lx\n", clients); HLock((Handle) clients); for (i = 0; i < (*clients)->numIDs; i++) { OSType id = (*clients)->list[i]; gprintf(TRANS, "%d: %c%c%c%c\n", i, (char) (id>>24), (char) ((id >> 16) & 0xFF), (char) ((id >> 8) & 0xFF), (char) (id & 0xFF)); } ports = MIDIGetPorts('amdr'); HLock((Handle) ports); for (i = 0; i < (*ports)->numIDs; i++) { OSType id = (*ports)->list[i]; gprintf(TRANS, "%d: %c%c%c%c\n", i, (char) (id>>24), (char) ((id >> 16) & 0xFF), (char) ((id >> 8) & 0xFF), (char) (id & 0xFF)); } HUnlock((Handle) ports); HUnlock((Handle) clients);#endif /* the work starts here */ err = MIDIConnectData('CMT ', 'Cout', 'amdr', 'Aout'); /* gprintf(TRANS, "Connected CMT.Cout to amdr.Aout: %d\n", err); */ err = MIDIConnectData('amdr', 'Ain ', 'CMT ', 'Bin '); /* gprintf(TRANS, "Connected amdr.Ain to CMT.Bin: %d\n", err); */ return; } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we supposed to be sync'd to another client? */ if (PortInfoP->timeBase.clientID != noClient) { /* Yes, so make that client our time base. */ TheErr = MIDIConnectTime( PortInfoP->timeBase.clientID, PortInfoP->timeBase.portID, CMTclientID, timePortID );#ifdef IGNORE /* Is the client still signed in? */ if (TheErr != midiVConnectErr) { /* Yes, so set our sync mode to external. */ MIDISetSync(ArpGlobals.TimeRefNum, midiExternalSync); }#endif } /* Were we somebody else's time base? */ for (i=0; i<PortInfoP->numConnects; i++) { MIDIConnectTime(CMTclientID, timePortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/ReleaseResource()"); /* SET UP INPUT PORT CONNECTIONS. */ PortInfoH = (MIDIPortInfoHdl) GetResource(portResType, inputPortResInfoID); if (PortInfoH == NULL) { ReportResError("PatchPorts/GetResource()"); } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we connected to anyone? */ for (i=0; i<PortInfoP->numConnects; i++) { MIDIConnectData(CMTclientID, inputPortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/GetResource()"); /* SET UP OUTPUT PORT CONNECTIONS. */ PortInfoH = (MIDIPortInfoHdl) GetResource(portResType, outputPortResInfoID); if (PortInfoH == NULL) { ReportResError("PatchPorts/GetResource()"); } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we connected to anyone? */ for (i=0; i<PortInfoP->numConnects; i++) { MIDIConnectData(CMTclientID, outputPortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/ReleaseResource()"); }/* Save current port connections (port info records) *//* to application's 'port' resource. */voidSavePatch(OSType PortID, short PortInfoResID, char *PortInfoResName){ Handle PortResH; /* Handle to ptch resource. */ CursHandle WatchCurs; WatchCurs = GetCursor(watchCursor); HLock((Handle) WatchCurs); SetCursor(*WatchCurs); HUnlock((Handle) WatchCurs); /* Remove existing port info resource. */ PortResH = GetResource(portResType, PortInfoResID); /* gprintf(TRANS, "PortResH: %lx, *PortResH: %lx\n", PortResH, *PortResH); */ if (PortResH) { ReportResError("SavePatch/GetResource()"); RmveResource(PortResH); ReportResError("SavePatch/RmveResource()"); DisposHandle(PortResH); UpdateResFile(CurResFile()); ReportResError("SavePatch/UpdateResFile()"); } /* Get new configurateion. */ PortResH = (Handle) MIDIGetPortInfo(CMTclientID, PortID); /* Save new configurateion. */ CtoPstr(PortInfoResName); AddResource(PortResH, portResType, PortInfoResID, (ConstStr255Param) PortInfoResName); PtoCstr((unsigned char *) PortInfoResName); ReportResError("SavePatch/AddResource()"); WriteResource(PortResH); ReportResError("SavePatch/WriteResource()"); UpdateResFile(CurResFile()); ReportResError("SavePatch/UpdateResFile()"); ReleaseResource(PortResH); ReportResError("SavePatch/ReleaseResource()"); InitCursor();}#endif /* NYQUIST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -