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 <midi++/port.h>
24 #include <midi++/manager.h>
25 #include <midi++/port_request.h>
27 #include <ardour/route.h>
28 #include <ardour/session.h>
30 #include "generic_midi_control_protocol.h"
31 #include "midicontrollable.h"
33 using namespace ARDOUR;
38 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
39 : ControlProtocol (s, _("GenericMIDI"))
41 MIDI::Manager* mm = MIDI::Manager::instance();
42 MIDI::PortRequest pr ("ardour:MIDI control", "ardour:MIDI control", "duplex", "alsa/seq");
44 _port = mm->add_port (pr);
46 _feedback_interval = 10000; // microseconds
47 last_feedback_time = 0;
49 Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning));
50 Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning));
51 Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback));
54 GenericMidiControlProtocol::~GenericMidiControlProtocol ()
59 GenericMidiControlProtocol::set_active (bool yn)
61 /* start/stop delivery/outbound thread */
66 GenericMidiControlProtocol::set_feedback_interval (microseconds_t ms)
68 _feedback_interval = ms;
72 GenericMidiControlProtocol::send_feedback ()
74 microseconds_t now = get_microseconds ();
76 if (last_feedback_time != 0) {
77 if ((now - last_feedback_time) < _feedback_interval) {
84 last_feedback_time = now;
88 GenericMidiControlProtocol::_send_feedback ()
90 const int32_t bufsize = 16 * 1024;
91 MIDI::byte buf[bufsize];
92 int32_t bsize = bufsize;
93 MIDI::byte* end = buf;
95 for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
96 end = (*r)->write_feedback (end, bsize);
103 _port->write (buf, (int32_t) (end - buf));
107 GenericMidiControlProtocol::start_learning (Controllable* c)
113 MIDIControllable* mc = new MIDIControllable (*_port, *c);
117 Glib::Mutex::Lock lm (pending_lock);
118 pending_controllables.push_back (mc);
119 mc->learning_stopped.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
122 mc->learn_about_external_control ();
127 GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
129 Glib::Mutex::Lock lm (pending_lock);
130 Glib::Mutex::Lock lm2 (controllables_lock);
132 MIDIControllables::iterator i = find (pending_controllables.begin(), pending_controllables.end(), mc);
134 if (i != pending_controllables.end()) {
135 pending_controllables.erase (i);
138 controllables.push_back (mc);
142 GenericMidiControlProtocol::stop_learning (Controllable* c)
144 Glib::Mutex::Lock lm (pending_lock);
146 /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the
147 relevant MIDIControllable and remove it from the pending list.
150 for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
151 if (&(*i)->get_controllable() == c) {
152 (*i)->stop_learning ();
154 pending_controllables.erase (i);