merge with master, primarily for adrian's maximise-mixer change
[ardour.git] / libs / midi++2 / mmc.cc
index 28d6393fb453c154c0bc5707a3a3a9af24c19479..b92e686ce6b753bca71bea99b2b2be0b5fa70c98 100644 (file)
     $Id$
 */
 
+#include <fcntl.h>
 #include <map>
 
-#include <pbd/error.h>
-#include <midi++/mmc.h>
-#include <midi++/port.h>
-#include <midi++/parser.h>
+#include "timecode/time.h"
+#include "timecode/bbt_time.h"
+
+#include "pbd/error.h"
+
+#include "midi++/mmc.h"
+#include "midi++/port.h"
+#include "midi++/parser.h"
+
+#ifndef __INT_MAX__   // 'ssize_t' won't be defined yet
+typedef long ssize_t;
+#endif
 
 using namespace std;
 using namespace MIDI;
 using namespace PBD;
 
+/**
+ * As libtimecode is linked statically to libmidi++ this
+ * is necessary to pull in all the symbols from libtimecode
+ * so they are exported for other users of libtimecode.
+ */
+double tmp = Timecode::BBT_Time::ticks_per_beat;
+
 static std::map<int,string> mmc_cmd_map;
 static void build_mmc_cmd_map ()
 {
@@ -191,38 +207,42 @@ static void build_mmc_cmd_map ()
        mmc_cmd_map.insert (newpair);
 }
 
+MachineControl::MachineControl ()
+{
+       build_mmc_cmd_map ();
 
-MachineControl::MachineControl (Port &p, float version,
-                               CommandSignature &csig,
-                               ResponseSignature &rsig)
+       _receive_device_id = 0x7f;
+       _send_device_id = 0x7f;
+}
 
-       : _port (p)
+void
+MachineControl::set_ports (MIDI::Port* ip, MIDI::Port* op)
 {
-       Parser *parser;
-       
-       build_mmc_cmd_map ();
+       port_connections.drop_connections ();
 
-       _device_id = 0;
-       
-       if ((parser = _port.input()) != 0) {
-               parser->mmc.connect 
-                       (mem_fun (*this, &MachineControl::process_mmc_message));
-       } else {
-               warning << "MMC connected to a non-input port: useless!"
-                       << endmsg;
-       }
+       _input_port = ip;
+       _output_port = op;
+
+       _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
+       _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
+       _input_port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_continue, this));
+       _input_port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_stop, this));
 }
 
 void
-MachineControl::set_device_id (byte id)
+MachineControl::set_receive_device_id (MIDI::byte id)
+{
+       _receive_device_id = id & 0x7f;
+}
 
+void
+MachineControl::set_send_device_id (MIDI::byte id)
 {
-       _device_id = id & 0x7f;
+       _send_device_id = id & 0x7f;
 }
 
 bool
-MachineControl::is_mmc (byte *sysex_buf, size_t len)
-
+MachineControl::is_mmc (MIDI::byte *sysex_buf, size_t len)
 {
        if (len < 4 || len > 48) {
                return false;
@@ -241,8 +261,7 @@ MachineControl::is_mmc (byte *sysex_buf, size_t len)
 }
 
 void
-MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len)
-
+MachineControl::process_mmc_message (Parser &, MIDI::byte *msg, size_t len)
 {
        size_t skiplen;
        byte *mmc_msg;
@@ -258,14 +277,14 @@ MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len)
        */
 
 #if 0
-       cerr << "*** me = " << (int) _device_id << " MMC message: len = " << len << "\n\t";
+       cerr << "*** me = " << (int) _receive_device_id << " MMC message: len = " << len << "\n\t";
        for (size_t i = 0; i < len; i++) {
                cerr << hex << (int) msg[i] << dec << ' ';
        }
        cerr << endl;
 #endif
 
-       if (msg[1] != 0x7f && msg[1] != _device_id) {
+       if (msg[1] != 0x7f && msg[1] != _receive_device_id) {
                return;
        }
 
@@ -449,8 +468,7 @@ MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len)
 }              
 
 int
