2 Copyright (C) 2006,2007 John Anderson
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.
21 #include <glibmm/main.h>
22 #include <boost/shared_array.hpp>
24 #include "mackie_port.h"
26 #include "mackie_control_exception.h"
27 #include "mackie_control_protocol.h"
28 #include "mackie_midi_builder.h"
36 #include "control_group.h"
38 #include "midi++/types.h"
39 #include "midi++/port.h"
41 #include "ardour/debug.h"
42 #include "ardour/rc_configuration.h"
47 using namespace Mackie;
48 using namespace ARDOUR;
51 // The MCU sysex header
52 MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10);
54 // The MCU extender sysex header
55 MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11);
57 MackiePort::MackiePort (MackieControlProtocol & mcp, MIDI::Port & input_port, MIDI::Port & output_port, int number, port_type_t port_type)
58 : SurfacePort (input_port, output_port, number)
60 , _port_type (port_type)
62 , _initialising (true)
65 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
68 MackiePort::~MackiePort()
70 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
72 DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
75 int MackiePort::strips() const
77 if (_port_type == mcu)
81 // BCF2000 only has 8 faders, so reserve one for master
82 case bcf2000: return 7;
83 case mackie: return 8;
86 throw MackieControlException ("MackiePort::strips: don't know what emulation we're using");
91 // must be an extender, ie no master fader
96 // should really be in MackiePort
97 void MackiePort::open()
99 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
101 input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
103 // make sure the device is connected
107 void MackiePort::close()
109 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
111 // disconnect signals
113 sysex_connection.disconnect();
114 ScopedConnectionList::drop_connections ();
117 // TODO emit a "closing" signal?
120 const MidiByteArray & MackiePort::sysex_hdr() const
124 case mcu: return mackie_sysex_hdr;
125 case ext: return mackie_sysex_hdr_xt;
127 cout << "MackiePort::sysex_hdr _port_type not known" << endl;
128 return mackie_sysex_hdr;
131 MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
134 back_insert_iterator<MidiByteArray> back (l);
135 copy (begin, end, back);
137 MidiByteArray retval;
139 // this is how to calculate the response to the challenge.
140 // from the Logic docs.
141 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
142 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
143 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
144 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
149 // not used right now
150 MidiByteArray MackiePort::host_connection_query (MidiByteArray & bytes)
152 MidiByteArray response;
154 // handle host connection query
155 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
157 if (bytes.size() != 18) {
158 finalise_init (false);
159 cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
163 // build and send host connection reply
165 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
166 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
170 // not used right now
171 MidiByteArray MackiePort::host_connection_confirmation (const MidiByteArray & bytes)
173 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
175 // decode host connection confirmation
176 if (bytes.size() != 14) {
177 finalise_init (false);
179 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
180 throw MackieControlException (os.str());
183 // send version request
184 return MidiByteArray (2, 0x13, 0x00);
187 void MackiePort::probe_emulation (const MidiByteArray &)
190 cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
192 MidiByteArray version_string;
193 for (int i = 6; i < 11; ++i) version_string << bytes[i];
194 cout << "version_string: " << version_string << endl;
197 // TODO investigate using serial number. Also, possibly size of bytes might
198 // give an indication. Also, apparently MCU sends non-documented messages
202 //cout << "MackiePort::probe_emulation out of sequence." << endl;
206 finalise_init (true);
209 void MackiePort::init()
211 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init\n");
214 _initialising = true;
216 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
218 // emit pre-init signal
221 // kick off initialisation. See docs in header file for init()
223 // bypass the init sequence because sometimes the first
224 // message doesn't get to the unit, and there's no way
225 // to do a timed lock in Glib.
226 //write_sysex (MidiByteArray (2, 0x13, 0x00));
228 finalise_init (true);
231 void MackiePort::finalise_init (bool yn)
233 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
235 bool emulation_ok = false;
237 // probing doesn't work very well, so just use a config variable
238 // to set the emulation mode
239 // TODO This might have to be specified on a per-port basis
240 // in the config file
241 // if an mcu and a bcf are needed to work as one surface
242 if (_emulation == none) {
244 // TODO same as code in mackie_control_protocol.cc
245 if (ARDOUR::Config->get_mackie_emulation() == "bcf") {
246 _emulation = bcf2000;
248 } else if (ARDOUR::Config->get_mackie_emulation() == "mcu") {
252 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
253 emulation_ok = false;
257 yn = yn && emulation_ok;
259 SurfacePort::active (yn);
264 // start handling messages from controls
265 connect_to_signals ();
268 _initialising = false;
272 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
275 void MackiePort::connect_to_signals ()
279 MIDI::Parser* p = input_port().parser();
281 /* V-Pot messages are Controller */
282 p->controller.connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_controller_message, this, _1, _2));
283 /* Button messages are NoteOn */
284 p->note_on.connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_note_on_message, this, _1, _2));
285 /* Fader messages are Pitchbend */
286 p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 0U));
287 p->channel_pitchbend[1].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 1U));
288 p->channel_pitchbend[2].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 2U));
289 p->channel_pitchbend[3].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 3U));
290 p->channel_pitchbend[4].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 4U));
291 p->channel_pitchbend[5].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 5U));
292 p->channel_pitchbend[6].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 6U));
293 p->channel_pitchbend[7].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 7U));
299 bool MackiePort::wait_for_init()
301 Glib::Mutex::Lock lock (init_mutex);
302 while (_initialising) {
303 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
304 init_cond.wait (init_mutex);
305 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
307 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
308 return SurfacePort::active();
311 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
313 MidiByteArray bytes (count, raw_bytes);
315 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
320 write_sysex (host_connection_query (bytes));
323 // not used right now
324 write_sysex (host_connection_confirmation (bytes));
328 cout << "host connection error" << bytes << endl;
331 probe_emulation (bytes);
334 cout << "unknown sysex: " << bytes << endl;
339 MackiePort::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
341 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi pitchbend on port %3 (number %4), fader = %1 value = %2\n",
342 (8*number()) + fader_id, pb, *this, number()));
344 Control* control = _mcp.surface().faders[(8*number()) + fader_id];
347 float midi_pos = pb >> 4; // only the top 10 bytes are used
348 _mcp.handle_control_event (*this, *control, midi_pos / 1023.0);
350 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
355 MackiePort::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
357 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_note_on %1 = %2\n", ev->note_number, ev->velocity));
359 Control* control = _mcp.surface().buttons[(8*number()) + ev->note_number];
362 ControlState control_state (ev->velocity == 0x7f ? press : release);
363 control->set_in_use (control_state.button_state == press);
364 control_event (*this, *control, control_state);
366 DEBUG_TRACE (DEBUG::MackieControl, "button not found\n");
371 MackiePort::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
373 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_controller %1 = %2\n", ev->controller_number, ev->value));
375 Control* control = _mcp.surface().pots[(8*number()) + ev->controller_number];
377 if (!control && ev->controller_number == Control::jog_base_id) {
378 control = _mcp.surface().controls_by_name["jog"];
384 // bytes[2] & 0b01000000 (0x40) give sign
385 state.sign = (ev->value & 0x40) == 0 ? 1 : -1;
386 // bytes[2] & 0b00111111 (0x3f) gives delta
387 state.ticks = (ev->value & 0x3f);
388 if (state.ticks == 0) {
389 /* euphonix and perhaps other devices send zero
390 when they mean 1, we think.
394 state.delta = float (state.ticks) / float (0x3f);
396 /* Pots only emit events when they move, not when they
397 stop moving. So to get a stop event, we need to use a timeout.
400 control->set_in_use (true);
401 _mcp.add_in_use_timeout (*this, *control, control);
403 control_event (*this, *control, state);
405 DEBUG_TRACE (DEBUG::MackieControl, "pot not found\n");
410 MackiePort::control_event (SurfacePort& sp, Control& c, const ControlState& cs)
412 _mcp.handle_control_event (sp, c, cs);