add sysex support to MIDI binding maps, and a couple more functions
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 28 Dec 2009 23:55:33 +0000 (23:55 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 28 Dec 2009 23:55:33 +0000 (23:55 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6410 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/midifunction.cc
libs/surfaces/generic_midi/midifunction.h

index 67e940d905c81465bbc8cc086b02b681264dafc3..d0d74f4c12196efd5ae3daea0c0d0bc4d75ddbe1 100644 (file)
@@ -20,6 +20,7 @@
 #define __STDC_FORMAT_MACROS 1
 #include <stdint.h>
 
+#include <sstream>
 #include <algorithm>
 
 #include "pbd/error.h"
@@ -469,6 +470,8 @@ GenericMidiControlProtocol::load_bindings (const string& xmlpath)
 
                        } else if (child->property ("function")) {
 
+                               cerr << "try to create a function from " << child->property ("function")->value() << endl;
+
                                /* function */
                                MIDIFunction* mf;
 
@@ -541,18 +544,13 @@ MIDIFunction*
 GenericMidiControlProtocol::create_function (const XMLNode& node)
 {
        const XMLProperty* prop;
-       int detail;
-       int channel;
+       int intval;
+       MIDI::byte detail = 0;
+       MIDI::channel_t channel = 0;
        string uri;
        MIDI::eventType ev;
-
-       if ((prop = node.property (X_("channel"))) == 0) {
-               return 0;
-       }
-       
-       if (sscanf (prop->value().c_str(), "%d", &channel) != 1) {
-               return 0;
-       }
+       MIDI::byte* sysex = 0;
+       uint32_t sysex_size = 0;
 
        if ((prop = node.property (X_("ctl"))) != 0) {
                ev = MIDI::controller;
@@ -560,25 +558,77 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
                ev = MIDI::on;
        } else if ((prop = node.property (X_("pgm"))) != 0) {
                ev = MIDI::program;
+       } else if ((prop = node.property (X_("sysex"))) != 0) {
+
+               ev = MIDI::sysex;
+               int val;
+               uint32_t cnt;
+
+               {
+                       cnt = 0;
+                       stringstream ss (prop->value());
+                       ss << hex;
+                       
+                       while (ss >> val) {
+                               cnt++;
+                       }
+               }
+
+               if (cnt == 0) {
+                       return 0;
+               }
+
+               sysex = new MIDI::byte[cnt];
+               sysex_size = cnt;
+               
+               {
+                       stringstream ss (prop->value());
+                       ss << hex;
+                       cnt = 0;
+                       
+                       while (ss >> val) {
+                               sysex[cnt++] = (MIDI::byte) val;
+                               cerr << hex << (int) sysex[cnt-1] << dec << ' ' << endl;
+                       }
+               }
+               
        } else {
+               warning << "Binding ignored - unknown type" << endmsg;
                return 0;
        }
 
-       if (sscanf (prop->value().c_str(), "%d", &detail) != 1) {
-               return 0;
+       if (sysex_size == 0) {
+               if ((prop = node.property (X_("channel"))) == 0) {
+                       return 0;
+               }
+       
+               if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
+                       return 0;
+               }
+               channel = (MIDI::channel_t) intval;
+               /* adjust channel to zero-based counting */
+               if (channel > 0) {
+                       channel -= 1;
+               }
+               
+               if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
+                       return 0;
+               }
+               
+               detail = (MIDI::byte) intval;
        }
 
        prop = node.property (X_("function"));
        
        MIDIFunction* mf = new MIDIFunction (*_port);
        
-       if (mf->init (*this, prop->value())) {
+       if (mf->init (*this, prop->value(), sysex, sysex_size)) {
                delete mf;
                return 0;
        }
 
        mf->bind_midi (channel, ev, detail);
-       
+
        cerr << "New MF with function = " << prop->value() << endl;
 
        return mf;
index e36af93ab3adfb5584356d2b1c3a1e983423eb70..609aca3bbc06f85ce99e64e4d5f7e45416b0fcda 100644 (file)
@@ -28,14 +28,17 @@ using namespace MIDI;
 MIDIFunction::MIDIFunction (MIDI::Port& p)
        : _port (p)
 {
+       sysex_size = 0;
+       sysex = 0;
 }
 
 MIDIFunction::~MIDIFunction ()
 {
+       delete sysex;
 }
 
 int
-MIDIFunction::init (BasicUI& ui, const std::string& function_name)
+MIDIFunction::init (BasicUI& ui, const std::string& function_name, MIDI::byte* sysex_data, size_t sysex_sz)
 {
        if (strcasecmp (function_name.c_str(), "transport-stop") == 0) {
                _function = TransportStop;
@@ -47,11 +50,24 @@ MIDIFunction::init (BasicUI& ui, const std::string& function_name)
                _function = TransportStart;
        } else if (strcasecmp (function_name.c_str(), "transport-end") == 0) {
                _function = TransportEnd;
+       } else if (strcasecmp (function_name.c_str(), "loop-toggle") == 0) {
+               _function = TransportLoopToggle;
+       } else if (strcasecmp (function_name.c_str(), "rec-enable") == 0) {
+               _function = TransportRecordEnable;
+       } else if (strcasecmp (function_name.c_str(), "rec-disable") == 0) {
+               _function = TransportRecordDisable;
        } else {
                return -1;
        }
 
        _ui = &ui;
+
+       if (sysex_sz) {
+               /* we take ownership of the sysex data */
+               sysex = sysex_data;
+               sysex_size = sysex_sz;
+       }
+
        return 0;
 }
 
@@ -78,6 +94,18 @@ MIDIFunction::execute ()
        case TransportEnd:
                _ui->goto_end ();
                break;
+
+       case TransportLoopToggle:
+               _ui->loop_toggle ();
+               break;
+
+       case TransportRecordEnable:
+               _ui->set_record_enable (true);
+               break;
+
+       case TransportRecordDisable:
+               _ui->set_record_enable (false);
+               break;
        }
 }
 
@@ -117,6 +145,20 @@ MIDIFunction::midi_sense_program_change (Parser &, byte msg)
        }
 }
 