-MachineControl::do_masked_write (byte *msg, size_t len)
-
+MachineControl::do_masked_write (MIDI::byte *msg, size_t len)
 {
        /* return the number of bytes "consumed" */
 
@@ -458,7 +476,11 @@ MachineControl::do_masked_write (byte *msg, size_t len)
        
        switch (msg[2]) {
        case 0x4f:  /* Track Record Ready Status */
-               write_track_record_ready (&msg[3], len - 3);
+               write_track_status (&msg[3], len - 3, msg[2]);
+               break;
+
+       case 0x62: /* track mute */
+               write_track_status (&msg[3], len - 3, msg[2]);
                break;
 
        default:
@@ -472,8 +494,7 @@ MachineControl::do_masked_write (byte *msg, size_t len)
 }
 
 void
-MachineControl::write_track_record_ready (byte *msg, size_t len)
-
+MachineControl::write_track_status (MIDI::byte *msg, size_t /*len*/, MIDI::byte reg)
 {
        size_t n;
        ssize_t base_track;
@@ -543,14 +564,18 @@ MachineControl::write_track_record_ready (byte *msg, size_t len)
                           bit set.
                        */
 
-                       if (msg[2] & (1<<n)) {
-                               trackRecordStatus[base_track+n] = true;
-                               TrackRecordStatusChange (*this, base_track+n,
-                                                        true);
-                       } else {
-                               trackRecordStatus[base_track+n] = false;
-                               TrackRecordStatusChange (*this, base_track+n,
-                                                        false);
+                       bool val = (msg[2] & (1<<n));
+                       
+                       switch (reg) {
+                       case 0x4f:
+                               trackRecordStatus[base_track+n] = val;
+                               TrackRecordStatusChange (*this, base_track+n, val);
+                               break;
+                               
+                       case 0x62:
+                               trackMute[base_track+n] = val;
+                               TrackMuteChange (*this, base_track+n, val);
+                               break;
                        }
                } 
 
@@ -558,8 +583,7 @@ MachineControl::write_track_record_ready (byte *msg, size_t len)
 }
 
 int
-MachineControl::do_locate (byte *msg, size_t msglen)
-
+MachineControl::do_locate (MIDI::byte *msg, size_t /*msglen*/)
 {
        if (msg[2] == 0) {
                warning << "MIDI::MMC: locate [I/F] command not supported"
@@ -574,7 +598,7 @@ MachineControl::do_locate (byte *msg, size_t msglen)
 }
 
 int
-MachineControl::do_step (byte *msg, size_t msglen)
+MachineControl::do_step (MIDI::byte *msg, size_t /*msglen*/)
 {
        int steps = msg[2] & 0x3f;
 
@@ -587,8 +611,7 @@ MachineControl::do_step (byte *msg, size_t msglen)
 }
 
 int
-MachineControl::do_shuttle (byte *msg, size_t msglen)
-
+MachineControl::do_shuttle (MIDI::byte *msg, size_t /*msglen*/)
 {
        size_t forward;
        byte sh = msg[2];
@@ -618,3 +641,84 @@ MachineControl::do_shuttle (byte *msg, size_t msglen)
        return 0;
 }
 
+void
+MachineControl::enable_send (bool yn)
+{
+       _enable_send = yn;
+}
+
+/** Send a MMC command to a the MMC port.
+ *  @param c command.
+ */
+void
+MachineControl::send (MachineControlCommand const & c)
+{
+       if (_output_port == 0 || !_enable_send) {
+               // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
+               return;
+       }
+
+       MIDI::byte buffer[32];
+       MIDI::byte* b = c.fill_buffer (this, buffer);
+
+       if (_output_port->midimsg (buffer, b - buffer, 0)) {
+               error << "MMC: cannot send command" << endmsg;
+       }
+}
+
+void
+MachineControl::spp_start ()
+{
+       SPPStart (); /* EMIT SIGNAL */
+}
+
+void
+MachineControl::spp_continue ()
+{
+       SPPContinue (); /* EMIT SIGNAL */
+}
+
+void
+MachineControl::spp_stop ()
+{
+       SPPStop (); /* EMIT SIGNAL */
+}
+
+MachineControlCommand::MachineControlCommand (MachineControl::Command c)
+       : _command (c)
+{
+
+}
+
+MachineControlCommand::MachineControlCommand (Timecode::Time t)
+       : _command (MachineControl::cmdLocate)
+       , _time (t)
+{
+
+}
+
+MIDI::byte * 
+MachineControlCommand::fill_buffer (MachineControl* mmc, MIDI::byte* b) const
+{
+       *b++ = 0xf0; // SysEx
+       *b++ = 0x7f; // Real-time SysEx ID for MMC
+       *b++ = mmc->send_device_id();
+       *b++ = 0x6; // MMC command
+
+       *b++ = _command;
+
+       if (_command == MachineControl::cmdLocate) {
+               *b++ = 0x6; // byte count
+               *b++ = 0x1; // "TARGET" subcommand
+               *b++ = _time.hours;
+               *b++ = _time.minutes;
+               *b++ = _time.seconds;
+               *b++ = _time.frames;
+               *b++ = _time.subframes;
+       }
+
+       *b++ = 0xf7;
+
+       return b;
+}
+