text: /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
   * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
   *
   *  This program is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU Lesser General Public License as published by
   *  the Free Software Foundation, either version 2.1 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU Lesser General Public License for more details.
   *
   *  You should have received a copy of the GNU Lesser General Public License
   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #ifndef MT32EMU_MIDI_STREAM_PARSER_H
  #define MT32EMU_MIDI_STREAM_PARSER_H
  
  #include "globals.h"
  #include "Types.h"
  
  namespace MT32Emu {
  
  class Synth;
  
  // Interface for a user-supplied class to receive parsed well-formed MIDI messages.
  class MT32EMU_EXPORT MidiReceiver {
  public:
  	// Invoked when a complete short MIDI message is parsed in the input MIDI stream.
  	virtual void handleShortMessage(const uint32_t message) = 0;
  
  	// Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream.
  	virtual void handleSysex(const uint8_t stream[], const uint32_t length) = 0;
  
  	// Invoked when a System Realtime MIDI message is parsed in the input MIDI stream.
  	virtual void handleSystemRealtimeMessage(const uint8_t realtime) = 0;
  
  protected:
  	~MidiReceiver() {}
  };
  
  // Interface for a user-supplied class to receive notifications of input MIDI stream parse errors.
  class MT32EMU_EXPORT MidiReporter {
  public:
  	// Invoked when an error occurs during processing the input MIDI stream.
  	virtual void printDebug(const char *debugMessage) = 0;
  
  protected:
  	~MidiReporter() {}
  };
  
  // Provides a context for parsing a stream of MIDI events coming from a single source.
  // There can be multiple MIDI sources feeding MIDI events to a single Synth object.
  // NOTE: Calls from multiple threads which feed a single Synth object with data must be explicitly synchronised,
  // although, no synchronisation is required with the rendering thread.
  class MT32EMU_EXPORT MidiStreamParserImpl {
  public:
  	// The first two arguments provide for implementations of essential interfaces needed.
  	// The third argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected.
  	// If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes).
  	// Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use.
  	MidiStreamParserImpl(MidiReceiver &, MidiReporter &, uint32_t initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
  	virtual ~MidiStreamParserImpl();
  
  	// Parses a block of raw MIDI bytes. All the parsed MIDI messages are sent in sequence to the user-supplied methods for further processing.
  	// SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages.
  	// NOTE: the total length of a SysEx message being fragmented shall not exceed MAX_STREAM_BUFFER_SIZE (32768 bytes).
  	void parseStream(const uint8_t *stream, uint32_t length);
  
  	// Convenience method which accepts a uint32_t-encoded short MIDI message and sends it to the user-supplied method for further processing.
  	// The short MIDI message may contain no status byte, the running status is used in this case.
  	void processShortMessage(const uint32_t message);
  
  private:
  	uint8_t runningStatus;
  	uint8_t *streamBuffer;
  	uint32_t streamBufferCapacity;
  	uint32_t streamBufferSize;
  	MidiReceiver &midiReceiver;
  	MidiReporter &midiReporter;
  
  	// Binary compatibility helper.
  	void *reserved;
  
  	bool checkStreamBufferCapacity(const bool preserveContent);
  	bool processStatusByte(uint8_t &status);
  	uint32_t parseShortMessageStatus(const uint8_t stream[]);
  	uint32_t parseShortMessageDataBytes(const uint8_t stream[], uint32_t length);
  	uint32_t parseSysex(const uint8_t stream[], const uint32_t length);
  	uint32_t parseSysexFragment(const uint8_t stream[], const uint32_t length);
  }; // class MidiStreamParserImpl
  
  // An abstract class that provides a context for parsing a stream of MIDI events coming from a single source.
  class MT32EMU_EXPORT MidiStreamParser : public MidiStreamParserImpl, protected MidiReceiver, protected MidiReporter {
  public:
  	// The argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected.
  	// If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes).
  	// Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use.
  	explicit MidiStreamParser(uint32_t initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
  };
  
  class MT32EMU_EXPORT DefaultMidiStreamParser : public MidiStreamParser {
  public:
  	explicit DefaultMidiStreamParser(Synth &synth, uint32_t initialStreamBufferCapacity = SYSEX_BUFFER_SIZE);
  	void setTimestamp(const uint32_t useTimestamp);
  	void resetTimestamp();
  
  protected:
  	void handleShortMessage(const uint32_t message);
  	void handleSysex(const uint8_t *stream, const uint32_t length);
  	void handleSystemRealtimeMessage(const uint8_t realtime);
  	void printDebug(const char *debugMessage);
  
  private:
  	Synth &synth;
  	bool timestampSet;
  	uint32_t timestamp;
  };
  
  } // namespace MT32Emu
  
  #endif // MT32EMU_MIDI_STREAM_PARSER_H
  