debug ardour->MCP fader mapping
[ardour.git] / libs / surfaces / mackie / mackie_port.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3
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.
8
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.
13
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.
17 */
18 #include "mackie_port.h"
19
20 #include "mackie_control_exception.h"
21 #include "mackie_control_protocol.h"
22 #include "mackie_midi_builder.h"
23 #include "controls.h"
24 #include "surface.h"
25
26 #include <glibmm/main.h>
27
28 #include <boost/shared_array.hpp>
29
30 #include "midi++/types.h"
31 #include "midi++/port.h"
32
33 #include "ardour/debug.h"
34 #include "ardour/rc_configuration.h"
35
36 #include "i18n.h"
37
38 #include <sstream>
39
40 using namespace std;
41 using namespace Mackie;
42 using namespace ARDOUR;
43 using namespace PBD;
44
45 // The MCU sysex header
46 MidiByteArray mackie_sysex_hdr  (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10);
47
48 // The MCU extender sysex header
49 MidiByteArray mackie_sysex_hdr_xt  (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11);
50
51 MackiePort::MackiePort (MackieControlProtocol & mcp, MIDI::Port & input_port, MIDI::Port & output_port, int number, port_type_t port_type)
52         : SurfacePort (input_port, output_port, number)
53         , _mcp (mcp)
54         , _port_type (port_type)
55         , _emulation (none)
56         , _initialising (true)
57         , _connected (false)
58 {
59         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
60 }
61
62 MackiePort::~MackiePort()
63 {
64         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
65         close();
66         DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
67 }
68
69 int MackiePort::strips() const
70 {
71         if  (_port_type == mcu)
72         {
73                 switch  (_emulation)
74                 {
75                         // BCF2000 only has 8 faders, so reserve one for master
76                         case bcf2000: return 7;
77                         case mackie: return 8;
78                         case none:
79                         default:
80                                 throw MackieControlException ("MackiePort::strips: don't know what emulation we're using");
81                 }
82         }
83         else
84         {
85                 // must be an extender, ie no master fader
86                 return 8;
87         }
88 }
89
90 // should really be in MackiePort
91 void MackiePort::open()
92 {
93         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
94         
95         input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
96                      
97         // make sure the device is connected
98         init();
99 }
100
101 void MackiePort::close()
102 {
103         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
104         
105         // disconnect signals
106
107         sysex_connection.disconnect();
108         ScopedConnectionList::drop_connections ();
109         _connected = false;
110
111         // TODO emit a "closing" signal?
112 }
113
114 const MidiByteArray & MackiePort::sysex_hdr() const
115 {
116         switch  (_port_type)
117         {
118                 case mcu: return mackie_sysex_hdr;
119                 case ext: return mackie_sysex_hdr_xt;
120         }
121         cout << "MackiePort::sysex_hdr _port_type not known" << endl;
122         return mackie_sysex_hdr;
123 }
124
125 MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
126 {
127         MidiByteArray l;
128         back_insert_iterator<MidiByteArray> back  (l);
129         copy (begin, end, back);
130         
131         MidiByteArray retval;
132         
133         // this is how to calculate the response to the challenge.
134         // from the Logic docs.
135         retval <<  (0x7f &  (l[0] +  (l[1] ^ 0xa) - l[3]));
136         retval <<  (0x7f &  ( (l[2] >> l[3]) ^  (l[0] + l[3])));
137         retval <<  (0x7f &  ((l[3] -  (l[2] << 2)) ^  (l[0] | l[1])));
138         retval <<  (0x7f &  (l[1] - l[2] +  (0xf0 ^  (l[3] << 4))));
139         
140         return retval;
141 }
142
143 // not used right now
144 MidiByteArray MackiePort::host_connection_query (MidiByteArray & bytes)
145 {
146         MidiByteArray response;
147
148         // handle host connection query
149         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
150         
151         if  (bytes.size() != 18) {
152                 finalise_init (false);
153                 cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
154                 return response;
155         }
156
157         // build and send host connection reply
158         response << 0x02;
159         copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
160         response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
161         return response;
162 }
163
164 // not used right now
165 MidiByteArray MackiePort::host_connection_confirmation (const MidiByteArray & bytes)
166 {
167         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
168         
169         // decode host connection confirmation
170         if  (bytes.size() != 14) {
171                 finalise_init (false);
172                 ostringstream os;
173                 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
174                 throw MackieControlException (os.str());
175         }
176         
177         // send version request
178         return MidiByteArray (2, 0x13, 0x00);
179 }
180
181 void MackiePort::probe_emulation (const MidiByteArray &)
182 {
183 #if 0
184         cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
185
186         MidiByteArray version_string;
187         for  (int i = 6; i < 11; ++i) version_string << bytes[i];
188         cout << "version_string: " << version_string << endl;
189 #endif
190         
191         // TODO investigate using serial number. Also, possibly size of bytes might
192         // give an indication. Also, apparently MCU sends non-documented messages
193         // sometimes.
194         if (!_initialising)
195         {
196                 //cout << "MackiePort::probe_emulation out of sequence." << endl;
197                 return;
198         }
199
200         finalise_init (true);
201 }
202
203 void MackiePort::init()
204 {
205         DEBUG_TRACE (DEBUG::MackieControl,  "MackiePort::init\n");
206
207         init_mutex.lock();
208         _initialising = true;
209
210         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
211
212         // emit pre-init signal
213         init_event();
214         
215         // kick off initialisation. See docs in header file for init()
216         
217         // bypass the init sequence because sometimes the first
218         // message doesn't get to the unit, and there's no way
219         // to do a timed lock in Glib.
220         //write_sysex  (MidiByteArray  (2, 0x13, 0x00));
221         
222         finalise_init (true);
223 }
224
225 void MackiePort::finalise_init (bool yn)
226 {
227         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
228
229         bool emulation_ok = false;
230         
231         // probing doesn't work very well, so just use a config variable
232         // to set the emulation mode
233         // TODO This might have to be specified on a per-port basis
234         // in the config file
235         // if an mcu and a bcf are needed to work as one surface
236         if  (_emulation == none) {
237
238                 // TODO same as code in mackie_control_protocol.cc
239                 if  (ARDOUR::Config->get_mackie_emulation() == "bcf") {
240                         _emulation = bcf2000;
241                         emulation_ok = true;
242                 } else if  (ARDOUR::Config->get_mackie_emulation() == "mcu")  {
243                         _emulation = mackie;
244                         emulation_ok = true;
245                 } else {
246                         cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
247                         emulation_ok = false;
248                 }
249         }
250         
251         yn = yn && emulation_ok;
252         
253         SurfacePort::active (yn);
254
255         if (yn) {
256                 active_event();
257                 
258                 // start handling messages from controls
259                 connect_to_signals ();
260         }
261
262         _initialising = false;
263         init_cond.signal();
264         init_mutex.unlock();
265
266         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
267 }
268
269 void MackiePort::connect_to_signals ()
270 {
271         if (!_connected) {
272
273                 MIDI::Parser* p = input_port().parser();
274
275                 p->controller.connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_controller_message, this, _1, _2));
276                 
277                 p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 0U));
278                 p->channel_pitchbend[1].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 1U));
279                 p->channel_pitchbend[2].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 2U));
280                 p->channel_pitchbend[3].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 3U));
281                 p->channel_pitchbend[4].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 4U));
282                 p->channel_pitchbend[5].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 5U));
283                 p->channel_pitchbend[6].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 6U));
284                 p->channel_pitchbend[7].connect_same_thread (*this, boost::bind (&MackiePort::handle_midi_pitchbend_message, this, _1, _2, 7U));
285                 
286                 _connected = true;
287         }
288 }
289
290 bool MackiePort::wait_for_init()
291 {
292         Glib::Mutex::Lock lock (init_mutex);
293         while (_initialising) {
294                 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
295                 init_cond.wait (init_mutex);
296                 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
297         }
298         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
299         return SurfacePort::active();
300 }
301
302 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
303 {
304         MidiByteArray bytes (count, raw_bytes);
305
306         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
307
308         switch (bytes[5])
309         {
310                 case 0x01:
311                         write_sysex (host_connection_query (bytes));
312                         break;
313                 case 0x03:
314                         // not used right now
315                         write_sysex (host_connection_confirmation (bytes));
316                         break;
317                 case 0x04:
318                         inactive_event ();
319                         cout << "host connection error" << bytes << endl;
320                         break;
321                 case 0x14:
322                         probe_emulation (bytes);
323                         break;
324                 default:
325                         cout << "unknown sysex: " << bytes << endl;
326         }
327 }
328
329 void
330 MackiePort::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
331 {
332         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi pitchbend, fader = %1 value = %2\n", fader_id, pb));
333
334         Control* control = _mcp.surface().faders[fader_id];
335
336         if (control) {
337                 float midi_pos = pb >> 4; // only the top 10 bytes are used
338                 _mcp.handle_control_event (*this, *control, midi_pos / 1023.0);
339         }
340 }
341
342 void 
343 MackiePort::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
344 {
345         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_controller %1 = %2\n", ev->controller_number, ev->value));
346
347         Control* control;
348
349         switch (ev->controller_number & 0xf0) {
350         case Control::type_button:
351                 control = _mcp.surface().buttons[ev->controller_number];
352                 if (control) {
353                         control->set_in_use (true);
354                         ControlState control_state (ev->value == 0x7f ? press : release);
355                         control->set_in_use (control_state.button_state == press);
356                         control_event (*this, *control, control_state);
357                 }
358                 
359                 break;
360
361         case Control::type_pot:
362                 control = _mcp.surface().pots[ev->controller_number];
363                 if (control) {
364                         ControlState state;
365                         
366                         // bytes[2] & 0b01000000 (0x40) give sign
367                         state.sign = (ev->value & 0x40) == 0 ? 1 : -1; 
368                         // bytes[2] & 0b00111111 (0x3f) gives delta
369                         state.ticks = (ev->value & 0x3f);
370                         if (state.ticks == 0) {
371                                 /* euphonix and perhaps other devices send zero
372                                    when they mean 1, we think.
373                                 */
374                                 state.ticks = 1;
375                         }
376                         state.delta = float (state.ticks) / float (0x3f);
377                         
378                         /* Pots only emit events when they move, not when they
379                            stop moving. So to get a stop event, we need to use a timeout.
380                         */
381                         
382                         control->set_in_use (true);
383                         _mcp.add_in_use_timeout (*this, *control, control);
384                         control_event (*this, *control, state);
385                 }
386                 break;
387         
388         default:
389                 break;
390         }
391 }
392
393 void
394 MackiePort::control_event (SurfacePort& sp, Control& c, const ControlState& cs)
395 {
396         _mcp.handle_control_event (sp, c, cs);
397 }