MCP: drastically alter setup of Mackie surface to not use the CSV files in anyway...
[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 {
58         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
59 }
60
61 MackiePort::~MackiePort()
62 {
63         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
64         close();
65         DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
66 }
67
68 int MackiePort::strips() const
69 {
70         if  (_port_type == mcu)
71         {
72                 switch  (_emulation)
73                 {
74                         // BCF2000 only has 8 faders, so reserve one for master
75                         case bcf2000: return 7;
76                         case mackie: return 8;
77                         case none:
78                         default:
79                                 throw MackieControlException ("MackiePort::strips: don't know what emulation we're using");
80                 }
81         }
82         else
83         {
84                 // must be an extender, ie no master fader
85                 return 8;
86         }
87 }
88
89 // should really be in MackiePort
90 void MackiePort::open()
91 {
92         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
93         
94         input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
95                      
96         // make sure the device is connected
97         init();
98 }
99
100 void MackiePort::close()
101 {
102         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
103         
104         // disconnect signals
105         any_connection.disconnect();
106         sysex_connection.disconnect();
107         
108         // TODO emit a "closing" signal?
109 }
110
111 const MidiByteArray & MackiePort::sysex_hdr() const
112 {
113         switch  (_port_type)
114         {
115                 case mcu: return mackie_sysex_hdr;
116                 case ext: return mackie_sysex_hdr_xt;
117         }
118         cout << "MackiePort::sysex_hdr _port_type not known" << endl;
119         return mackie_sysex_hdr;
120 }
121
122 MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
123 {
124         MidiByteArray l;
125         back_insert_iterator<MidiByteArray> back  (l);
126         copy (begin, end, back);
127         
128         MidiByteArray retval;
129         
130         // this is how to calculate the response to the challenge.
131         // from the Logic docs.
132         retval <<  (0x7f &  (l[0] +  (l[1] ^ 0xa) - l[3]));
133         retval <<  (0x7f &  ( (l[2] >> l[3]) ^  (l[0] + l[3])));
134         retval <<  (0x7f &  ((l[3] -  (l[2] << 2)) ^  (l[0] | l[1])));
135         retval <<  (0x7f &  (l[1] - l[2] +  (0xf0 ^  (l[3] << 4))));
136         
137         return retval;
138 }
139
140 // not used right now
141 MidiByteArray MackiePort::host_connection_query (MidiByteArray & bytes)
142 {
143         // handle host connection query
144         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
145         
146         if  (bytes.size() != 18) {
147                 finalise_init (false);
148                 cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
149                 return;
150         }
151
152         // build and send host connection reply
153         MidiByteArray response;
154         response << 0x02;
155         copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
156         response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
157         return response;
158 }
159
160 // not used right now
161 MidiByteArray MackiePort::host_connection_confirmation (const MidiByteArray & bytes)
162 {
163         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
164         
165         // decode host connection confirmation
166         if  (bytes.size() != 14) {
167                 finalise_init (false);
168                 ostringstream os;
169                 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
170                 throw MackieControlException (os.str());
171         }
172         
173         // send version request
174         return MidiByteArray (2, 0x13, 0x00);
175 }
176
177 void MackiePort::probe_emulation (const MidiByteArray &)
178 {
179 #if 0
180         cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
181
182         MidiByteArray version_string;
183         for  (int i = 6; i < 11; ++i) version_string << bytes[i];
184         cout << "version_string: " << version_string << endl;
185 #endif
186         
187         // TODO investigate using serial number. Also, possibly size of bytes might
188         // give an indication. Also, apparently MCU sends non-documented messages
189         // sometimes.
190         if (!_initialising)
191         {
192                 //cout << "MackiePort::probe_emulation out of sequence." << endl;
193                 return;
194         }
195
196         finalise_init (true);
197 }
198
199 void MackiePort::init()
200 {
201         DEBUG_TRACE (DEBUG::MackieControl,  "MackiePort::init\n");
202
203         init_mutex.lock();
204         _initialising = true;
205
206         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
207
208         // emit pre-init signal
209         init_event();
210         
211         // kick off initialisation. See docs in header file for init()
212         
213         // bypass the init sequence because sometimes the first
214         // message doesn't get to the unit, and there's no way
215         // to do a timed lock in Glib.
216         //write_sysex  (MidiByteArray  (2, 0x13, 0x00));
217         
218         finalise_init (true);
219 }
220
221 void MackiePort::finalise_init (bool yn)
222 {
223         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
224
225         bool emulation_ok = false;
226         
227         // probing doesn't work very well, so just use a config variable
228         // to set the emulation mode
229         // TODO This might have to be specified on a per-port basis
230         // in the config file
231         // if an mcu and a bcf are needed to work as one surface
232         if  (_emulation == none)
233         {
234                 // TODO same as code in mackie_control_protocol.cc
235                 if  (ARDOUR::Config->get_mackie_emulation() == "bcf")
236                 {
237                         _emulation = bcf2000;
238                         emulation_ok = true;
239                 }
240                 else if  (ARDOUR::Config->get_mackie_emulation() == "mcu")
241                 {
242                         _emulation = mackie;
243                         emulation_ok = true;
244                 }
245                 else
246                 {
247                         cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
248                         emulation_ok = false;
249                 }
250         }
251         
252         yn = yn && emulation_ok;
253         
254         SurfacePort::active (yn);
255
256         if (yn) {
257                 active_event();
258                 
259                 // start handling messages from controls
260                 connect_any();
261         }
262
263         _initialising = false;
264         init_cond.signal();
265         init_mutex.unlock();
266
267         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
268 }
269
270 void MackiePort::connect_any()
271 {
272         if (!any_connection.connected()) {
273                 input_port().parser()->any.connect_same_thread (any_connection, boost::bind (&MackiePort::handle_midi_any, this, _1, _2, _3));
274         }
275 }
276
277 bool MackiePort::wait_for_init()
278 {
279         Glib::Mutex::Lock lock (init_mutex);
280         while (_initialising) {
281                 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
282                 init_cond.wait (init_mutex);
283                 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
284         }
285         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
286         return SurfacePort::active();
287 }
288
289 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
290 {
291         MidiByteArray bytes (count, raw_bytes);
292
293         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
294
295         switch (bytes[5])
296         {
297                 case 0x01:
298                         write_sysex (host_connection_query (bytes));
299                         break;
300                 case 0x03:
301                         // not used right now
302                         write_sysex (host_connection_confirmation (bytes));
303                         break;
304                 case 0x04:
305                         inactive_event ();
306                         cout << "host connection error" << bytes << endl;
307                         break;
308                 case 0x14:
309                         probe_emulation (bytes);
310                         break;
311                 default:
312                         cout << "unknown sysex: " << bytes << endl;
313         }
314 }
315
316 Control & MackiePort::lookup_control (MIDI::byte * bytes, size_t count)
317 {
318         // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
319         // Reason being that this method is called for every single incoming
320         // midi event, and it needs to be as efficient as possible.
321
322         Control * control = 0;
323         MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
324
325         switch (midi_type) {
326                 // fader
327                 case MackieMidiBuilder::midi_fader_id:
328                 {
329                         int midi_id = bytes[0] & 0x0f;
330                         control = _mcp.surface().faders[midi_id];
331                         if  (control == 0)
332                         {
333                                 MidiByteArray mba (count, bytes);
334                                 ostringstream os;
335                                 os << "Control for fader" << bytes << " id " << midi_id << " is null";
336                                 throw MackieControlException (os.str());
337                         }
338                         break;
339                 }
340                         
341                 // button
342                 case MackieMidiBuilder::midi_button_id:
343                         control = _mcp.surface().buttons[bytes[1]];
344                         if  (control == 0)
345                         {
346                                 MidiByteArray mba (count, bytes);
347                                 ostringstream os;
348                                 os << "Control for button " << mba << " is null";
349                                 throw MackieControlException (os.str());
350                         }
351                         break;
352                         
353                 // pot (jog wheel, external control)
354                 case MackieMidiBuilder::midi_pot_id:
355                         control = _mcp.surface().pots[bytes[1]];
356                         if  (control == 0)
357                         {
358                                 MidiByteArray mba (count, bytes);
359                                 ostringstream os;
360                                 os << "Control for rotary " << mba << " is null";
361                                 throw MackieControlException (os.str());
362                         }
363                         break;
364                 
365                 default:
366                         MidiByteArray mba (count, bytes);
367                         ostringstream os;
368                         os << "Cannot find control for " << mba;
369                         throw MackieControlException (os.str());
370         }
371         return *control;
372 }
373
374 // converts midi messages into control_event signals
375 // it might be worth combining this with lookup_control
376 // because they have similar logic flows.
377 void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
378 {
379         MidiByteArray bytes (count, raw_bytes);
380         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_any %1\n", bytes));
381
382         try
383         {
384                 // ignore sysex messages
385                 if  (raw_bytes[0] == MIDI::sysex) return;
386
387                 // sanity checking
388                 if (count != 3) {
389                         ostringstream os;
390                         MidiByteArray mba (count, raw_bytes);
391                         os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
392                         throw MackieControlException (os.str());
393                 }
394                 
395                 Control & control = lookup_control (raw_bytes, count);
396                 control.set_in_use (true);
397                 
398                 // This handles incoming bytes. Outgoing bytes
399                 // are sent by the signal handlers.
400                 switch (control.type()) {
401                         // fader
402                         case Control::type_fader:
403                         {
404                                 // only the top-order 10 bits out of 14 are used
405                                 int midi_pos =  ( (raw_bytes[2] << 7) + raw_bytes[1]) >> 4;
406                                 
407                                 // in_use is set by the MackieControlProtocol::handle_strip_button
408                                 
409                                 // relies on implicit ControlState constructor
410                                 control_event (*this, control, float(midi_pos) / float(0x3ff));
411                         }
412                         break;
413                                 
414                         // button
415                         case Control::type_button:
416                         {
417                                 ControlState control_state (raw_bytes[2] == 0x7f ? press : release);
418                                 control.set_in_use (control_state.button_state == press);
419                                 control_event (*this, control, control_state);
420                                 
421                                 break;
422                         }
423                                 
424                         // pot (jog wheel, external control)
425                         case Control::type_pot:
426                         {
427                                 ControlState state;
428                                 
429                                 // bytes[2] & 0b01000000 (0x40) give sign
430                                 state.sign =  (raw_bytes[2] & 0x40) == 0 ? 1 : -1; 
431                                 // bytes[2] & 0b00111111 (0x3f) gives delta
432                                 state.ticks =  (raw_bytes[2] & 0x3f);
433                                 if (state.ticks == 0) {
434                                         /* euphonix and perhaps other devices send zero
435                                            when they mean 1, we think.
436                                         */
437                                         state.ticks = 1;
438                                 }
439                                 state.delta = float (state.ticks) / float (0x3f);
440                                 
441                                 /* Pots only emit events when they move, not when they
442                                    stop moving. So to get a stop event, we need to use a timeout.
443                                 */
444
445                                 control.set_in_use (true);
446                                 add_in_use_timeout (control, &control);
447
448                                 // emit the control event
449                                 control_event (*this, control, state);
450                                 break;
451                         }
452                         default:
453                                 cerr << "Do not understand control type " << control;
454                 }
455         }
456
457         catch (MackieControlException & e) {
458                 MidiByteArray bytes (count, raw_bytes);
459                 cout << bytes << ' ' << e.what() << endl;
460         }
461
462         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes));
463 }
464