summaryrefslogtreecommitdiffstats
path: root/arm-hybrid-22k/lib_src/eas_midi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm-hybrid-22k/lib_src/eas_midi.c')
-rw-r--r--arm-hybrid-22k/lib_src/eas_midi.c1114
1 files changed, 557 insertions, 557 deletions
diff --git a/arm-hybrid-22k/lib_src/eas_midi.c b/arm-hybrid-22k/lib_src/eas_midi.c
index 08aed72..2c0c793 100644
--- a/arm-hybrid-22k/lib_src/eas_midi.c
+++ b/arm-hybrid-22k/lib_src/eas_midi.c
@@ -1,13 +1,13 @@
-/*----------------------------------------------------------------------------
- *
- * File:
- * eas_midi.c
- *
- * Contents and purpose:
- * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages
- * that are streamed out of the file. It can also parse live MIDI streams.
- *
- * Copyright Sonic Network Inc. 2005
+/*----------------------------------------------------------------------------
+ *
+ * File:
+ * eas_midi.c
+ *
+ * Contents and purpose:
+ * This file implements the MIDI stream parser. It is called by eas_smf.c to parse MIDI messages
+ * that are streamed out of the file. It can also parse live MIDI streams.
+ *
+ * Copyright Sonic Network Inc. 2005
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,550 +20,550 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
- *----------------------------------------------------------------------------
- * Revision Control:
- * $Revision: 794 $
- * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_report.h"
-#include "eas_miditypes.h"
-#include "eas_midi.h"
-#include "eas_vm_protos.h"
-#include "eas_parser.h"
-
-#ifdef JET_INTERFACE
-#include "jet_data.h"
-#endif
-
-
-/* state enumerations for ProcessSysExMessage */
-typedef enum
-{
- eSysEx,
- eSysExUnivNonRealTime,
- eSysExUnivNrtTargetID,
- eSysExGMControl,
- eSysExUnivRealTime,
- eSysExUnivRtTargetID,
- eSysExDeviceControl,
- eSysExMasterVolume,
- eSysExMasterVolLSB,
- eSysExSPMIDI,
- eSysExSPMIDIchan,
- eSysExSPMIDIMIP,
- eSysExMfgID1,
- eSysExMfgID2,
- eSysExMfgID3,
- eSysExEnhancer,
- eSysExEnhancerSubID,
- eSysExEnhancerFeedback1,
- eSysExEnhancerFeedback2,
- eSysExEnhancerDrive,
- eSysExEnhancerWet,
- eSysExEOX,
- eSysExIgnore
-} E_SYSEX_STATES;
-
-/* local prototypes */
-static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode);
-static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode);
-
-/*----------------------------------------------------------------------------
- * EAS_InitMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Initializes the MIDI stream state for parsing.
- *
- * Inputs:
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream)
-{
- pMIDIStream->byte3 = EAS_FALSE;
- pMIDIStream->pending = EAS_FALSE;
- pMIDIStream->runningStatus = 0;
- pMIDIStream->status = 0;
-}
-
-/*----------------------------------------------------------------------------
- * EAS_ParseMIDIStream()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled)
- * so the interface works equally well for both file and stream I/O.
- *
- * Inputs:
- * c - character from MIDI stream
- *
- * Outputs:
- * returns EAS_RESULT (EAS_SUCCESS is OK)
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
-{
-
- /* check for new status byte */
- if (c & 0x80)
- {
- /* save new running status */
- if (c < 0xf8)
- {
- pMIDIStream->runningStatus = c;
- pMIDIStream->byte3 = EAS_FALSE;
-
- /* deal with SysEx */
- if ((c == 0xf7) || (c == 0xf0))
- {
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
- }
-
- /* inform the file parser that we're in the middle of a message */
- if ((c < 0xf4) || (c > 0xf6))
- pMIDIStream->pending = EAS_TRUE;
- }
-
- /* real-time message - ignore it */
- return EAS_SUCCESS;
- }
-
- /* 3rd byte of a 3-byte message? */
- if (pMIDIStream->byte3)
- {
- pMIDIStream->d2 = c;
- pMIDIStream->byte3 = EAS_FALSE;
- pMIDIStream->pending = EAS_FALSE;
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
- }
-
- /* check for status received */
- if (pMIDIStream->runningStatus)
- {
-
- /* save new status and data byte */
- pMIDIStream->status = pMIDIStream->runningStatus;
-
- /* check for 3-byte messages */
- if (pMIDIStream->status < 0xc0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_TRUE;
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
-
- /* check for 2-byte messages */
- if (pMIDIStream->status < 0xe0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_FALSE;
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
- }
-
- /* check for more 3-bytes message */
- if (pMIDIStream->status < 0xf0)
- {
- pMIDIStream->d1 = c;
- pMIDIStream->pending = EAS_TRUE;
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
-
- /* SysEx message? */
- if (pMIDIStream->status == 0xF0)
- {
- if (parserMode == eParserModeMetaData)
- return EAS_SUCCESS;
- return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
- }
-
- /* remaining messages all clear running status */
- pMIDIStream->runningStatus = 0;
-
- /* F2 is 3-byte message */
- if (pMIDIStream->status == 0xf2)
- {
- pMIDIStream->byte3 = EAS_TRUE;
- return EAS_SUCCESS;
- }
- }
-
- /* no status byte received, provide a warning, but we should be able to recover */
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ }
- pMIDIStream->pending = EAS_FALSE;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * ProcessMIDIMessage()
- *----------------------------------------------------------------------------
- * Purpose:
- * This function processes a typical MIDI message. All of the data has been received, just need
- * to take appropriate action.
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode)
-{
- EAS_U8 channel;
-
- channel = pMIDIStream->status & 0x0f;
- switch (pMIDIStream->status & 0xf0)
- {
- case 0x80:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- break;
-
- case 0x90:
- if (pMIDIStream->d2)
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE;
- if (parserMode == eParserModePlay)
- VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- }
- else
- {
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- }
- break;
-
- case 0xa0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- break;
-
- case 0xb0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
-#ifdef JET_INTERFACE
- if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB)
- {
- JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK),
- channel, pMIDIStream->d1, pMIDIStream->d2);
- }
-#endif
- break;
-
- case 0xc0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1); */ }
- if (parserMode < eParserModeMute)
- VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1);
- break;
-
- case 0xd0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1); */ }
- if (parserMode < eParserModeMute)
- VMChannelPressure(pSynth, channel, pMIDIStream->d1);
- break;
-
- case 0xe0:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- if (parserMode < eParserModeMute)
- VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n",
- pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * ProcessSysExMessage()
- *----------------------------------------------------------------------------
- * Purpose:
- * Process a SysEx character byte from the MIDI stream. Since we cannot
- * simply wait for the next character to arrive, we are forced to save
- * state after each character. It would be easier to parse at the file
- * level, but then we lose the nice feature of being able to support
- * these messages in a real-time MIDI stream.
- *
- * Inputs:
- * pEASData - pointer to synthesizer instance data
- * c - character to be processed
- * locating - if true, the sequencer is relocating to a new position
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * These are the SysEx messages we can receive:
- *
- * SysEx messages
- * { f0 7e 7f 09 01 f7 } GM 1 On
- * { f0 7e 7f 09 02 f7 } GM 1/2 Off
- * { f0 7e 7f 09 03 f7 } GM 2 On
- * { f0 7f 7f 04 01 lsb msb } Master Volume
- * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI
- * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
-{
-
- /* check for start byte */
- if (c == 0xf0)
- {
- pMIDIStream->sysExState = eSysEx;
- }
- /* check for end byte */
- else if (c == 0xf7)
- {
- /* if this was a MIP message, update the MIP table */
- if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData))
- VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
- pMIDIStream->sysExState = eSysExIgnore;
- }
-
- /* process SysEx message */
- else
- {
- switch (pMIDIStream->sysExState)
- {
- case eSysEx:
-
- /* first byte, determine message class */
- switch (c)
- {
- case 0x7e:
- pMIDIStream->sysExState = eSysExUnivNonRealTime;
- break;
- case 0x7f:
- pMIDIStream->sysExState = eSysExUnivRealTime;
- break;
- case 0x00:
- pMIDIStream->sysExState = eSysExMfgID1;
- break;
- default:
- pMIDIStream->sysExState = eSysExIgnore;
- break;
- }
- break;
-
- /* process GM message */
- case eSysExUnivNonRealTime:
- if (c == 0x7f)
- pMIDIStream->sysExState = eSysExUnivNrtTargetID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExUnivNrtTargetID:
- if (c == 0x09)
- pMIDIStream->sysExState = eSysExGMControl;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExGMControl:
- if ((c == 1) || (c == 3))
- {
- /* GM 1 or GM2 On, reset synth */
- if (parserMode != eParserModeMetaData)
- {
- pMIDIStream->flags |= MIDI_FLAG_GM_ON;
- VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE);
- VMInitMIPTable(pSynth);
- }
- pMIDIStream->sysExState = eSysExEOX;
- }
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- /* Process Master Volume and SP-MIDI */
- case eSysExUnivRealTime:
- if (c == 0x7f)
- pMIDIStream->sysExState = eSysExUnivRtTargetID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExUnivRtTargetID:
- if (c == 0x04)
- pMIDIStream->sysExState = eSysExDeviceControl;
- else if (c == 0x0b)
- pMIDIStream->sysExState = eSysExSPMIDI;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- /* process master volume */
- case eSysExDeviceControl:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExMasterVolume;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMasterVolume:
- /* save LSB */
- pMIDIStream->d1 = c;
- pMIDIStream->sysExState = eSysExMasterVolLSB;
- break;
-
- case eSysExMasterVolLSB:
- if (parserMode != eParserModeMetaData)
- {
- EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1);
- gain = (gain * gain) >> 15;
- VMSetVolume(pSynth, (EAS_U16) gain);
- }
- pMIDIStream->sysExState = eSysExEOX;
- break;
-
- /* process SP-MIDI MIP message */
- case eSysExSPMIDI:
- if (c == 0x01)
- {
- /* assume all channels are muted */
- if (parserMode != eParserModeMetaData)
- VMInitMIPTable(pSynth);
- pMIDIStream->d1 = 0;
- pMIDIStream->sysExState = eSysExSPMIDIchan;
- }
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExSPMIDIchan:
- if (c < NUM_SYNTH_CHANNELS)
- {
- pMIDIStream->d2 = c;
- pMIDIStream->sysExState = eSysExSPMIDIMIP;
- }
- else
- {
- /* bad MIP message - unmute channels */
- if (parserMode != eParserModeMetaData)
- VMInitMIPTable(pSynth);
- pMIDIStream->sysExState = eSysExIgnore;
- }
- break;
-
- case eSysExSPMIDIMIP:
- /* process MIP entry here */
- if (parserMode != eParserModeMetaData)
- VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c);
- pMIDIStream->sysExState = eSysExSPMIDIchan;
-
- /* if 16 channels received, update MIP table */
- if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS)
- {
- if (parserMode != eParserModeMetaData)
- VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
- pMIDIStream->sysExState = eSysExEOX;
- }
- break;
-
- /* process Enhancer */
- case eSysExMfgID1:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExMfgID1;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMfgID2:
- if (c == 0x3a)
- pMIDIStream->sysExState = eSysExMfgID1;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExMfgID3:
- if (c == 0x04)
- pMIDIStream->sysExState = eSysExEnhancer;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExEnhancer:
- if (c == 0x01)
- pMIDIStream->sysExState = eSysExEnhancerSubID;
- else
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExEnhancerSubID:
- pMIDIStream->sysExState = eSysExEnhancerFeedback1;
- break;
-
- case eSysExEnhancerFeedback1:
- pMIDIStream->sysExState = eSysExEnhancerFeedback2;
- break;
-
- case eSysExEnhancerFeedback2:
- pMIDIStream->sysExState = eSysExEnhancerDrive;
- break;
-
- case eSysExEnhancerDrive:
- pMIDIStream->sysExState = eSysExEnhancerWet;
- break;
-
- case eSysExEnhancerWet:
- pMIDIStream->sysExState = eSysExEOX;
- break;
-
- case eSysExEOX:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ }
- pMIDIStream->sysExState = eSysExIgnore;
- break;
-
- case eSysExIgnore:
- break;
-
- default:
- pMIDIStream->sysExState = eSysExIgnore;
- break;
- }
- }
-
- if (pMIDIStream->sysExState == eSysExIgnore)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ }
- return EAS_SUCCESS;
-} /* end ProcessSysExMessage */
-
+ *
+ *----------------------------------------------------------------------------
+ * Revision Control:
+ * $Revision: 794 $
+ * $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $
+ *----------------------------------------------------------------------------
+*/
+
+#include "eas_data.h"
+#include "eas_report.h"
+#include "eas_miditypes.h"
+#include "eas_midi.h"
+#include "eas_vm_protos.h"
+#include "eas_parser.h"
+
+#ifdef JET_INTERFACE
+#include "jet_data.h"
+#endif
+
+
+/* state enumerations for ProcessSysExMessage */
+typedef enum
+{
+ eSysEx,
+ eSysExUnivNonRealTime,
+ eSysExUnivNrtTargetID,
+ eSysExGMControl,
+ eSysExUnivRealTime,
+ eSysExUnivRtTargetID,
+ eSysExDeviceControl,
+ eSysExMasterVolume,
+ eSysExMasterVolLSB,
+ eSysExSPMIDI,
+ eSysExSPMIDIchan,
+ eSysExSPMIDIMIP,
+ eSysExMfgID1,
+ eSysExMfgID2,
+ eSysExMfgID3,
+ eSysExEnhancer,
+ eSysExEnhancerSubID,
+ eSysExEnhancerFeedback1,
+ eSysExEnhancerFeedback2,
+ eSysExEnhancerDrive,
+ eSysExEnhancerWet,
+ eSysExEOX,
+ eSysExIgnore
+} E_SYSEX_STATES;
+
+/* local prototypes */
+static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode);
+static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode);
+
+/*----------------------------------------------------------------------------
+ * EAS_InitMIDIStream()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Initializes the MIDI stream state for parsing.
+ *
+ * Inputs:
+ *
+ * Outputs:
+ * returns EAS_RESULT (EAS_SUCCESS is OK)
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+void EAS_InitMIDIStream (S_MIDI_STREAM *pMIDIStream)
+{
+ pMIDIStream->byte3 = EAS_FALSE;
+ pMIDIStream->pending = EAS_FALSE;
+ pMIDIStream->runningStatus = 0;
+ pMIDIStream->status = 0;
+}
+
+/*----------------------------------------------------------------------------
+ * EAS_ParseMIDIStream()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Parses a MIDI input stream character by character. Characters are pushed (rather than pulled)
+ * so the interface works equally well for both file and stream I/O.
+ *
+ * Inputs:
+ * c - character from MIDI stream
+ *
+ * Outputs:
+ * returns EAS_RESULT (EAS_SUCCESS is OK)
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+EAS_RESULT EAS_ParseMIDIStream (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
+{
+
+ /* check for new status byte */
+ if (c & 0x80)
+ {
+ /* save new running status */
+ if (c < 0xf8)
+ {
+ pMIDIStream->runningStatus = c;
+ pMIDIStream->byte3 = EAS_FALSE;
+
+ /* deal with SysEx */
+ if ((c == 0xf7) || (c == 0xf0))
+ {
+ if (parserMode == eParserModeMetaData)
+ return EAS_SUCCESS;
+ return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
+ }
+
+ /* inform the file parser that we're in the middle of a message */
+ if ((c < 0xf4) || (c > 0xf6))
+ pMIDIStream->pending = EAS_TRUE;
+ }
+
+ /* real-time message - ignore it */
+ return EAS_SUCCESS;
+ }
+
+ /* 3rd byte of a 3-byte message? */
+ if (pMIDIStream->byte3)
+ {
+ pMIDIStream->d2 = c;
+ pMIDIStream->byte3 = EAS_FALSE;
+ pMIDIStream->pending = EAS_FALSE;
+ if (parserMode == eParserModeMetaData)
+ return EAS_SUCCESS;
+ return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
+ }
+
+ /* check for status received */
+ if (pMIDIStream->runningStatus)
+ {
+
+ /* save new status and data byte */
+ pMIDIStream->status = pMIDIStream->runningStatus;
+
+ /* check for 3-byte messages */
+ if (pMIDIStream->status < 0xc0)
+ {
+ pMIDIStream->d1 = c;
+ pMIDIStream->pending = EAS_TRUE;
+ pMIDIStream->byte3 = EAS_TRUE;
+ return EAS_SUCCESS;
+ }
+
+ /* check for 2-byte messages */
+ if (pMIDIStream->status < 0xe0)
+ {
+ pMIDIStream->d1 = c;
+ pMIDIStream->pending = EAS_FALSE;
+ if (parserMode == eParserModeMetaData)
+ return EAS_SUCCESS;
+ return ProcessMIDIMessage(pEASData, pSynth, pMIDIStream, parserMode);
+ }
+
+ /* check for more 3-bytes message */
+ if (pMIDIStream->status < 0xf0)
+ {
+ pMIDIStream->d1 = c;
+ pMIDIStream->pending = EAS_TRUE;
+ pMIDIStream->byte3 = EAS_TRUE;
+ return EAS_SUCCESS;
+ }
+
+ /* SysEx message? */
+ if (pMIDIStream->status == 0xF0)
+ {
+ if (parserMode == eParserModeMetaData)
+ return EAS_SUCCESS;
+ return ProcessSysExMessage(pEASData, pSynth, pMIDIStream, c, parserMode);
+ }
+
+ /* remaining messages all clear running status */
+ pMIDIStream->runningStatus = 0;
+
+ /* F2 is 3-byte message */
+ if (pMIDIStream->status == 0xf2)
+ {
+ pMIDIStream->byte3 = EAS_TRUE;
+ return EAS_SUCCESS;
+ }
+ }
+
+ /* no status byte received, provide a warning, but we should be able to recover */
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Received MIDI data without a valid status byte: %d\n",c); */ }
+ pMIDIStream->pending = EAS_FALSE;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * ProcessMIDIMessage()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * This function processes a typical MIDI message. All of the data has been received, just need
+ * to take appropriate action.
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT ProcessMIDIMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_INT parserMode)
+{
+ EAS_U8 channel;
+
+ channel = pMIDIStream->status & 0x0f;
+ switch (pMIDIStream->status & 0xf0)
+ {
+ case 0x80:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ if (parserMode < eParserModeMute)
+ VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
+ break;
+
+ case 0x90:
+ if (pMIDIStream->d2)
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOn: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ pMIDIStream->flags |= MIDI_FLAG_FIRST_NOTE;
+ if (parserMode == eParserModePlay)
+ VMStartNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
+ }
+ else
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"NoteOff: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ if (parserMode < eParserModeMute)
+ VMStopNote(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
+ }
+ break;
+
+ case 0xa0:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PolyPres: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ break;
+
+ case 0xb0:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Control: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ if (parserMode < eParserModeMute)
+ VMControlChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
+#ifdef JET_INTERFACE
+ if (pMIDIStream->jetData & MIDI_FLAGS_JET_CB)
+ {
+ JET_Event(pEASData, pMIDIStream->jetData & (JET_EVENT_SEG_MASK | JET_EVENT_TRACK_MASK),
+ channel, pMIDIStream->d1, pMIDIStream->d2);
+ }
+#endif
+ break;
+
+ case 0xc0:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Program: %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1); */ }
+ if (parserMode < eParserModeMute)
+ VMProgramChange(pEASData->pVoiceMgr, pSynth, channel, pMIDIStream->d1);
+ break;
+
+ case 0xd0:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"ChanPres: %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1); */ }
+ if (parserMode < eParserModeMute)
+ VMChannelPressure(pSynth, channel, pMIDIStream->d1);
+ break;
+
+ case 0xe0:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"PBend: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ if (parserMode < eParserModeMute)
+ VMPitchBend(pSynth, channel, pMIDIStream->d1, pMIDIStream->d2);
+ break;
+
+ default:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL,"Unknown: %02x %02x %02x\n",
+ pMIDIStream->status, pMIDIStream->d1, pMIDIStream->d2); */ }
+ }
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * ProcessSysExMessage()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Process a SysEx character byte from the MIDI stream. Since we cannot
+ * simply wait for the next character to arrive, we are forced to save
+ * state after each character. It would be easier to parse at the file
+ * level, but then we lose the nice feature of being able to support
+ * these messages in a real-time MIDI stream.
+ *
+ * Inputs:
+ * pEASData - pointer to synthesizer instance data
+ * c - character to be processed
+ * locating - if true, the sequencer is relocating to a new position
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ * Notes:
+ * These are the SysEx messages we can receive:
+ *
+ * SysEx messages
+ * { f0 7e 7f 09 01 f7 } GM 1 On
+ * { f0 7e 7f 09 02 f7 } GM 1/2 Off
+ * { f0 7e 7f 09 03 f7 } GM 2 On
+ * { f0 7f 7f 04 01 lsb msb } Master Volume
+ * { f0 7f 7f 0b 01 ch mip [ch mip ...] f7 } SP-MIDI
+ * { f0 00 01 3a 04 01 fdbk1 fdbk2 drive wet dry f7 } Enhancer
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT ProcessSysExMessage (S_EAS_DATA *pEASData, S_SYNTH *pSynth, S_MIDI_STREAM *pMIDIStream, EAS_U8 c, EAS_INT parserMode)
+{
+
+ /* check for start byte */
+ if (c == 0xf0)
+ {
+ pMIDIStream->sysExState = eSysEx;
+ }
+ /* check for end byte */
+ else if (c == 0xf7)
+ {
+ /* if this was a MIP message, update the MIP table */
+ if ((pMIDIStream->sysExState == eSysExSPMIDIchan) && (parserMode != eParserModeMetaData))
+ VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
+ pMIDIStream->sysExState = eSysExIgnore;
+ }
+
+ /* process SysEx message */
+ else
+ {
+ switch (pMIDIStream->sysExState)
+ {
+ case eSysEx:
+
+ /* first byte, determine message class */
+ switch (c)
+ {
+ case 0x7e:
+ pMIDIStream->sysExState = eSysExUnivNonRealTime;
+ break;
+ case 0x7f:
+ pMIDIStream->sysExState = eSysExUnivRealTime;
+ break;
+ case 0x00:
+ pMIDIStream->sysExState = eSysExMfgID1;
+ break;
+ default:
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+ }
+ break;
+
+ /* process GM message */
+ case eSysExUnivNonRealTime:
+ if (c == 0x7f)
+ pMIDIStream->sysExState = eSysExUnivNrtTargetID;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExUnivNrtTargetID:
+ if (c == 0x09)
+ pMIDIStream->sysExState = eSysExGMControl;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExGMControl:
+ if ((c == 1) || (c == 3))
+ {
+ /* GM 1 or GM2 On, reset synth */
+ if (parserMode != eParserModeMetaData)
+ {
+ pMIDIStream->flags |= MIDI_FLAG_GM_ON;
+ VMReset(pEASData->pVoiceMgr, pSynth, EAS_FALSE);
+ VMInitMIPTable(pSynth);
+ }
+ pMIDIStream->sysExState = eSysExEOX;
+ }
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ /* Process Master Volume and SP-MIDI */
+ case eSysExUnivRealTime:
+ if (c == 0x7f)
+ pMIDIStream->sysExState = eSysExUnivRtTargetID;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExUnivRtTargetID:
+ if (c == 0x04)
+ pMIDIStream->sysExState = eSysExDeviceControl;
+ else if (c == 0x0b)
+ pMIDIStream->sysExState = eSysExSPMIDI;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ /* process master volume */
+ case eSysExDeviceControl:
+ if (c == 0x01)
+ pMIDIStream->sysExState = eSysExMasterVolume;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExMasterVolume:
+ /* save LSB */
+ pMIDIStream->d1 = c;
+ pMIDIStream->sysExState = eSysExMasterVolLSB;
+ break;
+
+ case eSysExMasterVolLSB:
+ if (parserMode != eParserModeMetaData)
+ {
+ EAS_I32 gain = ((EAS_I32) c << 8) | ((EAS_I32) pMIDIStream->d1 << 1);
+ gain = (gain * gain) >> 15;
+ VMSetVolume(pSynth, (EAS_U16) gain);
+ }
+ pMIDIStream->sysExState = eSysExEOX;
+ break;
+
+ /* process SP-MIDI MIP message */
+ case eSysExSPMIDI:
+ if (c == 0x01)
+ {
+ /* assume all channels are muted */
+ if (parserMode != eParserModeMetaData)
+ VMInitMIPTable(pSynth);
+ pMIDIStream->d1 = 0;
+ pMIDIStream->sysExState = eSysExSPMIDIchan;
+ }
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExSPMIDIchan:
+ if (c < NUM_SYNTH_CHANNELS)
+ {
+ pMIDIStream->d2 = c;
+ pMIDIStream->sysExState = eSysExSPMIDIMIP;
+ }
+ else
+ {
+ /* bad MIP message - unmute channels */
+ if (parserMode != eParserModeMetaData)
+ VMInitMIPTable(pSynth);
+ pMIDIStream->sysExState = eSysExIgnore;
+ }
+ break;
+
+ case eSysExSPMIDIMIP:
+ /* process MIP entry here */
+ if (parserMode != eParserModeMetaData)
+ VMSetMIPEntry(pEASData->pVoiceMgr, pSynth, pMIDIStream->d2, pMIDIStream->d1, c);
+ pMIDIStream->sysExState = eSysExSPMIDIchan;
+
+ /* if 16 channels received, update MIP table */
+ if (++pMIDIStream->d1 == NUM_SYNTH_CHANNELS)
+ {
+ if (parserMode != eParserModeMetaData)
+ VMUpdateMIPTable(pEASData->pVoiceMgr, pSynth);
+ pMIDIStream->sysExState = eSysExEOX;
+ }
+ break;
+
+ /* process Enhancer */
+ case eSysExMfgID1:
+ if (c == 0x01)
+ pMIDIStream->sysExState = eSysExMfgID1;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExMfgID2:
+ if (c == 0x3a)
+ pMIDIStream->sysExState = eSysExMfgID1;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExMfgID3:
+ if (c == 0x04)
+ pMIDIStream->sysExState = eSysExEnhancer;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExEnhancer:
+ if (c == 0x01)
+ pMIDIStream->sysExState = eSysExEnhancerSubID;
+ else
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExEnhancerSubID:
+ pMIDIStream->sysExState = eSysExEnhancerFeedback1;
+ break;
+
+ case eSysExEnhancerFeedback1:
+ pMIDIStream->sysExState = eSysExEnhancerFeedback2;
+ break;
+
+ case eSysExEnhancerFeedback2:
+ pMIDIStream->sysExState = eSysExEnhancerDrive;
+ break;
+
+ case eSysExEnhancerDrive:
+ pMIDIStream->sysExState = eSysExEnhancerWet;
+ break;
+
+ case eSysExEnhancerWet:
+ pMIDIStream->sysExState = eSysExEOX;
+ break;
+
+ case eSysExEOX:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Expected F7, received %02x\n", c); */ }
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+
+ case eSysExIgnore:
+ break;
+
+ default:
+ pMIDIStream->sysExState = eSysExIgnore;
+ break;
+ }
+ }
+
+ if (pMIDIStream->sysExState == eSysExIgnore)
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Ignoring SysEx byte %02x\n", c); */ }
+ return EAS_SUCCESS;
+} /* end ProcessSysExMessage */
+