2 Copyright (C) 2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <pbd/error.h>
24 #include <pbd/failed_constructor.h>
26 #include <midi++/port.h>
27 #include <midi++/manager.h>
28 #include <midi++/port_request.h>
30 #include <ardour/route.h>
31 #include <ardour/session.h>
33 #include "generic_midi_control_protocol.h"
34 #include "midicontrollable.h"
36 using namespace ARDOUR;
41 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
42 : ControlProtocol (s, _("GenericMIDI"))
44 MIDI::Manager* mm = MIDI::Manager::instance();
46 /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
47 the name is defined in ardour.rc which is likely not internationalized.
50 _port = mm->port (X_("control"));
53 error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
54 throw failed_constructor();
57 _feedback_interval = 10000; // microseconds
58 last_feedback_time = 0;
60 Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning));
61 Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning));
62 Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback));
65 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
70 GenericMidiControlProtocol::set_active (bool yn)
72 /* start/stop delivery/outbound thread */
77 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
79 _feedback_interval = ms;
83 GenericMidiControlProtocol::send_feedback ()
85 microseconds_t now = get_microseconds ();
87 if (last_feedback_time != 0) {
88 if ((now - last_feedback_time) < _feedback_interval) {
95 last_feedback_time = now;
99 GenericMidiControlProtocol::_send_feedback ()
101 const int32_t bufsize = 16 * 1024;
102 MIDI::byte buf[bufsize];
103 int32_t bsize = bufsize;
104 MIDI::byte* end = buf;
106 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
107 end = (*r)->write_feedback (end, bsize);
115 //_port->write (buf, (int32_t) (end - buf));
119 GenericMidiControlProtocol::start_learning (Controllable* c)
125 MIDIControllable* mc = new MIDIControllable (*_port, *c);
128 Glib::Mutex::Lock lm (pending_lock);
129 std::pair<MIDIControllables::iterator,bool> result;
130 result = pending_controllables.insert (mc);
132 c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
136 mc->learn_about_external_control ();
141 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
143 Glib::Mutex::Lock lm (pending_lock);
144 Glib::Mutex::Lock lm2 (controllables_lock);
146 MIDIControllables::iterator i = find (pending_controllables.begin(), pending_controllables.end(), mc);
148 if (i != pending_controllables.end()) {
149 pending_controllables.erase (i);
152 controllables.insert (mc);
156 GenericMidiControlProtocol::stop_learning (Controllable* c)
158 Glib::Mutex::Lock lm (pending_lock);
160 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
161 relevant MIDIControllable and remove it from the pending list.
164 for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
165 if (&(*i)->get_controllable() == c) {
166 (*i)->stop_learning ();
168 pending_controllables.erase (i);
175 GenericMidiControlProtocol::get_state ()
177 XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
178 XMLNode* children = new XMLNode (X_("controls"));
180 node->add_child_nocopy (*children);
182 Glib::Mutex::Lock lm2 (controllables_lock);
183 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
184 children->add_child_nocopy ((*i)->get_state());
191 GenericMidiControlProtocol::set_state (const XMLNode& node)
194 XMLNodeConstIterator niter;
198 Glib::Mutex::Lock lm (pending_lock);
199 pending_controllables.clear ();
202 Glib::Mutex::Lock lm2 (controllables_lock);
204 controllables.clear ();
206 nlist = node.children();
212 nlist = nlist.front()->children ();
214 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
218 if ((prop = (*niter)->property ("id")) != 0) {
220 ID id = prop->value ();
222 c = session->controllable_by_id (id);
225 MIDIControllable* mc = new MIDIControllable (*_port, *c);
226 if (mc->set_state (**niter) == 0) {
227 controllables.insert (mc);