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.
20 #define __STDC_FORMAT_MACROS 1
25 #include <pbd/error.h>
26 #include <pbd/failed_constructor.h>
28 #include <midi++/port.h>
29 #include <midi++/manager.h>
30 #include <midi++/port_request.h>
32 #include <ardour/route.h>
33 #include <ardour/session.h>
35 #include "generic_midi_control_protocol.h"
36 #include "midicontrollable.h"
38 using namespace ARDOUR;
43 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
44 : ControlProtocol (s, _("Generic MIDI"))
46 MIDI::Manager* mm = MIDI::Manager::instance();
48 /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
49 the name is defined in ardour.rc which is likely not internationalized.
52 _port = mm->port (X_("control"));
55 error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
56 throw failed_constructor();
60 _feedback_interval = 10000; // microseconds
61 last_feedback_time = 0;
63 Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning));
64 Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning));
65 Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback));
68 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
73 GenericMidiControlProtocol::set_active (bool yn)
75 /* start/stop delivery/outbound thread */
80 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
82 _feedback_interval = ms;
86 GenericMidiControlProtocol::send_feedback ()
92 microseconds_t now = get_microseconds ();
94 if (last_feedback_time != 0) {
95 if ((now - last_feedback_time) < _feedback_interval) {
102 last_feedback_time = now;
106 GenericMidiControlProtocol::_send_feedback ()
108 const int32_t bufsize = 16 * 1024; /* XXX too big */
109 MIDI::byte buf[bufsize];
110 int32_t bsize = bufsize;
111 MIDI::byte* end = buf;
113 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
114 end = (*r)->write_feedback (end, bsize);
122 //_port->write (buf, (int32_t) (end - buf));
126 GenericMidiControlProtocol::start_learning (Controllable* c)
132 MIDIControllable* mc = 0;
134 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
135 if ((*i)->get_controllable().id() == c->id()) {
142 mc = new MIDIControllable (*_port, *c);
146 Glib::Mutex::Lock lm (pending_lock);
147 std::pair<MIDIControllables::iterator,bool> result;
148 result = pending_controllables.insert (mc);
150 c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
154 mc->learn_about_external_control ();
159 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
161 Glib::Mutex::Lock lm (pending_lock);
162 Glib::Mutex::Lock lm2 (controllables_lock);
164 MIDIControllables::iterator i = find (pending_controllables.begin(), pending_controllables.end(), mc);
166 if (i != pending_controllables.end()) {
167 pending_controllables.erase (i);
170 controllables.insert (mc);
174 GenericMidiControlProtocol::stop_learning (Controllable* c)
176 Glib::Mutex::Lock lm (pending_lock);
177 Glib::Mutex::Lock lm2 (controllables_lock);
178 MIDIControllable* dptr = 0;
180 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
181 relevant MIDIControllable and remove it from the pending list.
184 for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
185 if (&(*i)->get_controllable() == c) {
186 (*i)->stop_learning ();
188 pending_controllables.erase (i);
193 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
194 if (&(*i)->get_controllable() == c) {
195 controllables.erase (i);
206 GenericMidiControlProtocol::get_state ()
208 XMLNode* node = new XMLNode ("Protocol");
211 node->add_property (X_("name"), _name);
212 node->add_property (X_("feedback"), do_feedback ? "1" : "0");
213 snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
214 node->add_property (X_("feedback_interval"), buf);
216 XMLNode* children = new XMLNode (X_("controls"));
218 node->add_child_nocopy (*children);
220 Glib::Mutex::Lock lm2 (controllables_lock);
221 for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
222 children->add_child_nocopy ((*i)->get_state());
229 GenericMidiControlProtocol::set_state (const XMLNode& node)
232 XMLNodeConstIterator niter;
233 const XMLProperty* prop;
235 if ((prop = node.property ("feedback")) != 0) {
236 do_feedback = (bool) atoi (prop->value().c_str());
241 if ((prop = node.property ("feedback_interval")) != 0) {
242 if (sscanf (prop->value().c_str(), "%" PRIu64, &_feedback_interval) != 1) {
243 _feedback_interval = 10000;
246 _feedback_interval = 10000;
252 Glib::Mutex::Lock lm (pending_lock);
253 pending_controllables.clear ();
256 Glib::Mutex::Lock lm2 (controllables_lock);
258 controllables.clear ();
260 nlist = node.children(); // "controls"
266 nlist = nlist.front()->children ();
268 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
270 if ((prop = (*niter)->property ("id")) != 0) {
272 ID id = prop->value ();
274 c = Controllable::by_id (id);
277 MIDIControllable* mc = new MIDIControllable (*_port, *c);
278 if (mc->set_state (**niter) == 0) {
279 controllables.insert (mc);
283 warning << string_compose (_("Generic MIDI control: controllable %1 not found (ignored)"), id)
293 GenericMidiControlProtocol::set_feedback (bool yn)
296 last_feedback_time = 0;
301 GenericMidiControlProtocol::get_feedback () const