summaryrefslogtreecommitdiff
path: root/libs/midi++2/mmc.cc
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-06-29 13:47:53 +0000
committerCarl Hetherington <carl@carlh.net>2010-06-29 13:47:53 +0000
commit9469d6b26acb0a6c79cd96058760081cc9bfa7fb (patch)
treef1939b23b9c279350279ae240e4a8d5b765f7dc7 /libs/midi++2/mmc.cc
parentb47524ded2af50bda96dc9d2dcf5f56cd7e94092 (diff)
Clean up MMC transmission a bit, and make sure that it is all done from one thread.
git-svn-id: svn://localhost/ardour2/branches/3.0@7324 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/midi++2/mmc.cc')
-rw-r--r--libs/midi++2/mmc.cc131
1 files changed, 112 insertions, 19 deletions
diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc
index 6030230108..b8aa253f80 100644
--- a/libs/midi++2/mmc.cc
+++ b/libs/midi++2/mmc.cc
@@ -20,6 +20,7 @@
#include <map>
+#include "control_protocol/timecode.h"
#include "pbd/error.h"
#include "midi++/mmc.h"
#include "midi++/port.h"
@@ -29,6 +30,8 @@ using namespace std;
using namespace MIDI;
using namespace PBD;
+pthread_t MachineControl::_sending_thread;
+
static std::map<int,string> mmc_cmd_map;
static void build_mmc_cmd_map ()
{
@@ -192,24 +195,27 @@ static void build_mmc_cmd_map ()
}
-MachineControl::MachineControl (Port &p, float /*version*/,
- CommandSignature & /*csig*/,
- ResponseSignature & /*rsig*/)
-
- : _port (p)
+MachineControl::MachineControl ()
+ : _port (0)
+ , _pending (16)
{
- Parser *parser;
-
build_mmc_cmd_map ();
_receive_device_id = 0;
_send_device_id = 0x7f;
-
- if ((parser = _port.input()) != 0) {
- parser->mmc.connect_same_thread (mmc_connection, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
+}
+
+void
+MachineControl::set_port (Port* p)
+{
+ _port = p;
+
+ mmc_connection.disconnect ();
+
+ if (_port->input()) {
+ _port->input()->mmc.connect_same_thread (mmc_connection, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
} else {
- warning << "MMC connected to a non-input port: useless!"
- << endmsg;
+ warning << "MMC connected to a non-input port: useless!" << endmsg;
}
}
@@ -227,7 +233,6 @@ MachineControl::set_send_device_id (byte id)
bool
MachineControl::is_mmc (byte *sysex_buf, size_t len)
-
{
if (len < 4 || len > 48) {
return false;
@@ -247,7 +252,6 @@ MachineControl::is_mmc (byte *sysex_buf, size_t len)
void
MachineControl::process_mmc_message (Parser &, byte *msg, size_t len)
-
{
size_t skiplen;
byte *mmc_msg;
@@ -455,7 +459,6 @@ MachineControl::process_mmc_message (Parser &, byte *msg, size_t len)
int
MachineControl::do_masked_write (byte *msg, size_t len)
-
{
/* return the number of bytes "consumed" */
@@ -555,12 +558,10 @@ MachineControl::write_track_status (byte *msg, size_t /*len*/, byte reg)
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;
}
@@ -571,7 +572,6 @@ MachineControl::write_track_status (byte *msg, size_t /*len*/, byte reg)
int
MachineControl::do_locate (byte *msg, size_t /*msglen*/)
-
{
if (msg[2] == 0) {
warning << "MIDI::MMC: locate [I/F] command not supported"
@@ -600,7 +600,6 @@ MachineControl::do_step (byte *msg, size_t /*msglen*/)
int
MachineControl::do_shuttle (byte *msg, size_t /*msglen*/)
-
{
size_t forward;
byte sh = msg[2];
@@ -630,3 +629,97 @@ MachineControl::do_shuttle (byte *msg, size_t /*msglen*/)
return 0;
}
+void
+MachineControl::enable_send (bool yn)
+{
+ _enable_send = yn;
+}
+
+/** Send a MMC command. It will be sent immediately if the call is made in _sending_thread,
+ * otherwise it will be queued and sent next time flush_pending()
+ * is called.
+ * @param c command, which this method takes ownership of.
+ */
+void
+MachineControl::send (MachineControlCommand const & c)
+{
+ if (pthread_self() == _sending_thread) {
+ send_immediately (c);
+ } else {
+ _pending.write (&c, 1);
+ }
+}
+
+/** Send any pending MMC commands immediately. Must be called from _sending_thread */
+void
+MachineControl::flush_pending ()
+{
+ MachineControlCommand c;
+ while (_pending.read (&c, 1) == 1) {
+ send_immediately (c);
+ }
+}
+
+/** Send a MMC immediately. Must be called from _sending_thread.
+ * @param c command, which this method takes ownership of.
+ */
+void
+MachineControl::send_immediately (MachineControlCommand const & c)
+{
+ if (_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 (_port->midimsg (buffer, b - buffer, 0)) {
+ error << "MMC: cannot send command" << endmsg;
+ }
+}
+
+/** Set the thread that we should send MMC in */
+void
+MachineControl::set_sending_thread (pthread_t t)
+{
+ _sending_thread = t;
+}
+
+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;
+}