diff options
Diffstat (limited to 'arm-wt-22k/lib_src/eas_midi.c')
-rw-r--r-- | arm-wt-22k/lib_src/eas_midi.c | 1114 |
1 files changed, 557 insertions, 557 deletions
diff --git a/arm-wt-22k/lib_src/eas_midi.c b/arm-wt-22k/lib_src/eas_midi.c index 0c77aea..8cb043a 100644 --- a/arm-wt-22k/lib_src/eas_midi.c +++ b/arm-wt-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 */ + |