Normalise names of .cc and .h files.
authorCarl Hetherington <carl@carlh.net>
Tue, 15 Sep 2009 16:49:15 +0000 (16:49 +0000)
committerCarl Hetherington <carl@carlh.net>
Tue, 15 Sep 2009 16:49:15 +0000 (16:49 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5664 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/midi++2/channel.cc [new file with mode: 0644]
libs/midi++2/factory.cc [new file with mode: 0644]
libs/midi++2/manager.cc [new file with mode: 0644]
libs/midi++2/midichannel.cc [deleted file]
libs/midi++2/midifactory.cc [deleted file]
libs/midi++2/midimanager.cc [deleted file]
libs/midi++2/midiparser.cc [deleted file]
libs/midi++2/midiport.cc [deleted file]
libs/midi++2/parser.cc [new file with mode: 0644]
libs/midi++2/port.cc [new file with mode: 0644]
libs/midi++2/wscript

diff --git a/libs/midi++2/channel.cc b/libs/midi++2/channel.cc
new file mode 100644 (file)
index 0000000..f19c913
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+    Copyright (C) 1998-99 Paul Barton-Davis 
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <cstring>
+#include "midi++/types.h"
+#include "midi++/port.h"
+#include "midi++/channel.h"
+
+using namespace sigc;
+using namespace MIDI;
+
+Channel::Channel (byte channelnum, Port &p) : _port (p)
+{
+       _channel_number = channelnum;
+
+       reset (0, 1, false);
+}      
+
+void
+Channel::connect_input_signals ()
+
+{
+       _port.input()->channel_pressure[_channel_number].connect
+               (mem_fun (*this, &Channel::process_chanpress));
+       _port.input()->channel_note_on[_channel_number].connect
+               (mem_fun (*this, &Channel::process_note_on));
+       _port.input()->channel_note_off[_channel_number].connect
+               (mem_fun (*this, &Channel::process_note_off));
+       _port.input()->channel_poly_pressure[_channel_number].connect
+               (mem_fun (*this, &Channel::process_polypress));
+       _port.input()->channel_program_change[_channel_number].connect
+               (mem_fun (*this, &Channel::process_program_change));
+       _port.input()->channel_controller[_channel_number].connect
+               (mem_fun (*this, &Channel::process_controller));
+       _port.input()->channel_pitchbend[_channel_number].connect
+               (mem_fun (*this, &Channel::process_pitchbend));
+       _port.input()->reset.connect (mem_fun (*this, &Channel::process_reset));
+}
+
+void
+Channel::connect_output_signals ()
+
+{
+       _port.output()->channel_pressure[_channel_number].connect
+               (mem_fun (*this, &Channel::process_chanpress));
+       _port.output()->channel_note_on[_channel_number].connect
+               (mem_fun (*this, &Channel::process_note_on));
+       _port.output()->channel_note_off[_channel_number].connect
+               (mem_fun (*this, &Channel::process_note_off));
+       _port.output()->channel_poly_pressure[_channel_number].connect
+               (mem_fun (*this, &Channel::process_polypress));
+       _port.output()->channel_program_change[_channel_number].connect
+               (mem_fun (*this, &Channel::process_program_change));
+       _port.output()->channel_controller[_channel_number].connect
+               (mem_fun (*this, &Channel::process_controller));
+       _port.output()->channel_pitchbend[_channel_number].connect
+               (mem_fun (*this, &Channel::process_pitchbend));
+       _port.output()->reset.connect (mem_fun (*this, &Channel::process_reset));
+}
+
+void
+Channel::reset (timestamp_t timestamp, nframes_t /*nframes*/, bool notes_off)
+{
+       _program_number = _channel_number;
+       _bank_number = 0;
+       _pitch_bend = 0;
+
+       _last_note_on = 0;
+       _last_note_off = 0;
+       _last_on_velocity = 0;
+       _last_off_velocity = 0;
+
+       if (notes_off) {
+               all_notes_off (timestamp);
+       }
+
+       memset (_polypress, 0, sizeof (_polypress));
+       memset (_controller_msb, 0, sizeof (_controller_msb));
+       memset (_controller_lsb, 0, sizeof (_controller_lsb));
+       
+       /* zero all controllers XXX not necessarily the right thing */
+
+       memset (_controller_val, 0, sizeof (_controller_val));
+
+       for (int n = 0; n < 128; n++) {
+               _controller_14bit[n] = false;
+       }
+
+       _rpn_msb = 0;
+       _rpn_lsb = 0;
+       _nrpn_msb = 0;
+       _nrpn_lsb = 0;
+
+       _omni = true;
+       _poly = false;
+       _mono = true;
+       _notes_on = 0;
+}
+
+void
+Channel::process_note_off (Parser & /*parser*/, EventTwoBytes *tb) 
+{
+       _last_note_off = tb->note_number;
+       _last_off_velocity = tb->velocity;
+
+       if (_notes_on) {
+               _notes_on--;
+       }
+}
+
+void
+Channel::process_note_on (Parser & /*parser*/, EventTwoBytes *tb) 
+{
+       _last_note_on = tb->note_number;
+       _last_on_velocity = tb->velocity;
+       _notes_on++;
+}
+
+void
+Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) 
+{
+       unsigned short cv;
+
+       /* XXX arguably need a lock here to protect non-atomic changes
+          to controller_val[...]. or rather, need to make sure that
+          all changes *are* atomic.
+       */
+
+       if (tb->controller_number <= 31) { /* unsigned: no test for >= 0 */
+
+               /* if this controller is already known to use 14 bits,
+                  then treat this value as the MSB, and combine it 
+                  with the existing LSB.
+
+                  otherwise, just treat it as a 7 bit value, and set
+                  it directly.
+               */
+
+               cv = (unsigned short) _controller_val[tb->controller_number];
+
+               if (_controller_14bit[tb->controller_number]) {
+                       cv = ((tb->value << 7) | (cv & 0x7f));
+               } else {
+                       cv = tb->value;
+               }
+
+               _controller_val[tb->controller_number] = (controller_value_t)cv;
+
+       } else if ((tb->controller_number >= 32 && 
+                   tb->controller_number <= 63)) {
+                  
+               cv = (unsigned short) _controller_val[tb->controller_number];
+
+               /* LSB for CC 0-31 arrived. 
+
+                  If this is the first time (i.e. its currently
+                  flagged as a 7 bit controller), mark the
+                  controller as 14 bit, adjust the existing value
+                  to be the MSB, and OR-in the new LSB value. 
+
+                  otherwise, OR-in the new low 7bits with the old
+                  high 7.
+               */
+
+               int cn = tb->controller_number - 32;
+                  
+               if (_controller_14bit[cn] == false) {
+                       _controller_14bit[cn] = true;
+                       cv = (cv << 7) | (tb->value & 0x7f);
+               } else {
+                       cv = (cv & 0x3f80) | (tb->value & 0x7f);
+               }
+
+               _controller_val[tb->controller_number] = 
+                       (controller_value_t) cv;
+       } else {
+
+               /* controller can only take 7 bit values */
+               
+               _controller_val[tb->controller_number] = 
+                       (controller_value_t) tb->value;
+       }
+
+       /* bank numbers are special, in that they have their own signal
+        */
+
+       if (tb->controller_number == 0) {
+               _bank_number = (unsigned short) _controller_val[0];
+               if (_port.input()) {
+                       _port.input()->bank_change (*_port.input(), _bank_number);
+                       _port.input()->channel_bank_change[_channel_number] 
+                               (*_port.input(), _bank_number);
+               }
+       }
+
+}
+
+void
+Channel::process_program_change (Parser & /*parser*/, byte val) 
+{
+       _program_number = val;
+}
+
+void
+Channel::process_chanpress (Parser & /*parser*/, byte val) 
+{
+       _chanpress = val;
+}
+
+void
+Channel::process_polypress (Parser & /*parser*/, EventTwoBytes *tb) 
+{
+       _polypress[tb->note_number] = tb->value;
+}
+
+void
+Channel::process_pitchbend (Parser & /*parser*/, pitchbend_t val) 
+{
+       _pitch_bend = val;
+}
+
+void
+Channel::process_reset (Parser & /*parser*/) 
+{
+       reset (0, 1);
+}
+
+/** Write a message to a channel.
+ * \return true if success
+ */
+bool
+Channel::channel_msg (byte id, byte val1, byte val2, timestamp_t timestamp)
+{
+       unsigned char msg[3];
+       int len = 0;
+
+       msg[0] = id | (_channel_number & 0xf);
+
+       switch (id) {
+       case off:
+               msg[1] = val1 & 0x7F;
+               msg[2] = val2 & 0x7F;
+               len = 3;
+               break;
+
+       case on:
+               msg[1] = val1 & 0x7F;
+               msg[2] = val2 & 0x7F;
+               len = 3;
+               break;
+
+       case MIDI::polypress:
+               msg[1] = val1 & 0x7F;
+               msg[2] = val2 & 0x7F;
+               len = 3;
+               break;
+
+       case controller:
+               msg[1] = val1 & 0x7F;
+               msg[2] = val2 & 0x7F;
+               len = 3;
+               break;
+
+       case MIDI::program:
+               msg[1] = val1 & 0x7F;
+               len = 2;
+               break;
+
+       case MIDI::chanpress:
+               msg[1] = val1 & 0x7F;
+               len = 2;
+               break;
+
+       case MIDI::pitchbend:
+               msg[1] = val1 & 0x7F;
+               msg[2] = val2 & 0x7F;
+               len = 3;
+               break;
+       }
+
+       return _port.midimsg (msg, len, timestamp);
+}
diff --git a/libs/midi++2/factory.cc b/libs/midi++2/factory.cc
new file mode 100644 (file)
index 0000000..1980ac5
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+    Copyright (C) 1998-99 Paul Barton-Davis 
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <cassert>
+#include <stdint.h>
+
+#include "pbd/error.h"
+#include "pbd/convert.h"
+
+#include "midi++/types.h"
+#include "midi++/factory.h"
+#include "midi++/fifomidi.h"
+
+#ifdef WITH_JACK_MIDI
+#include "midi++/jack.h"
+
+std::string MIDI::JACK_MidiPort::typestring = "jack";
+#endif // WITH_JACK_MIDI
+
+std::string MIDI::FIFO_MidiPort::typestring = "fifo";
+
+#ifdef WITH_ALSA
+#include "midi++/alsa_sequencer.h"
+#include "midi++/alsa_rawmidi.h"
+
+std::string MIDI::ALSA_SequencerMidiPort::typestring = "alsa/sequencer";
+std::string MIDI::ALSA_RawMidiPort::typestring = "alsa/raw";
+
+#endif // WITH_ALSA
+
+#ifdef WITH_COREMIDI
+#include "midi++/coremidi_midiport.h"
+
+std::string MIDI::CoreMidi_MidiPort::typestring = "coremidi";
+
+#endif // WITH_COREMIDI
+
+using namespace std;
+using namespace MIDI;
+using namespace PBD;
+
+// FIXME: void* data pointer, filthy
+Port *
+PortFactory::create_port (const XMLNode& node, void* data)
+
+{
+       Port::Descriptor desc (node);
+       Port *port;
+       
+       switch (desc.type) {
+#ifdef WITH_JACK_MIDI
+       case Port::JACK_Midi:
+               assert(data != NULL);
+               port = new JACK_MidiPort (node, (jack_client_t*) data);
+               break;
+#endif // WITH_JACK_MIDI
+       
+#ifdef WITH_ALSA
+       case Port::ALSA_RawMidi:
+               port = new ALSA_RawMidiPort (node);
+               break;
+
+       case Port::ALSA_Sequencer:
+               port = new ALSA_SequencerMidiPort (node);
+               break;
+#endif // WITH_ALSA
+
+#if WITH_COREMIDI
+       case Port::CoreMidi_MidiPort:
+               port = new CoreMidi_MidiPort (node);
+               break;
+#endif // WITH_COREMIDI
+
+       case Port::FIFO:
+               port = new FIFO_MidiPort (node);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return port;
+}
+
+bool 
+PortFactory::ignore_duplicate_devices (Port::Type type)
+{
+       bool ret = false;
+
+       switch (type) {
+#ifdef WITH_ALSA
+       case Port::ALSA_Sequencer:
+               ret = true;
+               break;
+#endif // WITH_ALSA
+
+#if WITH_COREMIDI
+       case Port::CoreMidi_MidiPort:
+               ret = true;
+               break;
+#endif // WITH_COREMIDI
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+int
+#if defined (WITH_ALSA) || defined (WITH_COREMIDI)
+PortFactory::get_known_ports (vector<PortSet>& ports)
+#else
+PortFactory::get_known_ports (vector<PortSet>&)
+#endif 
+{
+       int n = 0;
+#ifdef WITH_ALSA
+       n += ALSA_SequencerMidiPort::discover (ports);
+#endif // WITH_ALSA
+
+#if WITH_COREMIDI
+       n += CoreMidi_MidiPort::discover (ports);
+#endif // WITH_COREMIDI
+       
+       return n;
+}
+
+std::string
+PortFactory::default_port_type ()
+{
+#ifdef WITH_JACK_MIDI
+       return "jack";
+#endif
+
+#ifdef WITH_ALSA
+       return "alsa/sequencer";
+#endif
+
+#ifdef WITH_COREMIDI
+       return "coremidi";
+#endif // WITH_COREMIDI
+       
+       PBD::fatal << "programming error: no default port type defined in midifactory.cc" << endmsg;
+       /*NOTREACHED*/
+       return "";
+}
+
+Port::Type
+PortFactory::string_to_type (const string& xtype)
+{
+       if (0){ 
+#ifdef WITH_ALSA
+       } else if (strings_equal_ignore_case (xtype, ALSA_RawMidiPort::typestring)) {
+               return Port::ALSA_RawMidi;
+       } else if (strings_equal_ignore_case (xtype, ALSA_SequencerMidiPort::typestring)) {
+               return Port::ALSA_Sequencer;
+#endif 
+#ifdef WITH_COREMIDI
+       } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) {
+               return Port::CoreMidi_MidiPort;
+#endif
+       } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) {
+               return Port::FIFO;
+#ifdef WITH_JACK_MIDI
+       } else if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) {
+               return Port::JACK_Midi;
+#endif
+       }
+
+       return Port::Unknown;
+}
+
+string
+PortFactory::mode_to_string (int mode)
+{
+       if (mode == O_RDONLY) {
+               return "input";
+       } else if (mode == O_WRONLY) {
+               return "output";
+       } 
+
+       return "duplex";
+}
+
+int
+PortFactory::string_to_mode (const string& str)
+{
+       if (strings_equal_ignore_case (str, "output") || strings_equal_ignore_case (str, "out")) {
+               return O_WRONLY;
+       } else if (strings_equal_ignore_case (str, "input") || strings_equal_ignore_case (str, "in")) {
+               return O_RDONLY;
+       }
+
+       return O_RDWR;
+}
diff --git a/libs/midi++2/manager.cc b/libs/midi++2/manager.cc
new file mode 100644 (file)
index 0000000..ab03688
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+    Copyright (C) 1998-99 Paul Barton-Davis 
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include "pbd/error.h"
+
+#include "midi++/types.h"
+#include "midi++/manager.h"
+#include "midi++/factory.h"
+#include "midi++/channel.h"
+
+using namespace std;
+using namespace MIDI;
+using namespace PBD;
+
+/* XXX check for strdup leaks */
+
+Manager *Manager::theManager = 0;
+
+Manager::Manager () 
+{
+       inputPort = 0;
+       outputPort = 0;
+       inputChannelNumber = 0;
+       outputChannelNumber = 0;
+       api_data = 0;
+}
+
+Manager::~Manager ()
+{
+       PortMap::iterator i;
+
+       for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+               delete (*i).second;
+       }
+
+       ports_by_device.erase (ports_by_device.begin(), ports_by_device.end());
+       ports_by_tag.erase (ports_by_tag.begin(), ports_by_tag.end());
+
+       if (theManager == this) {
+               theManager = 0;
+       }
+}
+
+Port *
+Manager::add_port (const XMLNode& node)
+{
+       Port::Descriptor desc (node);
+       PortFactory factory;
+       Port *port;
+       PortMap::iterator existing;
+       pair<string, Port *> newpair;
+
+       /* do not allow multiple ports with the same tag. if attempted, just return the existing
+          port with the same tag. XXX this is really caused by the mess of setup_midi() being
+          called twice in Ardour, once in the global init() function and once after the user RC file
+          has been loaded (there may be extra ports in it). 
+        */
+
+       if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
+
+               port = (*existing).second;
+               
+               if (port->mode() == desc.mode) {
+                       
+                       /* Same mode - reuse the port, and just
+                          create a new tag entry.
+                       */
+                       
+                       newpair.first = desc.tag;
+                       newpair.second = port;
+                       
+                       ports_by_tag.insert (newpair);
+                       return port;
+               }
+               
+               /* If the existing is duplex, and this request
+                  is not, then fail, because most drivers won't
+                  allow opening twice with duplex and non-duplex
+                  operation.
+               */
+               
+               if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
+                   (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
+                       error << "MIDIManager: port tagged \""
+                             << desc.tag
+                             << "\" cannot be opened duplex and non-duplex"
+                             << endmsg;
+                       return 0;
+               }
+               
+               /* modes must be different or complementary */
+       }
+
+       if (!PortFactory::ignore_duplicate_devices (desc.type)) {
+
+               if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
+                       
+                       port = (*existing).second;
+                       
+                       if (port->mode() == desc.mode) {
+                               
+                               /* Same mode - reuse the port, and just
+                                  create a new tag entry.
+                               */
+                               
+                               newpair.first = desc.tag;
+                               newpair.second = port;
+                               
+                               ports_by_tag.insert (newpair);
+                               return port;
+                       }
+                       
+                       /* If the existing is duplex, and this request
+                          is not, then fail, because most drivers won't
+                          allow opening twice with duplex and non-duplex
+                          operation.
+                       */
+                       
+                       if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
+                           (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
+                               error << "MIDIManager: port tagged \""
+                                     << desc.tag
+                                     << "\" cannot be opened duplex and non-duplex"
+                                     << endmsg;
+                               return 0;
+                       }
+                       
+                       /* modes must be different or complementary */
+               }
+       }
+       
+       port = factory.create_port (node, api_data);
+       
+       if (port == 0) {
+               return 0;
+       }
+
+       if (!port->ok()) {
+               delete port;
+               return 0;
+       }
+
+       newpair.first = port->name();
+       newpair.second = port;
+       ports_by_tag.insert (newpair);
+
+       newpair.first = port->device();
+       newpair.second = port;
+       ports_by_device.insert (newpair);
+
+       /* first port added becomes the default input
+          port.
+       */
+
+       if (inputPort == 0) {
+               inputPort = port;
+       } 
+
+       if (outputPort == 0) {
+               outputPort = port;
+       }
+
+       return port;
+}
+
+int 
+Manager::remove_port (Port* port)
+{
+       PortMap::iterator res;
+
+       for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
+               PortMap::iterator tmp;
+               tmp = res;
+               ++tmp;
+               if (res->second == port) {
+                       ports_by_device.erase (res);
+               } 
+               res = tmp;
+       }
+
+
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
+               PortMap::iterator tmp;
+               tmp = res;
+               ++tmp;
+               if (res->second == port) {
+                       ports_by_tag.erase (res);
+               } 
+               res = tmp;
+       }
+       
+       delete port;
+
+       return 0;
+}
+
+int
+Manager::set_input_port (string tag)
+{
+       PortMap::iterator res;
+       bool found = false;
+
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+               if (tag == (*res).first) {
+                       found = true;
+                       break;
+               }
+       }
+       
+       if (!found) {
+               return -1;
+       }
+
+       inputPort = (*res).second;
+
+       return 0;
+}
+
+int
+Manager::set_output_port (string tag)
+
+{
+       PortMap::iterator res;
+       bool found = false;
+
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+               if (tag == (*res).first) {
+                       found = true;
+                       break;
+               }
+       }
+       
+       if (!found) {
+               return -1;
+       }
+
+       // XXX send a signal to say we're about to change output ports
+
+       if (outputPort) {
+               for (channel_t chan = 0; chan < 16; chan++) {
+                       outputPort->channel (chan)->all_notes_off (0);
+               }
+       }
+       outputPort = (*res).second;
+
+       // XXX send a signal to say we've changed output ports
+
+       return 0;
+}
+
+Port *
+Manager::port (string name)
+{
+       PortMap::iterator res;
+
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+               if (name == (*res).first) {
+                       return (*res).second;
+               }
+       }
+
+       return 0;
+}
+
+int
+Manager::foreach_port (int (*func)(const Port &, size_t, void *),
+                          void *arg)
+{
+       PortMap::const_iterator i;
+       int retval;
+       int n;
+               
+       for (n = 0, i = ports_by_device.begin(); 
+                   i != ports_by_device.end(); i++, n++) {
+
+               if ((retval = func (*((*i).second), n, arg)) != 0) {
+                       return retval;
+               }
+       }
+
+       return 0;
+}
+
+void
+Manager::cycle_start(nframes_t nframes)
+{
+       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+               (*i).second->cycle_start (nframes);
+       }
+}
+
+void
+Manager::cycle_end()
+{
+       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+               (*i).second->cycle_end ();
+       }
+}
+
+
+int
+Manager::get_known_ports (vector<PortSet>& ports)
+{
+       return PortFactory::get_known_ports (ports);
+}
diff --git a/libs/midi++2/midichannel.cc b/libs/midi++2/midichannel.cc
deleted file mode 100644 (file)
index f19c913..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
-    Copyright (C) 1998-99 Paul Barton-Davis 
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include <cstring>
-#include "midi++/types.h"
-#include "midi++/port.h"
-#include "midi++/channel.h"
-
-using namespace sigc;
-using namespace MIDI;
-
-Channel::Channel (byte channelnum, Port &p) : _port (p)
-{
-       _channel_number = channelnum;
-
-       reset (0, 1, false);
-}      
-
-void
-Channel::connect_input_signals ()
-
-{
-       _port.input()->channel_pressure[_channel_number].connect
-               (mem_fun (*this, &Channel::process_chanpress));
-       _port.input()->channel_note_on[_channel_number].connect
-               (mem_fun (*this, &Channel::process_note_on));
-       _port.input()->channel_note_off[_channel_number].connect
-               (mem_fun (*this, &Channel::process_note_off));
-       _port.input()->channel_poly_pressure[_channel_number].connect
-               (mem_fun (*this, &Channel::process_polypress));
-       _port.input()->channel_program_change[_channel_number].connect
-               (mem_fun (*this, &Channel::process_program_change));
-       _port.input()->channel_controller[_channel_number].connect
-               (mem_fun (*this, &Channel::process_controller));
-       _port.input()->channel_pitchbend[_channel_number].connect
-               (mem_fun (*this, &Channel::process_pitchbend));
-       _port.input()->reset.connect (mem_fun (*this, &Channel::process_reset));
-}
-
-void
-Channel::connect_output_signals ()
-
-{
-       _port.output()->channel_pressure[_channel_number].connect
-               (mem_fun (*this, &Channel::process_chanpress));
-       _port.output()->channel_note_on[_channel_number].connect
-               (mem_fun (*this, &Channel::process_note_on));
-       _port.output()->channel_note_off[_channel_number].connect
-               (mem_fun (*this, &Channel::process_note_off));
-       _port.output()->channel_poly_pressure[_channel_number].connect
-               (mem_fun (*this, &Channel::process_polypress));
-       _port.output()->channel_program_change[_channel_number].connect
-               (mem_fun (*this, &Channel::process_program_change));
-       _port.output()->channel_controller[_channel_number].connect
-               (mem_fun (*this, &Channel::process_controller));
-       _port.output()->channel_pitchbend[_channel_number].connect
-               (mem_fun (*this, &Channel::process_pitchbend));
-       _port.output()->reset.connect (mem_fun (*this, &Channel::process_reset));
-}
-
-void
-Channel::reset (timestamp_t timestamp, nframes_t /*nframes*/, bool notes_off)
-{
-       _program_number = _channel_number;
-       _bank_number = 0;
-       _pitch_bend = 0;
-
-       _last_note_on = 0;
-       _last_note_off = 0;
-       _last_on_velocity = 0;
-       _last_off_velocity = 0;
-
-       if (notes_off) {
-               all_notes_off (timestamp);
-       }
-
-       memset (_polypress, 0, sizeof (_polypress));
-       memset (_controller_msb, 0, sizeof (_controller_msb));
-       memset (_controller_lsb, 0, sizeof (_controller_lsb));
-       
-       /* zero all controllers XXX not necessarily the right thing */
-
-       memset (_controller_val, 0, sizeof (_controller_val));
-
-       for (int n = 0; n < 128; n++) {
-               _controller_14bit[n] = false;
-       }
-
-       _rpn_msb = 0;
-       _rpn_lsb = 0;
-       _nrpn_msb = 0;
-       _nrpn_lsb = 0;
-
-       _omni = true;
-       _poly = false;
-       _mono = true;
-       _notes_on = 0;
-}
-
-void
-Channel::process_note_off (Parser & /*parser*/, EventTwoBytes *tb) 
-{
-       _last_note_off = tb->note_number;
-       _last_off_velocity = tb->velocity;
-
-       if (_notes_on) {
-               _notes_on--;
-       }
-}
-
-void
-Channel::process_note_on (Parser & /*parser*/, EventTwoBytes *tb) 
-{
-       _last_note_on = tb->note_number;
-       _last_on_velocity = tb->velocity;
-       _notes_on++;
-}
-
-void
-Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) 
-{
-       unsigned short cv;
-
-       /* XXX arguably need a lock here to protect non-atomic changes
-          to controller_val[...]. or rather, need to make sure that
-          all changes *are* atomic.
-       */
-
-       if (tb->controller_number <= 31) { /* unsigned: no test for >= 0 */
-
-               /* if this controller is already known to use 14 bits,
-                  then treat this value as the MSB, and combine it 
-                  with the existing LSB.
-
-                  otherwise, just treat it as a 7 bit value, and set
-                  it directly.
-               */
-
-               cv = (unsigned short) _controller_val[tb->controller_number];
-
-               if (_controller_14bit[tb->controller_number]) {
-                       cv = ((tb->value << 7) | (cv & 0x7f));
-               } else {
-                       cv = tb->value;
-               }
-
-               _controller_val[tb->controller_number] = (controller_value_t)cv;
-
-       } else if ((tb->controller_number >= 32 && 
-                   tb->controller_number <= 63)) {
-                  
-               cv = (unsigned short) _controller_val[tb->controller_number];
-
-               /* LSB for CC 0-31 arrived. 
-
-                  If this is the first time (i.e. its currently
-                  flagged as a 7 bit controller), mark the
-                  controller as 14 bit, adjust the existing value
-                  to be the MSB, and OR-in the new LSB value. 
-
-                  otherwise, OR-in the new low 7bits with the old
-                  high 7.
-               */
-
-               int cn = tb->controller_number - 32;
-                  
-               if (_controller_14bit[cn] == false) {
-                       _controller_14bit[cn] = true;
-                       cv = (cv << 7) | (tb->value & 0x7f);
-               } else {
-                       cv = (cv & 0x3f80) | (tb->value & 0x7f);
-               }
-
-               _controller_val[tb->controller_number] = 
-                       (controller_value_t) cv;
-       } else {
-
-               /* controller can only take 7 bit values */
-               
-               _controller_val[tb->controller_number] = 
-                       (controller_value_t) tb->value;
-       }
-
-       /* bank numbers are special, in that they have their own signal
-        */
-
-       if (tb->controller_number == 0) {
-               _bank_number = (unsigned short) _controller_val[0];
-               if (_port.input()) {
-                       _port.input()->bank_change (*_port.input(), _bank_number);
-                       _port.input()->channel_bank_change[_channel_number] 
-                               (*_port.input(), _bank_number);
-               }
-       }
-
-}
-
-void
-Channel::process_program_change (Parser & /*parser*/, byte val) 
-{
-       _program_number = val;
-}
-
-void
-Channel::process_chanpress (Parser & /*parser*/, byte val) 
-{
-       _chanpress = val;
-}
-
-void
-Channel::process_polypress (Parser & /*parser*/, EventTwoBytes *tb) 
-{
-       _polypress[tb->note_number] = tb->value;
-}
-
-void
-Channel::process_pitchbend (Parser & /*parser*/, pitchbend_t val) 
-{
-       _pitch_bend = val;
-}
-
-void
-Channel::process_reset (Parser & /*parser*/) 
-{
-       reset (0, 1);
-}
-
-/** Write a message to a channel.
- * \return true if success
- */
-bool
-Channel::channel_msg (byte id, byte val1, byte val2, timestamp_t timestamp)
-{
-       unsigned char msg[3];
-       int len = 0;
-
-       msg[0] = id | (_channel_number & 0xf);
-
-       switch (id) {
-       case off:
-               msg[1] = val1 & 0x7F;
-               msg[2] = val2 & 0x7F;
-               len = 3;
-               break;
-
-       case on:
-               msg[1] = val1 & 0x7F;
-               msg[2] = val2 & 0x7F;
-               len = 3;
-               break;
-
-       case MIDI::polypress:
-               msg[1] = val1 & 0x7F;
-               msg[2] = val2 & 0x7F;
-               len = 3;
-               break;
-
-       case controller:
-               msg[1] = val1 & 0x7F;
-               msg[2] = val2 & 0x7F;
-               len = 3;
-               break;
-
-       case MIDI::program:
-               msg[1] = val1 & 0x7F;
-               len = 2;
-               break;
-
-       case MIDI::chanpress:
-               msg[1] = val1 & 0x7F;
-               len = 2;
-               break;
-
-       case MIDI::pitchbend:
-               msg[1] = val1 & 0x7F;
-               msg[2] = val2 & 0x7F;
-               len = 3;
-               break;
-       }
-
-       return _port.midimsg (msg, len, timestamp);
-}
diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc
deleted file mode 100644 (file)
index 1980ac5..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
-    Copyright (C) 1998-99 Paul Barton-Davis 
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include <cassert>
-#include <stdint.h>
-
-#include "pbd/error.h"
-#include "pbd/convert.h"
-
-#include "midi++/types.h"
-#include "midi++/factory.h"
-#include "midi++/fifomidi.h"
-
-#ifdef WITH_JACK_MIDI
-#include "midi++/jack.h"
-
-std::string MIDI::JACK_MidiPort::typestring = "jack";
-#endif // WITH_JACK_MIDI
-
-std::string MIDI::FIFO_MidiPort::typestring = "fifo";
-
-#ifdef WITH_ALSA
-#include "midi++/alsa_sequencer.h"
-#include "midi++/alsa_rawmidi.h"
-
-std::string MIDI::ALSA_SequencerMidiPort::typestring = "alsa/sequencer";
-std::string MIDI::ALSA_RawMidiPort::typestring = "alsa/raw";
-
-#endif // WITH_ALSA
-
-#ifdef WITH_COREMIDI
-#include "midi++/coremidi_midiport.h"
-
-std::string MIDI::CoreMidi_MidiPort::typestring = "coremidi";
-
-#endif // WITH_COREMIDI
-
-using namespace std;
-using namespace MIDI;
-using namespace PBD;
-
-// FIXME: void* data pointer, filthy
-Port *
-PortFactory::create_port (const XMLNode& node, void* data)
-
-{
-       Port::Descriptor desc (node);
-       Port *port;
-       
-       switch (desc.type) {
-#ifdef WITH_JACK_MIDI
-       case Port::JACK_Midi:
-               assert(data != NULL);
-               port = new JACK_MidiPort (node, (jack_client_t*) data);
-               break;
-#endif // WITH_JACK_MIDI
-       
-#ifdef WITH_ALSA
-       case Port::ALSA_RawMidi:
-               port = new ALSA_RawMidiPort (node);
-               break;
-
-       case Port::ALSA_Sequencer:
-               port = new ALSA_SequencerMidiPort (node);
-               break;
-#endif // WITH_ALSA
-
-#if WITH_COREMIDI
-       case Port::CoreMidi_MidiPort:
-               port = new CoreMidi_MidiPort (node);
-               break;
-#endif // WITH_COREMIDI
-
-       case Port::FIFO:
-               port = new FIFO_MidiPort (node);
-               break;
-
-       default:
-               return 0;
-       }
-
-       return port;
-}
-
-bool 
-PortFactory::ignore_duplicate_devices (Port::Type type)
-{
-       bool ret = false;
-
-       switch (type) {
-#ifdef WITH_ALSA
-       case Port::ALSA_Sequencer:
-               ret = true;
-               break;
-#endif // WITH_ALSA
-
-#if WITH_COREMIDI
-       case Port::CoreMidi_MidiPort:
-               ret = true;
-               break;
-#endif // WITH_COREMIDI
-
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-int
-#if defined (WITH_ALSA) || defined (WITH_COREMIDI)
-PortFactory::get_known_ports (vector<PortSet>& ports)
-#else
-PortFactory::get_known_ports (vector<PortSet>&)
-#endif 
-{
-       int n = 0;
-#ifdef WITH_ALSA
-       n += ALSA_SequencerMidiPort::discover (ports);
-#endif // WITH_ALSA
-
-#if WITH_COREMIDI
-       n += CoreMidi_MidiPort::discover (ports);
-#endif // WITH_COREMIDI
-       
-       return n;
-}
-
-std::string
-PortFactory::default_port_type ()
-{
-#ifdef WITH_JACK_MIDI
-       return "jack";
-#endif
-
-#ifdef WITH_ALSA
-       return "alsa/sequencer";
-#endif
-
-#ifdef WITH_COREMIDI
-       return "coremidi";
-#endif // WITH_COREMIDI
-       
-       PBD::fatal << "programming error: no default port type defined in midifactory.cc" << endmsg;
-       /*NOTREACHED*/
-       return "";
-}
-
-Port::Type
-PortFactory::string_to_type (const string& xtype)
-{
-       if (0){ 
-#ifdef WITH_ALSA
-       } else if (strings_equal_ignore_case (xtype, ALSA_RawMidiPort::typestring)) {
-               return Port::ALSA_RawMidi;
-       } else if (strings_equal_ignore_case (xtype, ALSA_SequencerMidiPort::typestring)) {
-               return Port::ALSA_Sequencer;
-#endif 
-#ifdef WITH_COREMIDI
-       } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) {
-               return Port::CoreMidi_MidiPort;
-#endif
-       } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) {
-               return Port::FIFO;
-#ifdef WITH_JACK_MIDI
-       } else if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) {
-               return Port::JACK_Midi;
-#endif
-       }
-
-       return Port::Unknown;
-}
-
-string
-PortFactory::mode_to_string (int mode)
-{
-       if (mode == O_RDONLY) {
-               return "input";
-       } else if (mode == O_WRONLY) {
-               return "output";
-       } 
-
-       return "duplex";
-}
-
-int
-PortFactory::string_to_mode (const string& str)
-{
-       if (strings_equal_ignore_case (str, "output") || strings_equal_ignore_case (str, "out")) {
-               return O_WRONLY;
-       } else if (strings_equal_ignore_case (str, "input") || strings_equal_ignore_case (str, "in")) {
-               return O_RDONLY;
-       }
-
-       return O_RDWR;
-}
diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc
deleted file mode 100644 (file)
index ab03688..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
-    Copyright (C) 1998-99 Paul Barton-Davis 
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include <fcntl.h>
-
-#include <glib.h>
-
-#include "pbd/error.h"
-
-#include "midi++/types.h"
-#include "midi++/manager.h"
-#include "midi++/factory.h"
-#include "midi++/channel.h"
-
-using namespace std;
-using namespace MIDI;
-using namespace PBD;
-
-/* XXX check for strdup leaks */
-
-Manager *Manager::theManager = 0;
-
-Manager::Manager () 
-{
-       inputPort = 0;
-       outputPort = 0;
-       inputChannelNumber = 0;
-       outputChannelNumber = 0;
-       api_data = 0;
-}
-
-Manager::~Manager ()
-{
-       PortMap::iterator i;
-
-       for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               delete (*i).second;
-       }
-
-       ports_by_device.erase (ports_by_device.begin(), ports_by_device.end());
-       ports_by_tag.erase (ports_by_tag.begin(), ports_by_tag.end());
-
-       if (theManager == this) {
-               theManager = 0;
-       }
-}
-
-Port *
-Manager::add_port (const XMLNode& node)
-{
-       Port::Descriptor desc (node);
-       PortFactory factory;
-       Port *port;
-       PortMap::iterator existing;
-       pair<string, Port *> newpair;
-
-       /* do not allow multiple ports with the same tag. if attempted, just return the existing
-          port with the same tag. XXX this is really caused by the mess of setup_midi() being
-          called twice in Ardour, once in the global init() function and once after the user RC file
-          has been loaded (there may be extra ports in it). 
-        */
-
-       if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
-
-               port = (*existing).second;
-               
-               if (port->mode() == desc.mode) {
-                       
-                       /* Same mode - reuse the port, and just
-                          create a new tag entry.
-                       */
-                       
-                       newpair.first = desc.tag;
-                       newpair.second = port;
-                       
-                       ports_by_tag.insert (newpair);
-                       return port;
-               }
-               
-               /* If the existing is duplex, and this request
-                  is not, then fail, because most drivers won't
-                  allow opening twice with duplex and non-duplex
-                  operation.
-               */
-               
-               if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
-                   (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
-                       error << "MIDIManager: port tagged \""
-                             << desc.tag
-                             << "\" cannot be opened duplex and non-duplex"
-                             << endmsg;
-                       return 0;
-               }
-               
-               /* modes must be different or complementary */
-       }
-
-       if (!PortFactory::ignore_duplicate_devices (desc.type)) {
-
-               if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
-                       
-                       port = (*existing).second;
-                       
-                       if (port->mode() == desc.mode) {
-                               
-                               /* Same mode - reuse the port, and just
-                                  create a new tag entry.
-                               */
-                               
-                               newpair.first = desc.tag;
-                               newpair.second = port;
-                               
-                               ports_by_tag.insert (newpair);
-                               return port;
-                       }
-                       
-                       /* If the existing is duplex, and this request
-                          is not, then fail, because most drivers won't
-                          allow opening twice with duplex and non-duplex
-                          operation.
-                       */
-                       
-                       if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
-                           (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
-                               error << "MIDIManager: port tagged \""
-                                     << desc.tag
-                                     << "\" cannot be opened duplex and non-duplex"
-                                     << endmsg;
-                               return 0;
-                       }
-                       
-                       /* modes must be different or complementary */
-               }
-       }
-       
-       port = factory.create_port (node, api_data);
-       
-       if (port == 0) {
-               return 0;
-       }
-
-       if (!port->ok()) {
-               delete port;
-               return 0;
-       }
-
-       newpair.first = port->name();
-       newpair.second = port;
-       ports_by_tag.insert (newpair);
-
-       newpair.first = port->device();
-       newpair.second = port;
-       ports_by_device.insert (newpair);
-
-       /* first port added becomes the default input
-          port.
-       */
-
-       if (inputPort == 0) {
-               inputPort = port;
-       } 
-
-       if (outputPort == 0) {
-               outputPort = port;
-       }
-
-       return port;
-}
-
-int 
-Manager::remove_port (Port* port)
-{
-       PortMap::iterator res;
-
-       for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
-               PortMap::iterator tmp;
-               tmp = res;
-               ++tmp;
-               if (res->second == port) {
-                       ports_by_device.erase (res);
-               } 
-               res = tmp;
-       }
-
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
-               PortMap::iterator tmp;
-               tmp = res;
-               ++tmp;
-               if (res->second == port) {
-                       ports_by_tag.erase (res);
-               } 
-               res = tmp;
-       }
-       
-       delete port;
-
-       return 0;
-}
-
-int
-Manager::set_input_port (string tag)
-{
-       PortMap::iterator res;
-       bool found = false;
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (tag == (*res).first) {
-                       found = true;
-                       break;
-               }
-       }
-       
-       if (!found) {
-               return -1;
-       }
-
-       inputPort = (*res).second;
-
-       return 0;
-}
-
-int
-Manager::set_output_port (string tag)
-
-{
-       PortMap::iterator res;
-       bool found = false;
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (tag == (*res).first) {
-                       found = true;
-                       break;
-               }
-       }
-       
-       if (!found) {
-               return -1;
-       }
-
-       // XXX send a signal to say we're about to change output ports
-
-       if (outputPort) {
-               for (channel_t chan = 0; chan < 16; chan++) {
-                       outputPort->channel (chan)->all_notes_off (0);
-               }
-       }
-       outputPort = (*res).second;
-
-       // XXX send a signal to say we've changed output ports
-
-       return 0;
-}
-
-Port *
-Manager::port (string name)
-{
-       PortMap::iterator res;
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (name == (*res).first) {
-                       return (*res).second;
-               }
-       }
-
-       return 0;
-}
-
-int
-Manager::foreach_port (int (*func)(const Port &, size_t, void *),
-                          void *arg)
-{
-       PortMap::const_iterator i;
-       int retval;
-       int n;
-               
-       for (n = 0, i = ports_by_device.begin(); 
-                   i != ports_by_device.end(); i++, n++) {
-
-               if ((retval = func (*((*i).second), n, arg)) != 0) {
-                       return retval;
-               }
-       }
-
-       return 0;
-}
-
-void
-Manager::cycle_start(nframes_t nframes)
-{
-       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               (*i).second->cycle_start (nframes);
-       }
-}
-
-void
-Manager::cycle_end()
-{
-       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               (*i).second->cycle_end ();
-       }
-}
-
-
-int
-Manager::get_known_ports (vector<PortSet>& ports)
-{
-       return PortFactory::get_known_ports (ports);
-}
diff --git a/libs/midi++2/midiparser.cc b/libs/midi++2/midiparser.cc
deleted file mode 100644 (file)
index 8f416a9..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
-    Copyright (C) 1998 Paul Barton-Davis
-
-    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
-    (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include <cstring>
-#include <cstdlib>
-#include <unistd.h>
-#include <cstring>
-#include <iostream>
-#include <iterator>
-
-#include "midi++/types.h"
-#include "midi++/parser.h"
-#include "midi++/port.h"
-#include "midi++/mmc.h"
-#include "pbd/transmitter.h"
-
-using namespace std;
-using namespace sigc;
-using namespace MIDI;
-
-const char *
-Parser::midi_event_type_name (eventType t)
-
-{
-       switch (t) {
-       case none:
-               return "no midi messages";
-
-       case raw:
-               return "raw midi data";
-
-       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)
-
-{
-       trace_stream = 0;
-       trace_prefix = "";
-       memset (message_counter, 0, sizeof (message_counter[0]) * 256);
-       msgindex = 0;
-       msgtype = none;
-       msglen = 256;
-       msgbuf = (unsigned char *) malloc (msglen);
-       msgbuf[msgindex++] = 0x90;
-       _mmc_forward = false;
-       reset_mtc_state ();
-       _offline = false;
-
-       /* this hack deals with the possibility of our first MIDI
-          bytes being running status messages.
-       */
-
-       channel_msg (0x90);
-       state = NEEDSTATUS;
-
-       pre_variable_state = NEEDSTATUS;
-       pre_variable_msgtype = none;
-}
-
-Parser::~Parser ()
-
-{
-       delete msgbuf;
-}
-
-void
-Parser::trace_event (Parser &, byte *msg, size_t len)
-{
-       eventType type;
-       ostream *o;
-
-       if ((o = trace_stream) == NULL) { /* can be asynchronously removed */
-               return;
-       }
-       
-       type = (eventType) (msg[0]&0xF0);
-
-       switch (type) {
-       case off:
-               *o << trace_prefix
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " NoteOff NoteNum "
-                  << (int) msg[1]
-                  << " Vel "
-                  << (int) msg[2]
-                  << endmsg;
-               break;
-               
-       case on:
-               *o << trace_prefix
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " NoteOn NoteNum "
-                  << (int) msg[1]
-                  << " Vel "
-                  << (int) msg[2]
-                  << endmsg;
-               break;
-           
-       case polypress:
-               *o << trace_prefix
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " PolyPressure"
-                  << (int) msg[1]
-                  << endmsg;
-               break;
-           
-       case MIDI::controller:
-               *o << trace_prefix
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " Controller "
-                  << (int) msg[1]
-                  << " Value "
-                  << (int) msg[2]
-                  << endmsg;
-               break;
-               
-       case program:
-               *o << trace_prefix 
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  <<  " Program Change ProgNum "
-                  << (int) msg[1]
-                  << endmsg;
-               break;
-               
-       case chanpress:
-               *o << trace_prefix 
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " Channel Pressure "
-                  << (int) msg[1]
-                  << endmsg;
-               break;
-           
-       case MIDI::pitchbend:
-               *o << trace_prefix
-                  << "Channel "
-                  << (msg[0]&0xF)+1
-                  << " Pitch Bend "
-                  << ((msg[2]<<7)|msg[1])
-                  << endmsg;
-               break;
-           
-       case MIDI::sysex:
-               if (len == 1) {
-                       switch (msg[0]) {
-                       case 0xf8:
-                               *o << trace_prefix
-                                  << "Clock"
-                                  << endmsg;
-                               break;
-                       case 0xfa:
-                               *o << trace_prefix
-                                  << "Start"
-                                  << endmsg;
-                               break;
-                       case 0xfb:
-                               *o << trace_prefix
-                                  << "Continue"
-                                  << endmsg;
-                               break;
-                       case 0xfc:
-                               *o << trace_prefix
-                                  << "Stop"
-                                  << endmsg;
-                               break;
-                       case 0xfe:
-                               *o << trace_prefix
-                                  << "Active Sense"
-                                  << endmsg;
-                               break;
-                       case 0xff:
-                               *o << trace_prefix
-                                  << "System Reset"
-                                  << endmsg;
-                               break;
-                       default:
-                               *o << trace_prefix
-                                  << "System Exclusive (1 byte : " << hex << (int) *msg << dec << ')'
-                                  << endmsg;           
-                               break;
-                       } 
-               } else {
-                       *o << trace_prefix
-                          << "System Exclusive (" << len << ") = [ " << hex;
-                       for (unsigned int i = 0; i < len; ++i) {
-                               *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;
-       }
-}
-
-void
-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 (mem_fun (*this, &Parser::trace_event));
-       } else {
-               trace_prefix = "";
-               trace_stream = 0;
-       }
-}
-
-void
-Parser::scanner (unsigned char inbyte)
-{
-       bool statusbit;
-
-       // cerr << "parse: " << hex << (int) inbyte << dec << " state = " << state << " msgindex = " << msgindex << " runnable = " << runnable << endl;
-
-       /* 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
-          they can just ask for it specifically. They are so unlike
-          every other MIDI message in terms of semantics that its
-          counter-productive to treat them similarly.
-       */
-       
-       if (inbyte == 0xfe) {
-               message_counter[inbyte]++;
-               if (!_offline) {
-                       active_sense (*this);
-               }
-               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. 
-       */
-
-       bool rtmsg = false;
-       
-       switch (inbyte) {
-       case 0xf8:
-               rtmsg = true;
-               break;
-       case 0xfa:
-               rtmsg = true;
-               break;
-       case 0xfb:
-               rtmsg = true;
-               break;
-       case 0xfc:
-               rtmsg = true;
-               break;
-       case 0xfd:
-               rtmsg = true;
-               break;
-       case 0xfe:
-               rtmsg = true;
-               break;
-       case 0xff:
-               rtmsg = true;
-               break;
-       }
-
-       if (rtmsg) {
-               if (edit (&inbyte, 1) >= 0 && !_offline) {
-                       realtime_msg (inbyte);
-               }
-               
-               return;
-       } 
-
-       statusbit = (inbyte & 0x80);
-
-       /*
-        * Variable length messages (ie. the 'system exclusive')
-        * can be terminated by the next status byte, not necessarily
-        * 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 */
-
-               if (inbyte == MIDI::eox) {
-                       msgbuf[msgindex++] = inbyte;
-               }
-
-#if 0
-               cerr << "SYSEX: " << hex;
-               for (unsigned int i = 0; i < msgindex; ++i) {
-                       cerr << (int) msgbuf[i] << ' ';
-               }
-               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 (!_offline) {
-                               any (*this, msgbuf, msgindex);
-                       }
-               }
-       }
-       
-       /*
-        * Status bytes always start a new message, except EOX
-        */
-       
-       if (statusbit) {
-
-               msgindex = 0;
-
-               if (inbyte == MIDI::eox) {
-                       /* return to the state we had pre-sysex */
-
-                       state = pre_variable_state;
-                       runnable = was_runnable;
-                       msgtype = pre_variable_msgtype;
-
-                       if (state != NEEDSTATUS && runnable) {
-                               msgbuf[msgindex++] = last_status_byte;
-                       }
-               } else {
-                       msgbuf[msgindex++] = inbyte;
-                       if ((inbyte & 0xf0) == 0xf0) {
-                               system_msg (inbyte);
-                               runnable = false;
-                       } else {
-                               channel_msg (inbyte);
-                       }
-               }
-
-               return;
-       }
-       
-       /*
-        * We've got a Data byte.
-        */
-       
-       msgbuf[msgindex++] = inbyte;
-
-       switch (state) {
-       case NEEDSTATUS:
-               /*
-                * We shouldn't get here, since in NEEDSTATUS mode
-                * we're expecting a new status byte, NOT any
-                * data bytes. On the other hand, some equipment
-                * with leaky modwheels and the like might be
-                * sending data bytes as part of running controller
-                * 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) {
-                       
-                       /* 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 
-                          byte" feature.
-                       */
-                       msgindex = 1;
-               } else {
-                       /* If not Runnable, reset to NEEDSTATUS mode */
-                       state = NEEDSTATUS;
-               }
-               break;
-               
-       case VARIABLELENGTH:
-               /* nothing to do */
-               break;
-       }
-       return;
-}
-
-/** Call the real-time function for the specified byte, immediately.
- * These can occur anywhere, so they don't change the state.
- */
-void
-Parser::realtime_msg(unsigned char inbyte)
-
-{
-       message_counter[inbyte]++;
-
-       if (_offline) {
-               return;
-       }
-
-       switch (inbyte) {
-       case 0xf8:
-               timing (*this, _midi_clock_timestamp);
-               break;
-       case 0xfa:
-               start (*this, _midi_clock_timestamp);
-               break;
-       case 0xfb:
-               contineu (*this, _midi_clock_timestamp);
-               break;
-       case 0xfc:
-               stop (*this, _midi_clock_timestamp);
-               break;
-       case 0xfe:
-               /* !!! active sense message in realtime_msg: should not reach here
-                */  
-               break;
-       case 0xff:
-               reset (*this);
-               break;
-       }
-
-       any (*this, &inbyte, 1);
-}
-
-
-/** Interpret a Channel (voice or mode) Message status byte.
- */
-void
-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;
-               state = NEEDTWOBYTES;
-               break;
-       case 0x90:
-               msgtype = on;
-               state = NEEDTWOBYTES;
-               break;
-       case 0xa0:
-               msgtype = polypress;
-               state = NEEDTWOBYTES;
-               break;
-       case 0xb0:
-               msgtype = MIDI::controller;
-               state = NEEDTWOBYTES;
-               break;
-       case 0xc0:
-               msgtype = program;
-               state = NEEDONEBYTE;
-               break;
-       case 0xd0:
-               msgtype = chanpress;
-               state = NEEDONEBYTE;
-               break;
-       case 0xe0:
-               msgtype = MIDI::pitchbend;
-               state = NEEDTWOBYTES;
-               break;
-       }
-}
-
-/** Initialize (and possibly emit) the signals for the
- * specified byte.  Set the state that the state-machine
- * should go into.  If the signal is not emitted
- * immediately, it will be when the state machine gets to
- * the end of the MIDI message.
- */
-void
-Parser::system_msg (unsigned char inbyte)
-{
-       message_counter[inbyte]++;
-
-       switch (inbyte) {
-       case 0xf0:
-               pre_variable_msgtype = msgtype;
-               pre_variable_state = state;
-               was_runnable = runnable;
-               msgtype = MIDI::sysex;
-               state = VARIABLELENGTH;
-               break;
-       case 0xf1:
-               msgtype = MIDI::mtc_quarter;
-               state = NEEDONEBYTE;
-               break;
-       case 0xf2:
-               msgtype = MIDI::position;
-               state = NEEDTWOBYTES;
-               break;
-       case 0xf3:
-               msgtype = MIDI::song;
-               state = NEEDONEBYTE;
-               break;
-       case 0xf6:
-               if (!_offline) {
-                       tune (*this);
-               }
-               state = NEEDSTATUS;
-               break;
-       case 0xf7:
-               break;
-       }
-
-       // all these messages will be sent via any() 
-       // when they are complete.
-       // any (*this, &inbyte, 1);
-}
-
-void 
-Parser::signal (byte *msg, size_t len)
-{
-       channel_t chan = msg[0]&0xF;
-       int chan_i = chan;
-
-       switch (msgtype) {
-       case none:
-               break;
-               
-       case off:
-               channel_active_preparse[chan_i] (*this);
-               note_off (*this, (EventTwoBytes *) &msg[1]);
-               channel_note_off[chan_i] 
-                       (*this, (EventTwoBytes *) &msg[1]);
-               channel_active_postparse[chan_i] (*this);
-               break;
-               
-       case on:
-               channel_active_preparse[chan_i] (*this);
-
-               /* Hack to deal with MIDI sources that use velocity=0
-                  instead of noteOff.
-               */
-
-               if (msg[2] == 0) {
-                       note_off (*this, (EventTwoBytes *) &msg[1]);
-                       channel_note_off[chan_i] 
-                               (*this, (EventTwoBytes *) &msg[1]);
-               } else {
-                       note_on (*this, (EventTwoBytes *) &msg[1]);
-                       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] 
-                       (*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] 
-                       (*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;
-
-       case MIDI::mtc_quarter:
-               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)
-{
-       if (!MachineControl::is_mmc (msg, msglen)) {
-               return false;
-       }
-
-       /* hand over the just the interior MMC part of
-          the sysex msg without the leading 0xF0
-       */
-
-       if (!_offline) {
-               mmc (*this, &msg[1], msglen - 1);
-       }
-
-       return true;
-}
-
-void
-Parser::set_offline (bool yn)
-{
-       if (_offline != yn) {
-               _offline = yn;
-               OfflineStatusChanged ();
-
-               /* this hack deals with the possibility of our first MIDI
-                  bytes being running status messages.
-               */
-               
-               channel_msg (0x90);
-               state = NEEDSTATUS;
-       }
-}
-
diff --git a/libs/midi++2/midiport.cc b/libs/midi++2/midiport.cc
deleted file mode 100644 (file)
index b7ffcc7..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
-    Copyright (C) 1998 Paul Barton-Davis
-    
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-#include <iostream>
-#include <cstdio>
-#include <fcntl.h>
-#include <errno.h>
-
-#include "pbd/xml++.h"
-#include "pbd/error.h"
-#include "pbd/failed_constructor.h"
-
-#include "midi++/types.h"
-#include "midi++/port.h"
-#include "midi++/channel.h"
-#include "midi++/factory.h"
-
-using namespace MIDI;
-using namespace std;
-using namespace PBD;
-
-size_t Port::nports = 0;
-
-Port::Port (const XMLNode& node)
-       : _currently_in_cycle(false)
-       , _nframes_this_cycle(0)
-{
-       Descriptor desc (node);
-
-       _ok = false;  /* derived class must set to true if constructor
-                        succeeds.
-                     */
-
-       bytes_written = 0;
-       bytes_read = 0;
-       input_parser = 0;
-       output_parser = 0;
-       slowdown = 0;
-
-       _devname = desc.device;
-       _tagname = desc.tag;
-       _mode = desc.mode;
-
-       if (_mode == O_RDONLY || _mode == O_RDWR) {
-               input_parser = new Parser (*this);
-       } else {
-               input_parser = 0;
-       }
-
-       if (_mode == O_WRONLY || _mode == O_RDWR) {
-               output_parser = new Parser (*this);
-       } else {
-               output_parser = 0;
-       }
-
-       for (int i = 0; i < 16; i++) {
-               _channel[i] =  new Channel (i, *this);
-
-               if (input_parser) {
-                       _channel[i]->connect_input_signals ();
-               }
-
-               if (output_parser) {
-                       _channel[i]->connect_output_signals ();
-               }
-       }
-}
-
-
-Port::~Port ()
-{
-       for (int i = 0; i < 16; i++) {
-               delete _channel[i];
-       }
-}
-
-void
-Port::parse ()
-{
-       byte buf[512];
-
-       /* parsing is done (if at all) by initiating a read from 
-          the port.
-       */
-
-       while (1) {
-               
-               // cerr << "+++ READ ON " << name() << endl;
-
-               int nread = read (buf, sizeof (buf));
-
-               // cerr << "-- READ (" << nread << " ON " << name() << endl;
-               
-               if (nread > 0) {
-                       if ((size_t) nread < sizeof (buf)) {
-                               break;
-                       } else {
-                               continue;
-                       }
-               } else if (nread == 0) {
-                       break;
-               } else if (errno == EAGAIN) {
-                       break;
-               } else {
-                       fatal << "Error reading from MIDI port " << name() << endmsg;
-                       /*NOTREACHED*/
-               }
-       }
-}
-
-/** Send a clock tick message.
- * \return true on success.
- */
-bool
-Port::clock (timestamp_t timestamp)
-{
-       static byte clockmsg = 0xf8;
-       
-       if (_mode != O_RDONLY) {
-               return midimsg (&clockmsg, 1, timestamp);
-       }
-       
-       return false;
-}
-
-void
-Port::cycle_start (nframes_t nframes)
-{
-       _currently_in_cycle = true;
-       _nframes_this_cycle = nframes;
-}
-
-void
-Port::cycle_end ()
-{
-       _currently_in_cycle = false;
-       _nframes_this_cycle = 0;
-}
-
-XMLNode&
-Port::get_state () const
-{
-       XMLNode* node = new XMLNode ("MIDI-port");
-       node->add_property ("tag", _tagname);
-       node->add_property ("device", _devname);
-       node->add_property ("mode", PortFactory::mode_to_string (_mode));
-       node->add_property ("type", get_typestring());
-
-       return *node;
-}
-
-void
-Port::set_state (const XMLNode& /*node*/)
-{
-       // relax
-}
-
-void
-Port::gtk_read_callback (void *ptr, int /*fd*/, int /*cond*/)
-{
-       byte buf[64];
-       ((Port *)ptr)->read (buf, sizeof (buf));
-}
-
-void
-Port::write_callback (byte *msg, unsigned int len, void *ptr)
-{
-       ((Port *)ptr)->write (msg, len, 0);
-}
-
-std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
-{
-       using namespace std;
-       os << "MIDI::Port { ";
-       os << "device: " << port.device();
-       os << "; ";
-       os << "name: " << port.name();
-       os << "; ";
-       os << "type: " << port.type();
-       os << "; ";
-       os << "mode: " << port.mode();
-       os << "; ";
-       os << "ok: " << port.ok();
-       os << "; ";
-       os << " }";
-       return os;
-}
-
-Port::Descriptor::Descriptor (const XMLNode& node)
-{
-       const XMLProperty *prop;
-       bool have_tag = false;
-       bool have_device = false;
-       bool have_type = false;
-       bool have_mode = false;
-
-       if ((prop = node.property ("tag")) != 0) {
-               tag = prop->value();
-               have_tag = true;
-       }
-
-       if ((prop = node.property ("device")) != 0) {
-               device = prop->value();
-               have_device = true;
-       }
-
-       if ((prop = node.property ("type")) != 0) {
-               type = PortFactory::string_to_type (prop->value());
-               have_type = true;
-       }
-
-       if ((prop = node.property ("mode")) != 0) {
-               mode = PortFactory::string_to_mode (prop->value());
-               have_mode = true;
-       }
-
-       if (!have_tag || !have_device || !have_type || !have_mode) {
-               throw failed_constructor();
-       }
-}
-
diff --git a/libs/midi++2/parser.cc b/libs/midi++2/parser.cc
new file mode 100644 (file)
index 0000000..8f416a9
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+    Copyright (C) 1998 Paul Barton-Davis
+
+    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
+    (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <cstring>
+#include <cstdlib>
+#include <unistd.h>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+
+#include "midi++/types.h"
+#include "midi++/parser.h"
+#include "midi++/port.h"
+#include "midi++/mmc.h"
+#include "pbd/transmitter.h"
+
+using namespace std;
+using namespace sigc;
+using namespace MIDI;
+
+const char *
+Parser::midi_event_type_name (eventType t)
+
+{
+       switch (t) {
+       case none:
+               return "no midi messages";
+
+       case raw:
+               return "raw midi data";
+
+       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)
+
+{
+       trace_stream = 0;
+       trace_prefix = "";
+       memset (message_counter, 0, sizeof (message_counter[0]) * 256);
+       msgindex = 0;
+       msgtype = none;
+       msglen = 256;
+       msgbuf = (unsigned char *) malloc (msglen);
+       msgbuf[msgindex++] = 0x90;
+       _mmc_forward = false;
+       reset_mtc_state ();
+       _offline = false;
+
+       /* this hack deals with the possibility of our first MIDI
+          bytes being running status messages.
+       */
+
+       channel_msg (0x90);
+       state = NEEDSTATUS;
+
+       pre_variable_state = NEEDSTATUS;
+       pre_variable_msgtype = none;
+}
+
+Parser::~Parser ()
+
+{
+       delete msgbuf;
+}
+
+void
+Parser::trace_event (Parser &, byte *msg, size_t len)
+{
+       eventType type;
+       ostream *o;
+
+       if ((o = trace_stream) == NULL) { /* can be asynchronously removed */
+               return;
+       }
+       
+       type = (eventType) (msg[0]&0xF0);
+
+       switch (type) {
+       case off:
+               *o << trace_prefix
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " NoteOff NoteNum "
+                  << (int) msg[1]
+                  << " Vel "
+                  << (int) msg[2]
+                  << endmsg;
+               break;
+               
+       case on:
+               *o << trace_prefix
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " NoteOn NoteNum "
+                  << (int) msg[1]
+                  << " Vel "
+                  << (int) msg[2]
+                  << endmsg;
+               break;
+           
+       case polypress:
+               *o << trace_prefix
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " PolyPressure"
+                  << (int) msg[1]
+                  << endmsg;
+               break;
+           
+       case MIDI::controller:
+               *o << trace_prefix
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " Controller "
+                  << (int) msg[1]
+                  << " Value "
+                  << (int) msg[2]
+                  << endmsg;
+               break;
+               
+       case program:
+               *o << trace_prefix 
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  <<  " Program Change ProgNum "
+                  << (int) msg[1]
+                  << endmsg;
+               break;
+               
+       case chanpress:
+               *o << trace_prefix 
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " Channel Pressure "
+                  << (int) msg[1]
+                  << endmsg;
+               break;
+           
+       case MIDI::pitchbend:
+               *o << trace_prefix
+                  << "Channel "
+                  << (msg[0]&0xF)+1
+                  << " Pitch Bend "
+                  << ((msg[2]<<7)|msg[1])
+                  << endmsg;
+               break;
+           
+       case MIDI::sysex:
+               if (len == 1) {
+                       switch (msg[0]) {
+                       case 0xf8:
+                               *o << trace_prefix
+                                  << "Clock"
+                                  << endmsg;
+                               break;
+                       case 0xfa:
+                               *o << trace_prefix
+                                  << "Start"
+                                  << endmsg;
+                               break;
+                       case 0xfb:
+                               *o << trace_prefix
+                                  << "Continue"
+                                  << endmsg;
+                               break;
+                       case 0xfc:
+                               *o << trace_prefix
+                                  << "Stop"
+                                  << endmsg;
+                               break;
+                       case 0xfe:
+                               *o << trace_prefix
+                                  << "Active Sense"
+                                  << endmsg;
+                               break;
+                       case 0xff:
+                               *o << trace_prefix
+                                  << "System Reset"
+                                  << endmsg;
+                               break;
+                       default:
+                               *o << trace_prefix
+                                  << "System Exclusive (1 byte : " << hex << (int) *msg << dec << ')'
+                                  << endmsg;           
+                               break;
+                       } 
+               } else {
+                       *o << trace_prefix
+                          << "System Exclusive (" << len << ") = [ " << hex;
+                       for (unsigned int i = 0; i < len; ++i) {
+                               *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;
+       }
+}
+
+void
+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 (mem_fun (*this, &Parser::trace_event));
+       } else {
+               trace_prefix = "";
+               trace_stream = 0;
+       }
+}
+
+void
+Parser::scanner (unsigned char inbyte)
+{
+       bool statusbit;
+
+       // cerr << "parse: " << hex << (int) inbyte << dec << " state = " << state << " msgindex = " << msgindex << " runnable = " << runnable << endl;
+
+       /* 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
+          they can just ask for it specifically. They are so unlike
+          every other MIDI message in terms of semantics that its
+          counter-productive to treat them similarly.
+       */
+       
+       if (inbyte == 0xfe) {
+               message_counter[inbyte]++;
+               if (!_offline) {
+                       active_sense (*this);
+               }
+               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. 
+       */
+
+       bool rtmsg = false;
+       
+       switch (inbyte) {
+       case 0xf8:
+               rtmsg = true;
+               break;
+       case 0xfa:
+               rtmsg = true;
+               break;
+       case 0xfb:
+               rtmsg = true;
+               break;
+       case 0xfc:
+               rtmsg = true;
+               break;
+       case 0xfd:
+               rtmsg = true;
+               break;
+       case 0xfe:
+               rtmsg = true;
+               break;
+       case 0xff:
+               rtmsg = true;
+               break;
+       }
+
+       if (rtmsg) {
+               if (edit (&inbyte, 1) >= 0 && !_offline) {
+                       realtime_msg (inbyte);
+               }
+               
+               return;
+       } 
+
+       statusbit = (inbyte & 0x80);
+
+       /*
+        * Variable length messages (ie. the 'system exclusive')
+        * can be terminated by the next status byte, not necessarily
+        * 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 */
+
+               if (inbyte == MIDI::eox) {
+                       msgbuf[msgindex++] = inbyte;
+               }
+
+#if 0
+               cerr << "SYSEX: " << hex;
+               for (unsigned int i = 0; i < msgindex; ++i) {
+                       cerr << (int) msgbuf[i] << ' ';
+               }
+               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 (!_offline) {
+                               any (*this, msgbuf, msgindex);
+                       }
+               }
+       }
+       
+       /*
+        * Status bytes always start a new message, except EOX
+        */
+       
+       if (statusbit) {
+
+               msgindex = 0;
+
+               if (inbyte == MIDI::eox) {
+                       /* return to the state we had pre-sysex */
+
+                       state = pre_variable_state;
+                       runnable = was_runnable;
+                       msgtype = pre_variable_msgtype;
+
+                       if (state != NEEDSTATUS && runnable) {
+                               msgbuf[msgindex++] = last_status_byte;
+                       }
+               } else {
+                       msgbuf[msgindex++] = inbyte;
+                       if ((inbyte & 0xf0) == 0xf0) {
+                               system_msg (inbyte);
+                               runnable = false;
+                       } else {
+                               channel_msg (inbyte);
+                       }
+               }
+
+               return;
+       }
+       
+       /*
+        * We've got a Data byte.
+        */
+       
+       msgbuf[msgindex++] = inbyte;
+
+       switch (state) {
+       case NEEDSTATUS:
+               /*
+                * We shouldn't get here, since in NEEDSTATUS mode
+                * we're expecting a new status byte, NOT any
+                * data bytes. On the other hand, some equipment
+                * with leaky modwheels and the like might be
+                * sending data bytes as part of running controller
+                * 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) {
+                       
+                       /* 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 
+                          byte" feature.
+                       */
+                       msgindex = 1;
+               } else {
+                       /* If not Runnable, reset to NEEDSTATUS mode */
+                       state = NEEDSTATUS;
+               }
+               break;
+               
+       case VARIABLELENGTH:
+               /* nothing to do */
+               break;
+       }
+       return;
+}
+
+/** Call the real-time function for the specified byte, immediately.
+ * These can occur anywhere, so they don't change the state.
+ */
+void
+Parser::realtime_msg(unsigned char inbyte)
+
+{
+       message_counter[inbyte]++;
+
+       if (_offline) {
+               return;
+       }
+
+       switch (inbyte) {
+       case 0xf8:
+               timing (*this, _midi_clock_timestamp);
+               break;
+       case 0xfa:
+               start (*this, _midi_clock_timestamp);
+               break;
+       case 0xfb:
+               contineu (*this, _midi_clock_timestamp);
+               break;
+       case 0xfc:
+               stop (*this, _midi_clock_timestamp);
+               break;
+       case 0xfe:
+               /* !!! active sense message in realtime_msg: should not reach here
+                */  
+               break;
+       case 0xff:
+               reset (*this);
+               break;
+       }
+
+       any (*this, &inbyte, 1);
+}
+
+
+/** Interpret a Channel (voice or mode) Message status byte.
+ */
+void
+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;
+               state = NEEDTWOBYTES;
+               break;
+       case 0x90:
+               msgtype = on;
+               state = NEEDTWOBYTES;
+               break;
+       case 0xa0:
+               msgtype = polypress;
+               state = NEEDTWOBYTES;
+               break;
+       case 0xb0:
+               msgtype = MIDI::controller;
+               state = NEEDTWOBYTES;
+               break;
+       case 0xc0:
+               msgtype = program;
+               state = NEEDONEBYTE;
+               break;
+       case 0xd0:
+               msgtype = chanpress;
+               state = NEEDONEBYTE;
+               break;
+       case 0xe0:
+               msgtype = MIDI::pitchbend;
+               state = NEEDTWOBYTES;
+               break;
+       }
+}
+
+/** Initialize (and possibly emit) the signals for the
+ * specified byte.  Set the state that the state-machine
+ * should go into.  If the signal is not emitted
+ * immediately, it will be when the state machine gets to
+ * the end of the MIDI message.
+ */
+void
+Parser::system_msg (unsigned char inbyte)
+{
+       message_counter[inbyte]++;
+
+       switch (inbyte) {
+       case 0xf0:
+               pre_variable_msgtype = msgtype;
+               pre_variable_state = state;
+               was_runnable = runnable;
+               msgtype = MIDI::sysex;
+               state = VARIABLELENGTH;
+               break;
+       case 0xf1:
+               msgtype = MIDI::mtc_quarter;
+               state = NEEDONEBYTE;
+               break;
+       case 0xf2:
+               msgtype = MIDI::position;
+               state = NEEDTWOBYTES;
+               break;
+       case 0xf3:
+               msgtype = MIDI::song;
+               state = NEEDONEBYTE;
+               break;
+       case 0xf6:
+               if (!_offline) {
+                       tune (*this);
+               }
+               state = NEEDSTATUS;
+               break;
+       case 0xf7:
+               break;
+       }
+
+       // all these messages will be sent via any() 
+       // when they are complete.
+       // any (*this, &inbyte, 1);
+}
+
+void 
+Parser::signal (byte *msg, size_t len)
+{
+       channel_t chan = msg[0]&0xF;
+       int chan_i = chan;
+
+       switch (msgtype) {
+       case none:
+               break;
+               
+       case off:
+               channel_active_preparse[chan_i] (*this);
+               note_off (*this, (EventTwoBytes *) &msg[1]);
+               channel_note_off[chan_i] 
+                       (*this, (EventTwoBytes *) &msg[1]);
+               channel_active_postparse[chan_i] (*this);
+               break;
+               
+       case on:
+               channel_active_preparse[chan_i] (*this);
+
+               /* Hack to deal with MIDI sources that use velocity=0
+                  instead of noteOff.
+               */
+
+               if (msg[2] == 0) {
+                       note_off (*this, (EventTwoBytes *) &msg[1]);
+                       channel_note_off[chan_i] 
+                               (*this, (EventTwoBytes *) &msg[1]);
+               } else {
+                       note_on (*this, (EventTwoBytes *) &msg[1]);
+                       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] 
+                       (*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] 
+                       (*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;
+
+       case MIDI::mtc_quarter:
+               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)
+{
+       if (!MachineControl::is_mmc (msg, msglen)) {
+               return false;
+       }
+
+       /* hand over the just the interior MMC part of
+          the sysex msg without the leading 0xF0
+       */
+
+       if (!_offline) {
+               mmc (*this, &msg[1], msglen - 1);
+       }
+
+       return true;
+}
+
+void
+Parser::set_offline (bool yn)
+{
+       if (_offline != yn) {
+               _offline = yn;
+               OfflineStatusChanged ();
+
+               /* this hack deals with the possibility of our first MIDI
+                  bytes being running status messages.
+               */
+               
+               channel_msg (0x90);
+               state = NEEDSTATUS;
+       }
+}
+
diff --git a/libs/midi++2/port.cc b/libs/midi++2/port.cc
new file mode 100644 (file)
index 0000000..b7ffcc7
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+    Copyright (C) 1998 Paul Barton-Davis
+    
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+#include <iostream>
+#include <cstdio>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "pbd/xml++.h"
+#include "pbd/error.h"
+#include "pbd/failed_constructor.h"
+
+#include "midi++/types.h"
+#include "midi++/port.h"
+#include "midi++/channel.h"
+#include "midi++/factory.h"
+
+using namespace MIDI;
+using namespace std;
+using namespace PBD;
+
+size_t Port::nports = 0;
+
+Port::Port (const XMLNode& node)
+       : _currently_in_cycle(false)
+       , _nframes_this_cycle(0)
+{
+       Descriptor desc (node);
+
+       _ok = false;  /* derived class must set to true if constructor
+                        succeeds.
+                     */
+
+       bytes_written = 0;
+       bytes_read = 0;
+       input_parser = 0;
+       output_parser = 0;
+       slowdown = 0;
+
+       _devname = desc.device;
+       _tagname = desc.tag;
+       _mode = desc.mode;
+
+       if (_mode == O_RDONLY || _mode == O_RDWR) {
+               input_parser = new Parser (*this);
+       } else {
+               input_parser = 0;
+       }
+
+       if (_mode == O_WRONLY || _mode == O_RDWR) {
+               output_parser = new Parser (*this);
+       } else {
+               output_parser = 0;
+       }
+
+       for (int i = 0; i < 16; i++) {
+               _channel[i] =  new Channel (i, *this);
+
+               if (input_parser) {
+                       _channel[i]->connect_input_signals ();
+               }
+
+               if (output_parser) {
+                       _channel[i]->connect_output_signals ();
+               }
+       }
+}
+
+
+Port::~Port ()
+{
+       for (int i = 0; i < 16; i++) {
+               delete _channel[i];
+       }
+}
+
+void
+Port::parse ()
+{
+       byte buf[512];
+
+       /* parsing is done (if at all) by initiating a read from 
+          the port.
+       */
+
+       while (1) {
+               
+               // cerr << "+++ READ ON " << name() << endl;
+
+               int nread = read (buf, sizeof (buf));
+
+               // cerr << "-- READ (" << nread << " ON " << name() << endl;
+               
+               if (nread > 0) {
+                       if ((size_t) nread < sizeof (buf)) {
+                               break;
+                       } else {
+                               continue;
+                       }
+               } else if (nread == 0) {
+                       break;
+               } else if (errno == EAGAIN) {
+                       break;
+               } else {
+                       fatal << "Error reading from MIDI port " << name() << endmsg;
+                       /*NOTREACHED*/
+               }
+       }
+}
+
+/** Send a clock tick message.
+ * \return true on success.
+ */
+bool
+Port::clock (timestamp_t timestamp)
+{
+       static byte clockmsg = 0xf8;
+       
+       if (_mode != O_RDONLY) {
+               return midimsg (&clockmsg, 1, timestamp);
+       }
+       
+       return false;
+}
+
+void
+Port::cycle_start (nframes_t nframes)
+{
+       _currently_in_cycle = true;
+       _nframes_this_cycle = nframes;
+}
+
+void
+Port::cycle_end ()
+{
+       _currently_in_cycle = false;
+       _nframes_this_cycle = 0;
+}
+
+XMLNode&
+Port::get_state () const
+{
+       XMLNode* node = new XMLNode ("MIDI-port");
+       node->add_property ("tag", _tagname);
+       node->add_property ("device", _devname);
+       node->add_property ("mode", PortFactory::mode_to_string (_mode));
+       node->add_property ("type", get_typestring());
+
+       return *node;
+}
+
+void
+Port::set_state (const XMLNode& /*node*/)
+{
+       // relax
+}
+
+void
+Port::gtk_read_callback (void *ptr, int /*fd*/, int /*cond*/)
+{
+       byte buf[64];
+       ((Port *)ptr)->read (buf, sizeof (buf));
+}
+
+void
+Port::write_callback (byte *msg, unsigned int len, void *ptr)
+{
+       ((Port *)ptr)->write (msg, len, 0);
+}
+
+std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
+{
+       using namespace std;
+       os << "MIDI::Port { ";
+       os << "device: " << port.device();
+       os << "; ";
+       os << "name: " << port.name();
+       os << "; ";
+       os << "type: " << port.type();
+       os << "; ";
+       os << "mode: " << port.mode();
+       os << "; ";
+       os << "ok: " << port.ok();
+       os << "; ";
+       os << " }";
+       return os;
+}
+
+Port::Descriptor::Descriptor (const XMLNode& node)
+{
+       const XMLProperty *prop;
+       bool have_tag = false;
+       bool have_device = false;
+       bool have_type = false;
+       bool have_mode = false;
+
+       if ((prop = node.property ("tag")) != 0) {
+               tag = prop->value();
+               have_tag = true;
+       }
+
+       if ((prop = node.property ("device")) != 0) {
+               device = prop->value();
+               have_device = true;
+       }
+
+       if ((prop = node.property ("type")) != 0) {
+               type = PortFactory::string_to_type (prop->value());
+               have_type = true;
+       }
+
+       if ((prop = node.property ("mode")) != 0) {
+               mode = PortFactory::string_to_mode (prop->value());
+               have_mode = true;
+       }
+
+       if (!have_tag || !have_device || !have_type || !have_mode) {
+               throw failed_constructor();
+       }
+}
+
index 9d25ac9930c3d683db84424fe0b97742dc4d8069..14974581a9ca269be1cfbb780665e26edc2e168e 100644 (file)
@@ -51,11 +51,11 @@ def build(bld):
                fd_midiport.cc
                fifomidi.cc
                midi.cc
                fd_midiport.cc
                fifomidi.cc
                midi.cc
-               midichannel.cc
-               midifactory.cc
-               midimanager.cc
-               midiparser.cc
-               midiport.cc
+               channel.cc
+               factory.cc
+               manager.cc
+               parser.cc
+               port.cc
                midnam_patch.cc
                mmc.cc
                mtc.cc
                midnam_patch.cc
                mmc.cc
                mtc.cc