home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / msdos / midi / mpusr2 / mpu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-24  |  15.3 KB  |  714 lines

  1. #include <stdlib.h>
  2. #include <dos.h>
  3. #include "std.h"
  4. #include "mpuregs.h"
  5. #include "mpuregs.h"
  6.  
  7. #define MPU_PRIVATES
  8. #include "mpu.h"
  9.  
  10. // Manifest constants
  11.  
  12. #if 0
  13. #define DEFAULT_BASE_ADDRESS 0x330        // Default MPU base address
  14. #define DEFAULT_INTERRUPT 2                // Default MPU interrrupt
  15. #define DEFAULT_READ_BUFFER_SIZE 1024    // Default read buffer size
  16. #define SEND_RETRIES 0xFFF                // Number of times to try a send
  17. #define EXTRA_READS_ON_OPEN 0x300        // Number of attempts to clear RECEIVE READY when opening
  18. #define MAX_TIMING_BYTE_DELAY 0xFFF
  19. #define RECEIVE_TRIES  3                // Number of attempts on READY_TO_RECEIVE
  20. #define SEND_TRIES 3                    // Number of attempts on READY_TO_SEND
  21. #else
  22. /*
  23.     I had to increase these constants to get things to work
  24.     on my 16mhz 286. I don't know yet if I have some kind of system
  25.     specific problem, nor have I narrowed down exactly which
  26.     constants needed to be increased. - lt
  27. */
  28. #define DEFAULT_BASE_ADDRESS 0x330        // Default MPU base address
  29. #define DEFAULT_INTERRUPT 2                // Default MPU interrrupt
  30. #define DEFAULT_READ_BUFFER_SIZE 1024    // Default read buffer size
  31. #define SEND_RETRIES 0x3FFF                // Number of times to try a send
  32. #define EXTRA_READS_ON_OPEN 0xf00    // Number of attempts to clear RECEIVE READY when opening
  33. #define MAX_TIMING_BYTE_DELAY 0x3FFF
  34. #define RECEIVE_TRIES  12                // Number of attempts on READY_TO_RECEIVE
  35. #define SEND_TRIES 12                    // Number of attempts on READY_TO_SEND
  36. #endif
  37.  
  38. #define TRACE_IN
  39. #define TRACE_OUT
  40.  
  41. #if defined(TRACE_IN) || defined(TRACE_OUT)
  42.  
  43. #define LOGSIZE  4096
  44.  
  45. struct LogEntry {
  46.     unsigned char tag;
  47.     unsigned short byte;
  48. };
  49. struct MpuLog {
  50.     struct LogEntry d[LOGSIZE];
  51.     int tail;
  52. };
  53. struct MpuLog mpulog;
  54.  
  55. #endif
  56.  
  57.  
  58. #ifdef DOC
  59.  
  60. DESCRIPTION
  61.  
  62. Returns a string error message corresponding to the supplied mpu error
  63. number.
  64. #endif
  65.  
  66. char *MpuErrorString(int mpuErrno) {
  67.     return mpuErrorStrings[mpuErrno];
  68. }
  69.  
  70. #ifdef DOC
  71. DESCRIPTION
  72.  
  73. Returns most recent error code, or 0 if successful.
  74. #endif
  75.  
  76. int GetMpuStatus(MpuPortT *mpu) {
  77.     return mpu->mpuErrno;
  78. }
  79.  
  80. #ifdef PDOC
  81.  
  82. DESCRIPTION
  83.  
  84. Is MPU data ready to send? This routine delays some to make sure.
  85.  
  86. RETURNS
  87.  
  88. NO = No data
  89. YES = Data ready.
  90. #endif
  91.  
  92. PRIVATE BOOL isReadyToSend(MpuPortT *mpu) {
  93.     int retries;
  94.     int TheStatus;
  95.     volatile unsigned int j = 0;
  96.     do
  97.     {
  98.         TheStatus = inportb(mpu->statusPort);
  99.         j++;
  100.     }
  101.     while ( ((TheStatus & MPU_NOT_READY_TO_SEND) != 0) && (j < SEND_TRIES));
  102.     return (j != SEND_TRIES);
  103. }
  104. #ifdef PDOC
  105.  
  106. DESCRIPTION
  107.  
  108. Is MPU data ready to receive? This routine delays some to make sure.
  109.  
  110. RETURNS
  111.  
  112. NO = No data
  113. YES = Data ready.
  114. #endif
  115.  
  116. PRIVATE BOOL isReadyToReceive(MpuPortT *mpu) {
  117.     int retries;
  118.     int TheStatus;
  119.     volatile unsigned int j = 0;
  120.     do
  121.     {
  122.         TheStatus = inportb(mpu->statusPort);
  123.         j++;
  124.     }
  125.     while ( ((TheStatus & MPU_NOT_READY_TO_RECEIVE) != 0) && (j < RECEIVE_TRIES));
  126.     return (j != RECEIVE_TRIES);
  127. }
  128.  
  129. #ifdef PDOC
  130.  
  131. DESCRIPTION
  132.  
  133. Check to see if data is waiting.
  134.  
  135. RETURNS
  136.     NO -> No data waiting
  137.     YES -> Data waiting
  138. #endif
  139.  
  140. BOOL DataReady(MpuPortT *mpu) {
  141.     return (mpu->dataHead != mpu->dataTail);
  142. }
  143.  
  144.  
  145. int SendData(MpuPortT *mpu,UCHAR data) {
  146.  
  147.     int TheStatus;
  148.     // Wait for ready
  149. #ifdef TRACE_OUT
  150.     mpulog.d[mpulog.tail].tag = 'O';
  151.     mpulog.d[mpulog.tail].byte = data;
  152.     if( ++mpulog.tail >= LOGSIZE ) mpulog.tail = 0;
  153. #endif
  154.     do {
  155.         TheStatus = inportb(mpu->statusPort);
  156.     } while ( ((TheStatus & MPU_NOT_READY_TO_SEND) != 0));
  157. #ifdef JUNK
  158.     if (!isReadyToSend(mpu)) {
  159.         mpu->mpuErrno = MPU_EHARDWARE;
  160.         return NO;
  161.     }
  162. #endif
  163.  
  164.     outp(mpu->dataPort,data);
  165.     return YES;
  166. }
  167.  
  168.  
  169.  
  170. #ifdef PDOC
  171.  
  172. DESCRIPTION
  173.  
  174. Interrupt handlers for MPU-401. Up to 4 MPU's supported.
  175. Four separate entry points allow an MpuPortT control block
  176. to be associated with the interrupt.
  177.  
  178. #endif
  179.  
  180. PRIVATE MpuPortT *mpuForInterrupt[4];
  181.  
  182.  
  183. PRIVATE void handleInterrupt(int portNum)
  184. {
  185.     MpuPortT *mpu = mpuForInterrupt[portNum];
  186.     int tail;
  187.     int data;
  188.     int track;
  189.  
  190.     enable();
  191.     if (mpu != NULL) {  /* Guard against spurious interrupts */
  192.         while (( inp(mpu->statusPort) & MPU_NOT_READY_TO_RECEIVE) == 0) {
  193.             tail = mpu->dataTail;
  194.             mpu->readBuffer[tail] = data = inp(mpu->dataPort);
  195. #ifdef TRACE_IN
  196.             mpulog.d[mpulog.tail].tag = 'I';
  197.             mpulog.d[mpulog.tail].byte = data;
  198.             if( ++mpulog.tail >= LOGSIZE ) mpulog.tail = 0;
  199. #endif
  200.  
  201.             if (data >= 0xF0) {
  202.                 if (data == 0xFF)
  203.                     mpu->_inSysex = YES;
  204.                 else if (data == 0xF7)
  205.                     mpu->_inSysex = NO;
  206.                 else if (data == 0xF9 ) {
  207.                         SendData(mpu,0xF8);
  208.                 }
  209.                 else if (data < 0xF7 && !mpu->_inSysex) {
  210.                     // callback track request
  211.                     track = data-0xF0;
  212.                     if (mpu->trackRequestHandler != NULL) {
  213.                         (*mpu->trackRequestHandler)(mpu->requestHandlerData,track);
  214.                     } else {
  215.                         SendData(mpu,0xF8);
  216.                     }
  217.                 }
  218.             }
  219.  
  220.             ++tail;
  221.             if (tail >= mpu->bufferSize)
  222.                 tail = 0;
  223.             if (tail == mpu->dataHead) {
  224.                 mpu->overrunError = YES;
  225.             } else {
  226.                 mpu->dataTail = tail;
  227.             }
  228.         }
  229.     }
  230.     disable();
  231.     outportb(0x20, 0x20);
  232. }
  233.  
  234. PRIVATE void interrupt mpuInterrupt0(void) {
  235.     handleInterrupt(0);
  236. }
  237. PRIVATE void interrupt mpuInterrupt1(void) {
  238.     handleInterrupt(1);
  239. }
  240. PRIVATE void interrupt mpuInterrupt2(void) {
  241.     handleInterrupt(2);
  242. }
  243.  
  244. PRIVATE void interrupt mpuInterrupt3(void) {
  245.     handleInterrupt(3);
  246. }
  247.  
  248. typedef void interrupt interruptHandlerT(void);
  249.  
  250. PRIVATE interruptHandlerT far * mpuInterrupt[4] = {
  251.     mpuInterrupt0,
  252.     mpuInterrupt1,
  253.     mpuInterrupt2,
  254.     mpuInterrupt3
  255. };
  256.  
  257. #ifdef PDOC
  258.  
  259. DESCRIPTION
  260.  
  261. Install an interrupt handler. Four separate interrupt handlers are
  262. available. The first unused interrupt handler is assigned to the
  263. supplied mpu port.
  264.  
  265. RETURNS
  266.  
  267. YES-> success
  268. NO -> failure.
  269. Call GetMpuStatus for error number.
  270.  
  271. #endif
  272.  
  273. int installInterruptHandler(MpuPortT *mpu) {
  274.     int i;
  275.     for (i = 0; i < 4 && mpuForInterrupt[i] != NULL; ++i)
  276.         NOTHING;
  277.     if (i == 4) {
  278.         mpu->mpuErrno = MPU_NOINTERRUPTHANDLERS;
  279.         return NO;
  280.     }
  281.     mpuForInterrupt[i] = mpu;
  282.  
  283.     mpu->oldInterrupt = getvect(mpu->mpuInterrupt+8);
  284.     setvect(mpu->mpuInterrupt+8,mpuInterrupt[i]);
  285.  
  286.     /* Enable IRQ */
  287.     outportb(0x21,inportb(0x21) & ((~0x80) >> mpu->mpuInterrupt));
  288.     return YES;
  289. }
  290.  
  291. #ifdef PDOC
  292.  
  293. DESCRIPTION
  294.  
  295. Removes the interrupt handler associated with the mpu port.
  296. #endif
  297.  
  298. PRIVATE void removeInterrupt(MpuPortT *mpu) {
  299.     int i;
  300.  
  301.     // Mask interrupt
  302.     outportb(0x21,inportb(0x21) | ((0x80) >> mpu->mpuInterrupt));
  303.     outportb(0x20,0x20); // Just in case interrupt fired while we were disabling it!!!
  304.  
  305.     // Remove interrupt handler
  306.     setvect(mpu->mpuInterrupt+8,mpu->oldInterrupt);
  307.  
  308.     for (i = 0; i < 4 & mpuForInterrupt[i] != mpu; ++i)
  309.         NOTHING;
  310.     if (i != 4) {
  311.         mpuForInterrupt[i] = NULL;
  312.     }
  313. }
  314. #ifdef DOC
  315.  
  316. DESCRIPTION
  317.     Send one command byte
  318.  
  319. RETURNS
  320.     YES = success.
  321.     NO = failure.
  322.     mpuErrorCode set on failure.
  323. #endif
  324.  
  325.  
  326. int SendCommand(MpuPortT *mpu,UCHAR cmd) {
  327. #ifdef TRACE_CMDS
  328.         printf("Cmd(%02X) ",cmd);
  329. #endif
  330.     FOREVER { // Until byte sent
  331.  
  332.         // Wait for ready
  333.         if (!isReadyToSend(mpu)) {
  334.             mpu->mpuErrno = MPU_EHARDWARE;
  335.             return NO;
  336.         }
  337.  
  338.         disable();
  339.         outp(mpu->commandPort,cmd);
  340.         while ((inp(mpu->statusPort) & MPU_NOT_READY_TO_RECEIVE) != 0)
  341.             NOTHING;
  342.         if (inp(mpu->dataPort) == ACK_MSG) {
  343.             enable();
  344.             return YES;
  345.         }
  346.         geninterrupt(mpu->mpuInterrupt);    // Regenerate interrupt for some reason
  347.         enable();
  348.     }
  349. }
  350.  
  351.  
  352. #ifdef PDOC
  353.  
  354. DESCRIPTION
  355.  
  356. Send one command byte. For use during initialization ONLY.
  357. This routine reads and discards any extraneous data bytes that
  358. may occur during an attempt to write a command byte.
  359.  
  360. RETURNS
  361.     YES = success.
  362.     NO = failure.
  363.     mpuErrorCode set on failure.
  364. #endif
  365.  
  366. int sendInitCommand(MpuPortT *mpu,UCHAR cmd) {
  367.     int j;
  368.  
  369. #ifdef TRACE_CMDS
  370.         printf("Cmd(%02X) ",cmd);
  371. #endif
  372.  
  373.     FOREVER { // Until byte sent
  374.  
  375.         // Wait for ready
  376.         while (!isReadyToSend(mpu)) {
  377.             if (((inp(mpu->statusPort)) & MPU_NOT_READY_TO_RECEIVE) == 0) {
  378.                 j = 0;
  379.                 while ((( inp(mpu->statusPort)) & MPU_NOT_READY_TO_RECEIVE) == 0) {
  380.                     inp(mpu->dataPort);    /* Discard a received message */
  381.                     if (j++ > EXTRA_READS_ON_OPEN) {
  382.                         mpu->mpuErrno = MPU_EHARDWARE;
  383.                         return NO;
  384.                     }
  385.                 }
  386.             } else {
  387.                 mpu->mpuErrno = MPU_EHARDWARE;
  388.                 return NO;
  389.             }
  390.         }
  391.  
  392.         disable();
  393.         outp(mpu->commandPort,cmd);
  394.         while (((inp(mpu->statusPort)) & MPU_NOT_READY_TO_RECEIVE) != 0)
  395.             NOTHING;
  396.         if (inp(mpu->dataPort) == ACK_MSG) {
  397.             enable();
  398.             return YES;
  399.         }
  400.         enable();
  401.     }
  402. }
  403.  
  404. #ifdef DOC
  405.  
  406. DESCRIPTION
  407.  
  408. Read a data byte from an MPU port.
  409.  
  410. RETURNS
  411.     -1 => error condition
  412.     else a data byte
  413. #endif
  414.  
  415. static int _traceReads = NO;
  416.  
  417. int ReadData(MpuPortT *mpu) {
  418.     int val;
  419.  
  420.     if (mpu->overrunError) {
  421.         mpu->mpuErrno = MPU_OVERRUN;
  422.         return -1;
  423.     }
  424.     if (mpu->ungetChar != -1) {
  425.         val = mpu->ungetChar;
  426.         mpu->ungetChar = -1;
  427.         return val;
  428.     }
  429.     while (!DataReady(mpu))
  430.         NOTHING;
  431.     val = mpu->readBuffer[mpu->dataHead];
  432.     ++mpu->dataHead;
  433.     if (mpu->dataHead == mpu->bufferSize) {
  434.         mpu->dataHead = 0;
  435.     }
  436.     if (_traceReads) {
  437.         printf("(%02X)",val);
  438.     }
  439.     return val;
  440. }
  441.  
  442. #ifdef DOC
  443.  
  444. DESCRIPTION
  445.  
  446. Return the last character to the read buffer. Only one character may be
  447. ungotten.
  448. #endif
  449.  
  450. void UngetData(MpuPortT *mpu,UCHAR data) {
  451.     mpu->ungetChar = data;
  452. }
  453. #ifdef DOC
  454.  
  455. DESCRIPTION
  456.  
  457. Create an MPU port. If any of the parameters are zero, default values
  458. are used.
  459.  
  460. RETURNS
  461.  
  462. If NULL, then error. Call GetMpuError() to get error code.
  463. else, a pointer to a newly opened MpuPortT.
  464. #endif
  465.  
  466. MpuPortT *CreateMpuPort(
  467.     int base_address,        // Mpu Base address (default 0x330)
  468.     int interrupt_number,   // Mpu Interrupt (default 2)
  469.     int buffer_size,        // Receive buffer size (default 1024)
  470.     enum MpuOperatingModeT operating_mode, // Operating mode:
  471.                              // STOP_MODE,
  472.                              // RECORD_MODE,
  473.                              // PLAY_MODE,
  474.                              // RECORDPLAY_MODE
  475.     enum MpuClockT clock_source, //     MPU_INTERNAL_CLOCK
  476.                                  // or    MPU_MIDI_CLOCK
  477.                                  // or    MPU_FSK_CLOCK
  478.     int tempo,                    // Beats per minute
  479.     enum MpuTimebaseT timebase, // Ticks per beat (see MpuTimebaseT in MPU.H)
  480.     int metronome_measure_length, // beats per measure,0-> metronome off
  481.     int mode,                // See DESCRIPTION
  482.     int midi_channel_mask,  // bit n controls midi channel n+1
  483.                             // bit = 0 -> pass through without host intervention
  484.                             // bit = 1 -> record/filter this midi channel
  485.     int *result                // retcode is placed here
  486. ) {
  487.     static int timebaseTicks[] = {
  488.       48,72,96,120,144,168,192
  489.     };
  490.  
  491.  
  492.     MpuPortT *mpu;
  493.     int t;
  494.  
  495.     if (result)
  496.         *result = 0;
  497.  
  498.     if (base_address == 0)
  499.         base_address = DEFAULT_BASE_ADDRESS;
  500.     if (interrupt_number == 0)
  501.         interrupt_number = DEFAULT_INTERRUPT;
  502.     if (buffer_size == 0)
  503.         buffer_size = DEFAULT_READ_BUFFER_SIZE;
  504.  
  505.     mpu = malloc(sizeof(MpuPortT));
  506.     if (mpu == NULL) {
  507.         if (result)
  508.             *result = MPU_NOMEM;
  509.         return NULL;
  510.     }
  511.  
  512.     mpu->dataPort = base_address;
  513.     mpu->commandPort = base_address+1;
  514.     mpu->statusPort = base_address+1;
  515.     mpu->mpuInterrupt = interrupt_number;
  516.     mpu->currentTime = 0;
  517.     mpu->ungetChar = -1;
  518.     mpu->_inSysex = 0;
  519.  
  520.     mpu->readBuffer = malloc(buffer_size);
  521.     if (mpu->readBuffer == NULL) {
  522.         free(mpu);
  523.         mpu->mpuErrno = MPU_NOMEM;
  524.         return NULL;
  525.     }
  526.     mpu->bufferSize = buffer_size;
  527.     mpu->dataHead = 0;
  528.     mpu->dataTail = 0;
  529.     mpu->overrunError = NO;
  530.     mpu->currentMode = STOP_MODE;
  531.     mpu->lastCommand = 0;
  532.     mpu->trackRequestHandler = NULL;
  533.     mpu->requestHandlerData = NULL;
  534.     mpu->mpuErrno = 0;
  535.  
  536.     // Synch up on a timing byte to start.
  537.     for (t = 0; t < MAX_TIMING_BYTE_DELAY; ++t) {
  538.         if ((( inp(mpu->statusPort)) & MPU_NOT_READY_TO_RECEIVE) == 0) {
  539.             inp(mpu->dataPort);
  540.         }
  541.     }
  542.  
  543.     if (!sendInitCommand(mpu,MPU_RESET_CMD)) {
  544.         *result = MPU_NOHARDWARE;
  545.         free(mpu->readBuffer);
  546.         free(mpu);
  547.         return NULL;
  548.     }
  549.  
  550.     switch (clock_source) {
  551.         case MPU_INTERNAL_CLOCK:
  552.             sendInitCommand(mpu,INT_CLOCK_CMD);
  553.             break;
  554.         case MPU_MIDI_CLOCK:
  555.             sendInitCommand(mpu,MIDI_CLOCK_CMD);
  556.             break;
  557.         case MPU_FSK_CLOCK:
  558.             sendInitCommand(mpu,FSK_CLOCK_CMD);
  559.             break;
  560.     }
  561.     sendInitCommand(mpu,TIMING_BYTE_ALWAYS_CMD);
  562.     if (mode & MPU_RX_MODE) {
  563.         sendInitCommand(mpu,MODE_MESS_ON_CMD);
  564.     }
  565.     if (mode & MPU_EXCLUSIVE_THRU) {
  566.         sendInitCommand(mpu,EXCLUSIVE_THRU_ON_CMD);
  567.     }
  568.     if (mode & MPU_RX_COMMON) {
  569.         sendInitCommand(mpu,COMMON_TO_HOST_ON_CMD);
  570.     }
  571.     if (MPU_RX_REALTIME) {
  572.         sendInitCommand(mpu,REAL_TIME_TO_HOST_ON_CMD);
  573.     }
  574.     if (metronome_measure_length) {
  575.         sendInitCommand(mpu,MIDI_METRONOME_CMD);
  576.         SendData(mpu,metronome_measure_length);
  577.         sendInitCommand(mpu,METRONOME_W_ACCENTS_CMD);
  578.     } else {
  579.         sendInitCommand(mpu,METRONOME_OFF_CMD);
  580.     }
  581.     if (mode & MPU_RX_BENDER) {
  582.         sendInitCommand(mpu,BENDER_ON_CMD);
  583.     } else {
  584.         sendInitCommand(mpu,BENDER_OFF_CMD);
  585.     }
  586.     if (mode & MPU_VOICES_THRU)
  587.         sendInitCommand(mpu,MIDI_THRU_ON_CMD);
  588.     else
  589.         sendInitCommand(mpu,MIDI_THRU_OFF_CMD);
  590.     if (mode & MPU_RX_EXCLUSIVE)
  591.         sendInitCommand(mpu,EXCLUSIVE_TO_HOST_ON_CMD);
  592.     else
  593.         sendInitCommand(mpu,EXCLUSIVE_TO_HOST_OFF_CMD);
  594.     sendInitCommand(mpu,TIMEBASE_48_CMD+timebase);
  595.     sendInitCommand(mpu,SET_TEMPO_CMD);
  596.     SendData(mpu,tempo);
  597.  
  598.     sendInitCommand(mpu,MIDI_CHANNEL_MASK_LO_CMD);
  599.     SendData(mpu,midi_channel_mask);
  600.     sendInitCommand(mpu,MIDI_CHANNEL_MASK_HI_CMD);
  601.     SendData(mpu,midi_channel_mask >> 8);
  602.  
  603.  
  604.     if (!installInterruptHandler(mpu)) { // Can use normal SendCommand after this!
  605.         free(mpu->readBuffer);
  606.         free(mpu);
  607.         return NULL;
  608.     }
  609.  
  610.     sendInitCommand(mpu,CLEAR_PLAY_COUNTERS_CMD);
  611.     sendInitCommand(mpu,CLEAR_RECORD_COUNTER_CMD);
  612.  
  613.     mpu->currentMode = STOP_MODE;
  614.  
  615.     SetMpuOperatingMode(mpu,operating_mode);
  616.  
  617.     return mpu;
  618. }
  619.  
  620. #ifdef DOC
  621.  
  622. DESCRIPTION
  623.  
  624. Stops the MPU. Sets PLAY, RECORD and MIDI modes to STOP.
  625. Waits for MPU to complete pending PLAY operations.
  626. #endif
  627.  
  628. void StopMpu(MpuPortT *mpu) {
  629.     int data;
  630.  
  631.     switch (mpu->currentMode) {
  632.     case PLAY_MODE:
  633.         SendCommand(mpu,PLAY_STOP | MIDI_STOP);
  634.         break;
  635.     case RECORD_MODE:
  636.         SendCommand(mpu,RECORD_STOP | MIDI_STOP);
  637.         break;
  638.     case RECORDPLAY_MODE:
  639.         SendCommand(mpu,RECORD_STOP | PLAY_STOP | MIDI_STOP);
  640.         break;
  641.     }
  642.     if (mpu->currentMode == RECORD_MODE
  643.         || mpu->currentMode == RECORDPLAY_MODE) {
  644.         // Wait for End of recording
  645.         do {
  646.             data = ReadData(mpu);
  647.         } while (data != ALL_END_MSG && data != -1);
  648.     }
  649.     mpu->currentMode = STOP_MODE;
  650. }
  651.  
  652.  
  653. #ifdef DOC
  654. DESCRIPTION
  655.  
  656. Set Mpu Operating mode:
  657.  
  658. STOP_MODE: Don't send or receive messages.
  659. RECORD_MODE: Receive messages
  660. PLAY_MODE: Allow sending of scheduled messages, receive no messages.
  661. RECORDPLAY_MODE: Allow sending of scheduled messages, receive messages.
  662.  
  663. BUGS
  664.  
  665. Doesn't currently support CONTINUE operation.
  666.  
  667. #endif
  668.  
  669. void SetMpuOperatingMode(MpuPortT *mpu,MpuOperatingModeT operating_mode) {
  670.     switch (operating_mode) {
  671.     case STOP_MODE:
  672.         StopMpu(mpu);
  673.         break;
  674.     case RECORD_MODE:
  675.         SendCommand(mpu,RECORD_START | MIDI_START);
  676.         break;
  677.     case PLAY_MODE:
  678.         SendCommand(mpu,PLAY_START | MIDI_START);
  679.         break;
  680.     case RECORDPLAY_MODE:
  681.         SendCommand(mpu,PLAY_START | RECORD_START | MIDI_START);
  682.         break;
  683.     }
  684. }
  685.  
  686. #ifdef DOC
  687.  
  688. DESCRIPTION
  689.  
  690. Destroy an MPU port. Deallocates memory, and removes the interrupt.
  691.  
  692. RETURNS
  693.  
  694. YES -> success.
  695. NO -> failure
  696. Call GetMpuStatus for error code.
  697. #endif
  698.  
  699. BOOL DestroyMpu(MpuPortT *mpu) {
  700.     if (mpu->currentMode != STOP_MODE) {
  701.         StopMpu(mpu);
  702.     }
  703.     if (mpu == NULL)
  704.         return YES;
  705.     removeInterrupt(mpu);
  706.     free(mpu->readBuffer);
  707.     free(mpu);
  708.     return YES;
  709. }
  710.  
  711.  
  712.  
  713.  
  714.