X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fmidi%2B%2B2%2Fparser.cc;h=fcee844cefa5e05cc107c68f5dbc99b3c65750d4;hb=efca4413b927d2e728a4cc3e7b892aa9bfd1fdff;hp=4f19c40ebe79d273305d85aab7362a8921bdb01f;hpb=f6fdd8dcbf41f864e9f0cc32dabe81fe3533ddfe;p=ardour.git diff --git a/libs/midi++2/parser.cc b/libs/midi++2/parser.cc index 4f19c40ebe..fcee844cef 100644 --- a/libs/midi++2/parser.cc +++ b/libs/midi++2/parser.cc @@ -1,9 +1,9 @@ /* Copyright (C) 1998 Paul Barton-Davis - This file was inspired by the MIDI parser for KeyKit by - Tim Thompson. - + This file was inspired by the MIDI parser for KeyKit by + Tim Thompson. + 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 @@ -50,63 +50,61 @@ Parser::midi_event_type_name (eventType t) case MIDI::any: return "any midi message"; - + case off: return "note off"; - + case on: return "note on"; - + case polypress: return "aftertouch"; - + case MIDI::controller: return "controller"; - + case program: return "program change"; - + case chanpress: return "channel pressure"; - + case MIDI::pitchbend: return "pitch bend"; - + case MIDI::sysex: return "system exclusive"; - + case MIDI::song: return "song position"; - + case MIDI::tune: return "tune"; - + case MIDI::eox: return "end of sysex"; - + case MIDI::timing: return "timing"; - + case MIDI::start: return "start"; - + case MIDI::stop: return "continue"; - + case MIDI::contineu: return "stop"; - + case active: return "active sense"; - + default: return "unknow MIDI event type"; } } -Parser::Parser (Port &p) - : _port (p) - +Parser::Parser () { trace_stream = 0; trace_prefix = ""; @@ -134,11 +132,11 @@ Parser::Parser (Port &p) Parser::~Parser () { - delete msgbuf; + free (msgbuf); } void -Parser::trace_event (Parser &, byte *msg, size_t len) +Parser::trace_event (Parser &, MIDI::byte *msg, size_t len) { eventType type; ostream *o; @@ -146,7 +144,7 @@ Parser::trace_event (Parser &, byte *msg, size_t len) if ((o = trace_stream) == NULL) { /* can be asynchronously removed */ return; } - + type = (eventType) (msg[0]&0xF0); switch (type) { @@ -160,7 +158,7 @@ Parser::trace_event (Parser &, byte *msg, size_t len) << (int) msg[2] << endmsg; break; - + case on: *o << trace_prefix << "Channel " @@ -171,16 +169,16 @@ Parser::trace_event (Parser &, byte *msg, size_t len) << (int) msg[2] << endmsg; break; - + case polypress: *o << trace_prefix << "Channel " << (msg[0]&0xF)+1 - << " PolyPressure" + << " PolyPressure " << (int) msg[1] << endmsg; break; - + case MIDI::controller: *o << trace_prefix << "Channel " @@ -191,25 +189,25 @@ Parser::trace_event (Parser &, byte *msg, size_t len) << (int) msg[2] << endmsg; break; - + case program: - *o << trace_prefix + *o << trace_prefix << "Channel " << (msg[0]&0xF)+1 << " Program Change ProgNum " << (int) msg[1] << endmsg; break; - + case chanpress: - *o << trace_prefix + *o << trace_prefix << "Channel " << (msg[0]&0xF)+1 << " Channel Pressure " << (int) msg[1] << endmsg; break; - + case MIDI::pitchbend: *o << trace_prefix << "Channel " @@ -218,7 +216,7 @@ Parser::trace_event (Parser &, byte *msg, size_t len) << ((msg[2]<<7)|msg[1]) << endmsg; break; - + case MIDI::sysex: if (len == 1) { switch (msg[0]) { @@ -255,9 +253,9 @@ Parser::trace_event (Parser &, byte *msg, size_t len) default: *o << trace_prefix << "System Exclusive (1 byte : " << hex << (int) *msg << dec << ')' - << endmsg; + << endmsg; break; - } + } } else { *o << trace_prefix << "System Exclusive (" << len << ") = [ " << hex; @@ -265,42 +263,42 @@ Parser::trace_event (Parser &, byte *msg, size_t len) *o << (int) msgbuf[i] << ' '; } *o << dec << ']' << endmsg; - + } break; - + case MIDI::song: *o << trace_prefix << "Song" << endmsg; break; - + case MIDI::tune: *o << trace_prefix << "Tune" << endmsg; break; - + case MIDI::eox: *o << trace_prefix << "End-of-System Exclusive" << endmsg; break; - + case MIDI::timing: *o << trace_prefix << "Timing" << endmsg; break; - + case MIDI::start: *o << trace_prefix << "Start" << endmsg; break; - + case MIDI::stop: *o << trace_prefix << "Stop" << endmsg; break; - + case MIDI::contineu: *o << trace_prefix << "Continue" << endmsg; break; - + case active: *o << trace_prefix << "Active Sense" << endmsg; break; - + default: *o << trace_prefix << "Unrecognized MIDI message" << endmsg; break; @@ -313,10 +311,9 @@ Parser::trace (bool onoff, ostream *o, const string &prefix) trace_connection.disconnect (); if (onoff) { - cerr << "enabling tracing for port " << _port.name() << endl; trace_stream = o; trace_prefix = prefix; - trace_connection = any.connect (boost::bind (&Parser::trace_event, this, _1, _2, _3)); + any.connect_same_thread (trace_connection, boost::bind (&Parser::trace_event, this, _1, _2, _3)); } else { trace_prefix = ""; trace_stream = 0; @@ -327,11 +324,12 @@ void Parser::scanner (unsigned char inbyte) { bool statusbit; + boost::optional edit_result; // cerr << "parse: " << hex << (int) inbyte << dec << " state = " << state << " msgindex = " << msgindex << " runnable = " << runnable << endl; - /* Check active sensing early, so it doesn't interrupt sysex. - + /* Check active sensing early, so it doesn't interrupt sysex. + NOTE: active sense messages are not considered to fit under "any" for the purposes of callbacks. If a caller wants active sense messages handled, which is unlikely, then @@ -339,7 +337,7 @@ Parser::scanner (unsigned char inbyte) every other MIDI message in terms of semantics that its counter-productive to treat them similarly. */ - + if (inbyte == 0xfe) { message_counter[inbyte]++; if (!_offline) { @@ -347,21 +345,21 @@ Parser::scanner (unsigned char inbyte) } return; } - + /* If necessary, allocate larger message buffer. */ - + if (msgindex >= msglen) { msglen *= 2; msgbuf = (unsigned char *) realloc (msgbuf, msglen); } - + /* Real time messages can occur ANYPLACE, - but do not interrupt running status. + but do not interrupt running status. */ bool rtmsg = false; - + switch (inbyte) { case 0xf8: rtmsg = true; @@ -387,12 +385,14 @@ Parser::scanner (unsigned char inbyte) } if (rtmsg) { - if (edit (&inbyte, 1) >= 0 && !_offline) { + boost::optional res = edit (&inbyte, 1); + + if (res.get_value_or (1) >= 0 && !_offline) { realtime_msg (inbyte); } - + return; - } + } statusbit = (inbyte & 0x80); @@ -402,8 +402,9 @@ Parser::scanner (unsigned char inbyte) * an EOX. Actually, since EOX is a status byte, this * code ALWAYS handles the end of a VARIABLELENGTH message. */ - + if (state == VARIABLELENGTH && statusbit) { + /* The message has ended, so process it */ /* add EOX to any sysex message */ @@ -419,24 +420,29 @@ Parser::scanner (unsigned char inbyte) } cerr << dec << endl; #endif - if (msgindex > 0 && edit (msgbuf, msgindex) >= 0) { - if (!possible_mmc (msgbuf, msgindex) || _mmc_forward) { - if (!possible_mtc (msgbuf, msgindex) || _mtc_forward) { - if (!_offline) { - sysex (*this, msgbuf, msgindex); + if (msgindex > 0) { + + boost::optional res = edit (msgbuf, msgindex); + + if (res.get_value_or (1) >= 0) { + if (!possible_mmc (msgbuf, msgindex) || _mmc_forward) { + if (!possible_mtc (msgbuf, msgindex) || _mtc_forward) { + if (!_offline) { + sysex (*this, msgbuf, msgindex); + } } } - } - if (!_offline) { - any (*this, msgbuf, msgindex); + if (!_offline) { + any (*this, msgbuf, msgindex); + } } } } - + /* * Status bytes always start a new message, except EOX */ - + if (statusbit) { msgindex = 0; @@ -463,11 +469,11 @@ Parser::scanner (unsigned char inbyte) return; } - + /* * We've got a Data byte. */ - + msgbuf[msgindex++] = inbyte; switch (state) { @@ -481,31 +487,33 @@ Parser::scanner (unsigned char inbyte) * messages, so just handle it silently. */ break; - + case NEEDTWOBYTES: /* wait for the second byte */ if (msgindex < 3) return; /*FALLTHRU*/ - + case NEEDONEBYTE: /* We've completed a 1 or 2 byte message. */ - - if (edit (msgbuf, msgindex) == 0) { - + + edit_result = edit (msgbuf, msgindex); + + if (edit_result.get_value_or (1)) { + /* message not cancelled by an editor */ - + message_counter[msgbuf[0] & 0xF0]++; if (!_offline) { signal (msgbuf, msgindex); } } - + if (runnable) { - /* In Runnable mode, we reset the message - index, but keep the callbacks_pending and state the - same. This provides the "running status + /* In Runnable mode, we reset the message + index, but keep the callbacks_pending and state the + same. This provides the "running status byte" feature. */ msgindex = 1; @@ -514,7 +522,7 @@ Parser::scanner (unsigned char inbyte) state = NEEDSTATUS; } break; - + case VARIABLELENGTH: /* nothing to do */ break; @@ -550,7 +558,7 @@ Parser::realtime_msg(unsigned char inbyte) break; case 0xfe: /* !!! active sense message in realtime_msg: should not reach here - */ + */ break; case 0xff: reset (*this); @@ -568,9 +576,9 @@ Parser::channel_msg(unsigned char inbyte) { last_status_byte = inbyte; runnable = true; /* Channel messages can use running status */ - + /* The high 4 bits, which determine the type of channel message. */ - + switch (inbyte&0xF0) { case 0x80: msgtype = off; @@ -644,13 +652,13 @@ Parser::system_msg (unsigned char inbyte) break; } - // all these messages will be sent via any() + // all these messages will be sent via any() // when they are complete. // any (*this, &inbyte, 1); } -void -Parser::signal (byte *msg, size_t len) +void +Parser::signal (MIDI::byte *msg, size_t len) { channel_t chan = msg[0]&0xF; int chan_i = chan; @@ -658,15 +666,15 @@ Parser::signal (byte *msg, size_t len) switch (msgtype) { case none: break; - + case off: channel_active_preparse[chan_i] (*this); note_off (*this, (EventTwoBytes *) &msg[1]); - channel_note_off[chan_i] + channel_note_off[chan_i] (*this, (EventTwoBytes *) &msg[1]); channel_active_postparse[chan_i] (*this); break; - + case on: channel_active_preparse[chan_i] (*this); @@ -676,54 +684,54 @@ Parser::signal (byte *msg, size_t len) if (msg[2] == 0) { note_off (*this, (EventTwoBytes *) &msg[1]); - channel_note_off[chan_i] + channel_note_off[chan_i] (*this, (EventTwoBytes *) &msg[1]); } else { note_on (*this, (EventTwoBytes *) &msg[1]); - channel_note_on[chan_i] + channel_note_on[chan_i] (*this, (EventTwoBytes *) &msg[1]); } channel_active_postparse[chan_i] (*this); break; - + case MIDI::controller: channel_active_preparse[chan_i] (*this); controller (*this, (EventTwoBytes *) &msg[1]); - channel_controller[chan_i] + channel_controller[chan_i] (*this, (EventTwoBytes *) &msg[1]); channel_active_postparse[chan_i] (*this); break; - + case program: channel_active_preparse[chan_i] (*this); program_change (*this, msg[1]); channel_program_change[chan_i] (*this, msg[1]); channel_active_postparse[chan_i] (*this); break; - + case chanpress: channel_active_preparse[chan_i] (*this); pressure (*this, msg[1]); channel_pressure[chan_i] (*this, msg[1]); channel_active_postparse[chan_i] (*this); break; - + case polypress: channel_active_preparse[chan_i] (*this); poly_pressure (*this, (EventTwoBytes *) &msg[1]); - channel_poly_pressure[chan_i] + channel_poly_pressure[chan_i] (*this, (EventTwoBytes *) &msg[1]); channel_active_postparse[chan_i] (*this); break; - + case MIDI::pitchbend: channel_active_preparse[chan_i] (*this); pitchbend (*this, (msg[2]<<7)|msg[1]); channel_pitchbend[chan_i] (*this, (msg[2]<<7)|msg[1]); channel_active_postparse[chan_i] (*this); break; - + case MIDI::sysex: sysex (*this, msg, len); break; @@ -732,28 +740,28 @@ Parser::signal (byte *msg, size_t len) process_mtc_quarter_frame (msg); mtc_quarter_frame (*this, *msg); break; - + case MIDI::position: position (*this, msg, len); break; - + case MIDI::song: song (*this, msg, len); break; - + case MIDI::tune: tune (*this); - + default: /* XXX some kind of warning ? */ break; } - + any (*this, msg, len); } bool -Parser::possible_mmc (byte *msg, size_t msglen) +Parser::possible_mmc (MIDI::byte *msg, size_t msglen) { if (!MachineControl::is_mmc (msg, msglen)) { return false; @@ -780,7 +788,7 @@ Parser::set_offline (bool yn) /* this hack deals with the possibility of our first MIDI bytes being running status messages. */ - + channel_msg (0x90); state = NEEDSTATUS; }