home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / MIDI Manager Class Library / CMIDIOutputPort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-05  |  7.2 KB  |  200 lines  |  [TEXT/KAHL]

  1. /*
  2.  *--- CMIDIOutputPort.c ----------------------------------------------------------------
  3.  * Copyright © Paul Ferguson, 1990, 1991, 1992.  All rights reserved.
  4.  *
  5.  * Superclass:  CDataPort
  6.  * Subclasses:  None
  7.  *
  8.  * Description:
  9.  *    CMIDIOutputPort.c defines a MIDI Manager port object.
  10.  *
  11.  *    For use with THINK C 5.0, the accompanying THINK Class Library (TCL), and MIDI
  12.  *    Manager 2.0. Refer to the accompanying Microsoft Word document for complete
  13.  *    details about MIDI Manager objects.
  14.  *
  15.  *    If you have comments or questions about this code, you can reach me on
  16.  *    CompuServe at 70441,3055.
  17.  *
  18.  *--------------------------------------------------------------------------------------
  19.  *---- NOTE --- NOTE --- NOTE --- NOTE --- NOTE --- NOTE --- NOTE --- NOTE --- NOTE ----
  20.  *--------------------------------------------------------------------------------------
  21.  *    If you are not familiar with programming the Apple MIDI Manager, refer to the
  22.  *    "MIDI Management Tools" Version 2.0, available from APDA.  You MUST have the
  23.  *    software (MIDI.H and the library) from this package in order to use these objects.
  24.  *    It will not work without this.
  25.  *--------------------------------------------------------------------------------------
  26.  *    REVISION HISTORY:
  27.  *        August ??, 1990            - Original release (1.0).
  28.  *        November 5, 1990        - Added checks for midiMgrVer to most methods.
  29.  *        August 1991                - updated for THINK C 5.0 as version 2.0
  30.  *--------------------------------------------------------------------------------------
  31.  */
  32.  
  33. #include "CMIDIOutputPort.h"                // This code's header file
  34.  
  35. #define    midiWritePacket        108                // EQU from MIDI.a
  36.  
  37. static pascal OSErr (*CMIDIOutputPort::midiWriteProc) (short refnum, MIDIPacketPtr packet);
  38.  
  39. /*
  40.  *--- IMIDIOutputPort ------------------------------------------------------------
  41.  * Initialize the Output Port Object.
  42.  *--------------------------------------------------------------------------------
  43.  */
  44. OSErr CMIDIOutputPort::IMIDIOutputPort(StringPtr        theName,
  45.                                        OSType            thePortID,
  46.                                        Boolean            theVisibleFlag,
  47.                                        CMIDITimePort *    theTimePort,
  48.                                        long                theOffset)
  49. {
  50.     MIDIPortParams        portParams;        // MIDI Mgr Init data structure
  51.     OSErr                theResult;
  52.  
  53.  
  54.     
  55.  
  56.  
  57.     portParams.portID            = thePortID;
  58.     portParams.portType            = midiPortTypeOutput;
  59.     if ( (theVisibleFlag == FALSE) && (itsVersion >= 0x0200) )    // Invisible output port, in 2.x
  60.         portParams.portType        |= midiPortInvisible;
  61.  
  62.     portParams.timeBase            = theTimePort ? theTimePort->GetRefNum() : 0;
  63.     portParams.offsetTime        = theOffset;
  64.     portParams.readHook            = (Ptr) 0;
  65.     portParams.refCon            = SetCurrentA5();
  66.     BlockMove(theName, portParams.name, theName[0]+1);
  67.     theResult = this->IMIDIPort(&portParams, 0);
  68.  
  69.     if (itsVersion >= 0x200)
  70.     {
  71.         midiWriteProc = MIDICallAddress(midiWritePacket);
  72.     }
  73.  
  74.     return theResult;
  75. }
  76.  
  77. /*
  78.  *--- CMIDIOutputPort::WritePacket -------------------------------------------
  79.  * This method writes a completed MIDI Manager packet.
  80.  * If your application is especially time critical, or you want to optimize
  81.  * performance, you may prefer to store this port object's reference number
  82.  * (by calling GetRefCon()), and issuing MIDIWritePacket() calls directly.
  83.  *----------------------------------------------------------------------------
  84.  */
  85. OSErr CMIDIOutputPort::WritePacket(MIDIPacketPtr theMIDIPacket)
  86. {
  87.     if (itsVersion == 0) return ErrNoMIDI;
  88.     if (itsVersion >= 0x200)
  89.         return (*midiWriteProc) (itsRefNum, theMIDIPacket);
  90.     else
  91.         return MIDIWritePacket (itsRefNum, theMIDIPacket);
  92. }
  93.  
  94. /*
  95.  *--- CMIDIOutputPort::Write ----------------------------------------------
  96.  * Send a packet immediately without timestamp.
  97.  *-------------------------------------------------------------------------
  98.  */
  99. OSErr CMIDIOutputPort::Write(char * theData, short theDataLen)
  100. {
  101.     return DoMIDIWrite(theData, theDataLen, midiTimeStampCurrent, 0);
  102. }
  103.  
  104. /*
  105.  *--- CMIDIOutputPort::WriteTS --------------------------------------------
  106.  * Send a packet immediately with the user-supplied timestamp.
  107.  *-------------------------------------------------------------------------
  108.  */
  109. OSErr CMIDIOutputPort::WriteTS(char * theData, short theDataLen, long theTimeStamp)
  110. {
  111.     return DoMIDIWrite(theData, theDataLen, midiTimeStampValid, theTimeStamp);
  112. }
  113.  
  114. /*
  115.  *--- CMIDIOutputPort::DoMIDIWrite --------------------------------------------
  116.  * This local function does all the real work of sending MIDI data.
  117.  *
  118.  * This method is classified as 'private' in CMIDI.h.  If you wish to call
  119.  * this method directly, simply change the header file.
  120.  *
  121.  * If you know your application is going to write a lot of short or fixed
  122.  * length packets, you may wish to override or modify this method to remove the
  123.  * BlockMove trap and multi-length packet logic overhead.
  124.  *
  125.  * It is called by CMIDIOutputPort::Write() and CMIDIOutputPort::WriteTS().
  126.  *-----------------------------------------------------------------------------
  127.  */
  128. OSErr CMIDIOutputPort::DoMIDIWrite(    char *            theData,
  129.                                     short            theDataLen,
  130.                                     unsigned char    theFlags,
  131.                                     long            theTimeStamp)
  132. {
  133.     MIDIPacket                midiPacket;        // MIDI Manager packet to be transmitted
  134.     register MIDIPacketPtr    midiPPtr = &midiPacket;
  135.     
  136.     if (itsVersion == 0) return (ErrNoMIDI);
  137.     
  138.     if (theDataLen < 250)    // Handle short packets directly
  139.     {
  140.         midiPPtr->flags = theFlags | midiMsgType | midiNoCont;
  141.         midiPPtr->len   = theDataLen + 6;
  142.         if (theFlags == midiTimeStampValid)
  143.             midiPPtr->tStamp = theTimeStamp;
  144.         BlockMove(theData, &(midiPPtr->data[0]), theDataLen);
  145.         if (midiWriteProc)
  146.             return (*midiWriteProc) (itsRefNum, &midiPacket);        // ••• Call MIDI Manager
  147.         else
  148.             return MIDIWritePacket(itsRefNum, &midiPacket);
  149.     }
  150.     else                    // Multiple packet send    (more than 249 bytes)
  151.     {
  152.         register char *    source = theData;
  153.         register short    thisPacketLen;
  154.         OSErr            err;
  155.  
  156.         do
  157.         {
  158.             midiPPtr->flags  = theFlags | midiMsgType;        // Re-init each time
  159.             if (theFlags == midiTimeStampValid)
  160.                 midiPPtr->tStamp = theTimeStamp;
  161.             thisPacketLen = (theDataLen < 249) ? theDataLen : 249;
  162.             BlockMove(source, &(midiPPtr->data[0]), thisPacketLen);// Data to write
  163.             /*
  164.              * Set the continuation bits field in the flags byte.
  165.              */
  166.             theDataLen -= thisPacketLen;
  167.             if (source == theData)                            // the first piece of the message
  168.             {
  169.                 if (theDataLen > 0)                            // Multiple writes required?
  170.                     midiPPtr->flags |= midiStartCont;        // Yes
  171.                 else                                        // Everything fits in one packet
  172.                     midiPPtr->flags |= midiNoCont;            // SHOULD NEVER SEE THIS CASE HERE!
  173.             }
  174.             else
  175.             {
  176.                 if (theDataLen > 0)                            // a middle piece
  177.                     midiPPtr->flags |= midiMidCont;
  178.                 else                                        // Last piece of the message
  179.                     midiPPtr->flags |= midiEndCont;
  180.             }
  181.             midiPPtr->len = thisPacketLen + 6;                // Set the packet length
  182.         if (midiWriteProc)
  183.             err = (*midiWriteProc) (itsRefNum, &midiPacket);        // ••• Call MIDI Manager
  184.         else
  185.             err = MIDIWritePacket(itsRefNum, &midiPacket);
  186.         if (err) break;
  187.  
  188. // You may want to add more sophisticated error handling here.  Also, if you are
  189. // sending large packets like system exclusive messages, you may need to add a
  190. // timing delay here so you don't overflow the output buffer or the device.
  191.  
  192.             source += thisPacketLen;                        // Bump pointer
  193.  
  194.         } while (theDataLen > 0);        // Loop for next portion of data
  195.         return err;                        // Indicates last result
  196.     }
  197. }
  198.  
  199. // end of CMIDIOutputPort.c
  200.