From 4cab03887ccc311e2b195c81703811c1cb6aeb1b Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 5 Dec 2017 16:00:21 +0100 Subject: [PATCH] Add a Raw MIDI parser (based on ALSA raw MIDI) --- libs/ardour/ardour/raw_midi_parser.h | 89 ++++++++++++++++++++ libs/ardour/raw_midi_parser.cc | 118 +++++++++++++++++++++++++++ libs/ardour/wscript | 1 + 3 files changed, 208 insertions(+) create mode 100644 libs/ardour/ardour/raw_midi_parser.h create mode 100644 libs/ardour/raw_midi_parser.cc diff --git a/libs/ardour/ardour/raw_midi_parser.h b/libs/ardour/ardour/raw_midi_parser.h new file mode 100644 index 0000000000..3e1e70066b --- /dev/null +++ b/libs/ardour/ardour/raw_midi_parser.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014,2017 Robin Gareus + * Copyright (C) 2010 Devin Anderson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _ardour_raw_midi_parser_h_ +#define _ardour_raw_midi_parser_h_ + +#include "ardour/libardour_visibility.h" +#include "ardour/types.h" + +namespace ARDOUR { + +class LIBARDOUR_API RawMidiParser +{ +public: + RawMidiParser (); + + void reset () { + _event_size = 0; + _unbuffered_bytes = 0; + _total_bytes = 0; + _expected_bytes = 0; + _status_byte = 0; + } + + uint8_t const * midi_buffer () const { return _parser_buffer; } + size_t buffer_size () const { return _event_size; } + + /** parse a MIDI byte + * @return true if message is complete, false if more data is needed + */ + bool process_byte (const uint8_t byte); + +private: + + void record_byte (uint8_t byte) { + if (_total_bytes < sizeof (_parser_buffer)) { + _parser_buffer[_total_bytes] = byte; + } else { + ++_unbuffered_bytes; + } + ++_total_bytes; + } + + void prepare_byte_event (const uint8_t byte) { + _parser_buffer[0] = byte; + _event_size = 1; + } + + bool prepare_buffered_event () { + const bool result = _unbuffered_bytes == 0; + if (result) { + _event_size = _total_bytes; + } + _total_bytes = 0; + _unbuffered_bytes = 0; + if (_status_byte >= 0xf0) { + _expected_bytes = 0; + _status_byte = 0; + } + return result; + } + + size_t _event_size; + size_t _unbuffered_bytes; + size_t _total_bytes; + size_t _expected_bytes; + uint8_t _status_byte; + uint8_t _parser_buffer[1024]; +}; + +} // namespace ARDOUR + +#endif /* _ardour_raw_midi_parser_h_ */ diff --git a/libs/ardour/raw_midi_parser.cc b/libs/ardour/raw_midi_parser.cc new file mode 100644 index 0000000000..273f792194 --- /dev/null +++ b/libs/ardour/raw_midi_parser.cc @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014,2017 Robin Gareus + * Copyright (C) 2010 Devin Anderson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ardour/raw_midi_parser.h" + +using namespace ARDOUR; + +RawMidiParser::RawMidiParser () +{ + reset (); +} + +/* based on AlsaRawMidiIn, some code-dup */ +bool +RawMidiParser::process_byte (const uint8_t byte) +{ + if (byte >= 0xf8) { + // Realtime + if (byte == 0xfd) { + return false; + } + prepare_byte_event (byte); + return true; + } + if (byte == 0xf7) { + // Sysex end + if (_status_byte == 0xf0) { + record_byte (byte); + return prepare_buffered_event (); + } + _total_bytes = 0; + _unbuffered_bytes = 0; + _expected_bytes = 0; + _status_byte = 0; + return false; + } + if (byte >= 0x80) { + // Non-realtime status byte + if (_total_bytes) { + _total_bytes = 0; + _unbuffered_bytes = 0; + } + _status_byte = byte; + switch (byte & 0xf0) { + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel + _expected_bytes = 3; + break; + case 0xc0: + case 0xd0: + // Program Change, Channel Pressure + _expected_bytes = 2; + break; + case 0xf0: + switch (byte) { + case 0xf0: + // Sysex + _expected_bytes = 0; + break; + case 0xf1: + case 0xf3: + // MTC Quarter Frame, Song Select + _expected_bytes = 2; + break; + case 0xf2: + // Song Position + _expected_bytes = 3; + break; + case 0xf4: + case 0xf5: + // Undefined + _expected_bytes = 0; + _status_byte = 0; + return false; + case 0xf6: + // Tune Request + prepare_byte_event (byte); + _expected_bytes = 0; + _status_byte = 0; + return true; + } + } + record_byte (byte); + return false; + } + // Data byte + if (!_status_byte) { + // Data bytes without a status will be discarded. + _total_bytes++; + _unbuffered_bytes++; + return false; + } + if (!_total_bytes) { + record_byte (_status_byte); + } + record_byte (byte); + return (_total_bytes == _expected_bytes) ? prepare_buffered_event () : false; +} diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 7a4a26c151..8cd06692bf 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -180,6 +180,7 @@ libardour_sources = [ 'quantize.cc', 'rc_configuration.cc', 'readonly_control.cc', + 'raw_midi_parser.cc', 'recent_sessions.cc', 'record_enable_control.cc', 'record_safe_control.cc', -- 2.30.2