/* A simple layer using MidiShare. By Stephane Letz, mars 3, 2002. */ /* Should be define for compilation on MacOS9 */ #define __Macintosh__ #define __MacOS9__ #define MidiSharePPC_68k #include #include "CMP.midi.h" /* Comparser include from parent directory. */ /*---------------------------------------------------- MidiShare Driver Internals: -------------*/ typedef struct MD_SPECIFIC_MIDISHARE /* Ptr to this data will be stored in our encap- */ { /* sulating, more generic CMP_MIDI_IO struct. */ short refnum; /* the MidiShare refnum */ MidiFilterPtr filter; /* the MidiShare filter */ } MD_SPECIFIC_MIDISHARE; /*------------------------------------------------------------------------*/ void* specificOpenMIDI(CMP_MIDI_IO* mio) /* Sign on to MidiShare midi. */ { MD_SPECIFIC_MIDISHARE* result = (MD_SPECIFIC_MIDISHARE*)NULL; int i; if (!MidiShare()) { sprintf(mio->rep255, "MidiShare is not installed.\n"); return ((void*)result); } result = (MD_SPECIFIC_MIDISHARE*)malloc(sizeof(MD_SPECIFIC_MIDISHARE)); if (!result) { sprintf(mio->rep255, "Not enough memory for MidiShare MIDI.\n"); return ((void*)result); } /*-------------------------------- Open MidiShare client: --------------*/ #if defined(__Macintosh__) && defined (__MacOS9__) result->refnum = MidiOpen("\pComParser"); #else result->refnum = MidiOpen("ComParser"); #endif result->filter = MidiNewFilter(); if ((result->refnum < 0) || ! result->filter) /* Cannot open MidiShare client. */ { sprintf(mio->rep255, "Can not open MidiShare client.\n"); goto freeExit; } for (i = 0 ; i < 256; i++) { MidiAcceptPort(result->filter, i, 1); /* accept all ports */ MidiAcceptType(result->filter, i, 0); /* reject all types */ } for (i = 0 ; i < 16; i++) { MidiAcceptChan(result->filter, i, 1); /* accept all chan */ } /* Accept only the following types */ MidiAcceptType(result->filter, typeNote, 1); MidiAcceptType(result->filter, typeKeyOn, 1); MidiAcceptType(result->filter, typeKeyOff, 1); MidiAcceptType(result->filter, typeKeyPress, 1); MidiAcceptType(result->filter, typeChanPress, 1); MidiAcceptType(result->filter, typeCtrlChange, 1); MidiAcceptType(result->filter, typeProgChange, 1); MidiAcceptType(result->filter, typePitchWheel, 1); /* Set the filter */ MidiSetFilter(result->refnum, result->filter); /*-------------------------------- Connect to input/ouput: --------------*/ MidiConnect(0,result->refnum,1); MidiConnect(result->refnum,0,1); goto okExit; freeExit: free(result); /* Sure it's there. */ if ( result->filter) MidiFreeFilter( result->filter); result = (MD_SPECIFIC_MIDISHARE*)NULL; okExit: return ((void*)result); } /*-------------------------------------------------------------*/ /* cmpCloseMIDI -- Close up shop and sign out from MidiShare. */ void specificCloseMIDI(CMP_MIDI_IO* mio) { MD_SPECIFIC_MIDISHARE* midiMidiShare = (MD_SPECIFIC_MIDISHARE*)mio->specific; if (midiMidiShare) { MidiClose(midiMidiShare->refnum); MidiFreeFilter(midiMidiShare->filter); sprintf(mio->rep255, "Logged out to MidiShare.\n"); free(midiMidiShare); mio->specific = (void*)NULL; }else{ sprintf(mio->rep255, "Failed to close down MidiShare MIDI ports!\n"); } } /*-----------------------------------------------------------------------------*/ /* Send a MIDI message out the output port. Returns 0 on succes, negative on */ /* failure (then writes error report in struct, if it's there: mio->rep255). */ int sendMIDI(CMP_MIDI_IO* mio, unsigned char* ptr, int length, int interface) { MD_SPECIFIC_MIDISHARE* midiMidiShare; MidiEvPtr ev; int i; if (!mio) /* Just for safety, we don't use the global here. */ return(-1024); midiMidiShare = (MD_SPECIFIC_MIDISHARE*)(mio->specific); if (!midiMidiShare) { sprintf(mio->rep255, "Missing specific data in MidiShare sendMIDI.\n"); return(-1025); } ev = MidiNewEv(typeStream); Port(ev) = interface; if (!ev) { sprintf(mio->rep255, "Can not allocate MidiShare event.\n"); return(-1025); } for (i=0; irep255, "Can not allocate MidiShare cells.\n"); MidiFreeEv(ev); return(-1025); } MidiSendIm(midiMidiShare->refnum,ev); return (0); } /*--------------------------------------------------------------------*/ /* Within a real time environment call this routine regularly to poll */ /* for newly arrived MIDI data. It will call the funtions you provide */ /* for elsewhere. It resets an overflow status after emptying buffer. */ /* Returns number of messages processed (>=0) or negative on failure. */ long receiveMIDI(CMP_MIDI_IO* mio) { MD_SPECIFIC_MIDISHARE* midiMidiShare; char* funNam = "MidiShare_Midi.c : receiveMIDI()"; long processed = 0L; /* Negative return value on errors. */ MidiEvPtr ev; if (!mio) return(-1L); midiMidiShare = (MD_SPECIFIC_MIDISHARE*)(mio->specific); if (!midiMidiShare) { sprintf(mio->rep255, "Missing specific data in %s.\n", funNam); return(-2L); } /*------------------------------------ Midi reception: -------------------*/ while((ev = MidiGetEv(midiMidiShare->refnum))) { switch (EvType(ev)) { case typeSysEx: if (MidiGetField(ev,0) == mio->recSysexID){ /* not implemented yet */ /* recMidiSystemExclusive((unsigned char*)&mdv.sysexmsg, mdv.msglen); */ } break; case typeKeyOn: if (Vel(ev) > 0) recMidiNoteOn(Chan(ev),Pitch(ev),Vel(ev)); else recMidiNoteOff(Chan(ev),Pitch(ev),Vel(ev)); break; case typeKeyOff: recMidiNoteOff(Chan(ev),Pitch(ev),Vel(ev)); break; case typeKeyPress: recMidiPolyPressure(Chan(ev),Pitch(ev), Vel(ev)); break; case typeCtrlChange: recMidiController(Chan(ev),Pitch(ev), Vel(ev)); break; case typeProgChange: recMidiProgramChange(Chan(ev),Pitch(ev)); break; case typeChanPress: recMidiChannelPressure(Chan(ev),Pitch(ev)); break; case typePitchWheel: recMidiPitchBend(Chan(ev),MidiGetField(ev,0)+MidiGetField(ev,1)<<7); break; default: sprintf(mio->rep255,"Wrong event type in %s.\n", funNam); return(-7L); } /*------------------------------------ SOFTWARE THRU: -------------------*/ if (mio->recThru) { MidiSend(midiMidiShare->refnum,ev); }else{ MidiFreeEv(ev); } processed++; } return processed; }