+void
+MIDIFunction::midi_sense_sysex (Parser &, byte* msg, size_t sz)
+{
+       if (sz != sysex_size) {
+               return;
+       }
+
+       if (memcmp (msg, sysex, sysex_size) != 0) {
+               return;
+       }
+
+       execute ();
+}
+
 void
 MIDIFunction::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
 {
@@ -156,6 +198,10 @@ MIDIFunction::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
                p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_program_change, this, _1, _2));
                break;
 
+       case MIDI::sysex:
+               p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_sysex, this, _1, _2, _3));
+               break;
+
        default:
                break;
        }
@@ -173,3 +219,4 @@ MIDIFunction::set_state (const XMLNode& node, int version)
 {
        return 0;
 }
+
index 5374d94157aa50a0ed965553f69fd5309190fbf2..8931e2c9ebde4ebdf0a759a22cef9e4e96658346 100644 (file)
@@ -45,13 +45,16 @@ class MIDIFunction : public PBD::Stateful
                TransportStop,
                TransportZero,
                TransportStart,
-               TransportEnd
+               TransportEnd,
+               TransportLoopToggle,
+               TransportRecordEnable,
+               TransportRecordDisable
        };
 
        MIDIFunction (MIDI::Port&);
        virtual ~MIDIFunction ();
 
-       int init (BasicUI&, const std::string&);
+       int init (BasicUI&, const std::string& function_name, MIDI::byte* sysex = 0, size_t ssize = 0);
 
        MIDI::Port& get_port() const { return _port; }
        const std::string& function_name() const { return _function_name; }
@@ -73,8 +76,9 @@ class MIDIFunction : public PBD::Stateful
        MIDI::eventType  control_type;
        MIDI::byte       control_additional;
        MIDI::channel_t  control_channel;
+       MIDI::byte*      sysex;
+       size_t         sysex_size;
 
-       void init (const std::string& function_name);
        void execute ();
 
        void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
@@ -82,6 +86,7 @@ class MIDIFunction : public PBD::Stateful
        void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
        void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *);
        void midi_sense_program_change (MIDI::Parser &, MIDI::byte);
+       void midi_sense_sysex (MIDI::Parser &, MIDI::byte*, size_t);
 };
 
 #endif // __gm_midicontrollable_h__