📄 midimgr.c
字号:
/* midimgr.c -- this file contains interface code to support use of Apple Midi Manager *//* * This code is based on code supplied with the Apple Midi Manager. * Copyright 1991, Carnegie Mellon University */ /* BUGS: * If exclusive() is called to turn exclusive messages on or off DURING the * receipt of an exclusive message, incoming data will be garbled. The correct * handling would be to record when receipt of an exclusive message is in * progress, then properly remove any partial message when exclusive is turned * off, and ignore any remaining message part when exclusive is turned on. * The present code does neither. */ #include "cext.h"#undef round#ifdef THINK_C#include <pascal.h> /* for ThinkC 7 */#endif#include "stdio.h"#include "userio.h"#include "MIDI.h"#include "midifns.h"#include "midibuff.h"#include "midierr.h"#include "midimgr.h"#include "midicode.h"#include "cmdline.h"/* Needed for KillEverybody */#include <toolutils.h>#include <AppleEvents.h>#include <EPPC.h>#include <Gestalt.h>#include <PPCToolbox.h> #include <Processes.h>#include <Sound.h>#define CMTclientID 'CMT '/* note the following are in alphabetical order for Patcher display */#define timePortID 'Atim'#define inputPortID 'Bin '#define outputPortID 'Cout'#define noClient ' '#define noTimeBaseRefNum 0#define noReadHook 0L#define zeroTime 0L#define timePortBuffSize 0L#define inputPortBuffSize 2048#define outputPortBuffSize 0L#define refCon0 0Lpascal short CMTreader(MIDIPacket *ThePacketPtr, long TheRefCon);/* "patch" switch from command line. This switch is cached in patch_flag and tells whether to look in the resource fork for a patch, or just hook up to midi in and out. If the resource fork is used, the patch will be saved upon exit. */private boolean patch_flag; extern boolean ctrlFilter;extern boolean exclFilter;extern boolean realFilter;private midi_read_lock = false; /* used to stop input during data structure manipulation */private void set_error(int bit);#ifndef NYQUISTvoid PatchPorts(void);void SavePatch(OSType PortID, short PortInfoResID, char *PortInfoResName);#endif/* exported: */public short InputRefNum; /* Input port reference number. */public short OutputRefNum; /* Output port reference number. */public short TimeRefNum; /* Time base port reference number. */Boolean GManualPatch; /* True if not launched by a PatchBay Config. File. *//****************************************************************************** variables shared with other modules*****************************************************************************//* midi input buffer */long buff[BUFF_SIZE/4]; /* data buffer, declared long to get 32-bit alignment */int buffhead = 0; /* buffer head and tail pointers */int bufftail = 0;/* user supplied system exclusive buffer */byte *xbuff = NULL; /* address of the user-supplied buffer */public long xbufmask; /* mask for circular buffer address calculation */long xbufhead = 0; /* buffer head and tail pointers */long xbuftail = 0;boolean xbuf_flush = true; /* says to flush remainder of sysex message */#ifdef SYSEXDEBUGint sysexcount = 0; /* for debugging */int sysexdone = 0;int sysexheadcount = 0;byte sysexfirst = 0;int sysexsysex = 0;#endif/* midi_flush -- empty out buffers *//**/void midi_flush(){ midi_read_lock = true; buffhead = 0; bufftail = 0; xbufhead = 0; xbuftail = 0; xbuf_flush = true; /* in case sysex continuation messages are still coming */ midi_read_lock = false;}/* Nyquist only uses CMT for Midi and Adagio file IO */#ifndef NYQUIST/* Get String representation of MIDI Mgr Version Num.*//* See Mac Tech Note #189 for details. */char *StdMacVerNumToStr(long VerNum, char *VerStr){ char *RetVal; char MajVer, MinVer, VerStage, VerRev, BugFixVer = 0; if (VerNum == 0) { RetVal = NULL; } else { MajVer = (VerNum & 0xFF000000) >> 24; MinVer = (VerNum & 0x00FF0000) >> 16; VerStage = (VerNum & 0x0000FF00) >> 8; VerRev = (VerNum & 0x000000FF) >> 0; BugFixVer = MinVer & 0x0F; switch (VerStage) { case 0x20: VerStage = 'd'; break; case 0x40: VerStage = 'a'; break; case 0x60: VerStage = 'b'; break; case 0x80: VerStage = ' '; break; default: VerStage = '?'; break; } if (BugFixVer == 0) { sprintf(VerStr,"%X.%X%c%X", MajVer, MinVer>>4, VerStage, VerRev); } else { sprintf(VerStr,"%X.%X.%X%c%X", MajVer, MinVer >> 4, MinVer & 0x0F, VerStage, VerRev); } RetVal = VerStr; } return(RetVal);}/* C2PStrCpy -- Convert a C String (from Cstr) into a Pascal string *//* * NOTE: this is not the same code as shipped with midi manager example */char *C2PStrCpy(char *Cstr, Str255 Pstr){ char *c = Cstr; char *p = ((char *) Pstr) + 1; while (*c) *p++ = *c++; *Pstr = c - Cstr; return( (char *) Pstr );}/* This checks to see if THINK C is running under System 7, and ONLY WORKS UNDER SYSTEM 7! Don't use unless you check! */boolean ThinkCRunning(void){ ProcessSerialNumber processSN; OSErr myErr; ProcessInfoRec infoRec; processSN.lowLongOfPSN = kNoProcess; processSN.highLongOfPSN = kNoProcess; do { myErr = GetNextProcess(&processSN); infoRec.processInfoLength = sizeof(ProcessInfoRec); infoRec.processName = 0L; infoRec.processAppSpec = 0L; myErr = GetProcessInformation(&processSN, &infoRec); if (!myErr) { if (infoRec.processSignature == 'KAHL') { return(true); } } } while (myErr == noErr); return(false);}/* This kills off all the other running processes... ONLY WORKS UNDER SYSTEM 7! Don't use unless you check! */void KillEverybody(void){ ProcessSerialNumber myProc, processSN; ProcessSerialNumber finderPSN; ProcessInfoRec infoRec; Str31 processName; FSSpec procSpec; OSErr myErr = noErr; OSErr otherError; AppleEvent theEvent; AEDesc theAddress; Boolean ourFlag, notFinder; Boolean finderFound = false; GetCurrentProcess(&myProc); /* Preset the PSN to no PSN, see IM VI, the Process Manager */ processSN.lowLongOfPSN = kNoProcess; processSN.highLongOfPSN = kNoProcess; finderPSN.lowLongOfPSN = 0UL; /* brk: was nil */ finderPSN.highLongOfPSN = 0UL; /* brk: was nil */ do { myErr = GetNextProcess(&processSN); /* See if it's us first */ notFinder = true; SameProcess(&myProc, &processSN, &ourFlag); infoRec.processInfoLength = sizeof(ProcessInfoRec); infoRec.processName = (StringPtr) &processName; infoRec.processAppSpec = &procSpec; GetProcessInformation(&processSN, &infoRec); if (!ourFlag && !finderFound) { /* see if it's the Finder, we have to kill the finder LAST */ /* or else non-sys 7 apps won't get killed */ /* since the Finder must be there to convert the AppleEvent to Puppet Strings */ /* if the app is not APpleEvent aware */ /* Also, FileShare HAS to be killed before the Finder */ /* or your life will be unpleasant */ if (infoRec.processSignature == 'MACS' && infoRec.processType == 'FNDR') { /* save this number for later */ finderPSN = processSN; notFinder = false; finderFound = true; } else { notFinder = true; } } if (!myErr && !ourFlag && notFinder) { otherError = AECreateDesc(typeProcessSerialNumber, (Ptr)&processSN, sizeof(processSN), &theAddress); if (!otherError) otherError = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); if (!otherError) AEDisposeDesc(&theAddress); /* Again, the Finder will convert the AppleEvent to puppetstrings if */ /* the application is a System 6 or non-AE aware app. This ONLY */ /* happens for the 4 required (oapp,odoc,pdoc, and quit) AppleEvents */ /* and ONLY if you use the PSN for the address */ if (!otherError) AESend(&theEvent, 0L, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, 0L, 0L); AEDisposeDesc(&theEvent); } } while (!myErr); /* Now, if the finder was running, it's safe to kill it */ if (finderPSN.lowLongOfPSN || finderPSN.highLongOfPSN) { otherError = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(processSN), &theAddress); if (!otherError) otherError = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); if (!otherError) AEDisposeDesc(&theAddress); if (!otherError) AESend(&theEvent, 0L, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, 0L, 0L); AEDisposeDesc(&theEvent); }}/* Sign into the MIDI Manager. *//* Set up time, input, and output ports. *//* Start our time base clock. */void setup_midimgr(void){ MIDIPortParams Init; /* MIDI Mgr Init data structure */ Handle TheIconHndl; OSErr TheErr; long MIDIMgrVerNum; /* MIDI Manager Ver (Std Mac Ver #) */ Str255 name = "\pCMU MIDI Toolkit"; char MIDIMgrVerStr[256]; /* MIDI Manager Ver (Std Mac Ver # String) */ long vers; EventRecord theEvent; Gestalt(gestaltSystemVersion, &vers); vers = (vers >> 8) & 0xf; /* shift result over and mask out major version number */ if ((vers >= 7) && (!cl_switch("keep")) && (!ThinkCRunning())) { gprintf(TRANS,"Killing other processes...\n"); KillEverybody(); for (vers=0; vers<100; ++vers) { while (WaitNextEvent(everyEvent, &theEvent, 0L, 0L)) ; } } /* Make sure MIDIMgr is installed and save version num. */ MIDIMgrVerNum = SndDispVersion(midiToolNum); if (MIDIMgrVerNum == 0) { gprintf(ERROR, "The MIDI Manager is not installed! Exiting...\n"); EXIT(1); } else { StdMacVerNumToStr(MIDIMgrVerNum, MIDIMgrVerStr); gprintf(TRANS,"MIDI Manager Version %s\n", MIDIMgrVerStr); } /* Sign in to the MIDI Manager. */ TheIconHndl = GetResource('ICN#', 1); TheErr = MIDISignIn(CMTclientID, 0L, TheIconHndl, name); if (TheErr) { gprintf(ERROR, "Trouble signing into MIDI Manager! Aborting..."); EXIT(1); } /* Assume not a Patchbay configuration. */ GManualPatch = true; /* Add time port. */ Init.portID = timePortID; Init.portType = midiPortTypeTime; Init.timeBase = noTimeBaseRefNum; Init.readHook = noReadHook; Init.initClock.syncType = midiInternalSync; Init.initClock.curTime = zeroTime; Init.initClock.format = midiFormatMSec; Init.refCon = SetCurrentA5(); C2PStrCpy("TimeBase", Init.name); TheErr = MIDIAddPort(CMTclientID, timePortBuffSize, &TimeRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { gprintf(ERROR, "Not enough room in heap zone to add time port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } /* Add an input port. */ Init.portID = inputPortID; Init.portType = midiPortTypeInput; Init.timeBase = TimeRefNum; Init.offsetTime = midiGetCurrent; Init.readHook = NewMIDIReadHookProc(CMTreader); Init.refCon = SetCurrentA5(); C2PStrCpy("InputPort", Init.name); TheErr = MIDIAddPort(CMTclientID, inputPortBuffSize, &InputRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { gprintf(ERROR, "Not enough room in heap zone to add input port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } /* Add an output port. */ Init.portID = outputPortID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -