MCP: zoom button toggles led
[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
19 #include <sstream>
20
21 #include <glibmm/main.h>
22 #include <boost/shared_array.hpp>
23
24 #include "mackie_port.h"
25
26 #include "mackie_control_exception.h"
27 #include "mackie_control_protocol.h"
28 #include "mackie_midi_builder.h"
29 #include "controls.h"
30 #include "surface.h"
31
32 #include "fader.h"
33 #include "button.h"
34 #include "strip.h"
35 #include "pot.h"
36 #include "control_group.h"
37
38 #include "midi++/types.h"
39 #include "midi++/port.h"
40
41 #include "ardour/debug.h"
42 #include "ardour/rc_configuration.h"
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace Mackie;
48 using namespace ARDOUR;
49 using namespace PBD;
50
51 // The MCU sysex header
52 MidiByteArray mackie_sysex_hdr  (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10);
53
54 // The MCU extender sysex header
55 MidiByteArray mackie_sysex_hdr_xt  (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11);
56
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)
59         , _mcp (mcp)
60         , _port_type (port_type)
61         , _emulation (none)
62         , _initialising (true)
63         , _connected (false)
64 {
65         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
66 }
67
68 MackiePort::~MackiePort()
69 {
70         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
71         close();
72         DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
73 }
74
75 int MackiePort::strips() const
76 {
77         if  (_port_type == mcu)
78         {
79                 switch  (_emulation)
80                 {
81                         // BCF2000 only has 8 faders, so reserve one for master
82                         case bcf2000: return 7;
83                         case mackie: return 8;
84                         case none:
85                         default:
86                                 throw MackieControlException ("MackiePort::strips: don't know what emulation we're using");
87                 }
88         }
89         else
90         {
91                 // must be an extender, ie no master fader
92                 return 8;
93         }
94 }
95
96 // should really be in MackiePort
97 void MackiePort::open()
98 {
99         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
100         
101         input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
102                      
103         // make sure the device is connected
104         init();
105 }
106
107 void MackiePort::close()
108 {
109         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
110         
111         // disconnect signals
112
113         sysex_connection.disconnect();
114         ScopedConnectionList::drop_connections ();
115         _connected = false;
116
117         // TODO emit a "closing" signal?
118 }
119
120 const MidiByteArray & MackiePort::sysex_hdr() const
121 {
122         switch  (_port_type)
123         {
124                 case mcu: return mackie_sysex_hdr;
125                 case ext: return mackie_sysex_hdr_xt;
126         }
127         cout << "MackiePort::sysex_hdr _port_type not known" << endl;
128         return mackie_sysex_hdr;
129 }
130
131 MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
132 {
133         MidiByteArray l;
134         back_insert_iterator<MidiByteArray> back  (l);
135         copy (begin, end, back);
136         
137         MidiByteArray retval;
138         
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))));
145         
146         return retval;
147 }
148
149 // not used right now
150 MidiByteArray MackiePort::host_connection_query (MidiByteArray & bytes)
151 {
152         MidiByteArray response;
153
154         // handle host connection query
155         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
156         
157         if  (bytes.size() != 18) {
158                 finalise_init (false);
159                 cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
160                 return response;
161         }
162
163         // build and send host connection reply
164         response << 0x02;
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);
167         return response;
168 }
169
170 // not used right now
171 MidiByteArray MackiePort::host_connection_confirmation (const MidiByteArray & bytes)
172 {
173         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
174         
175         // decode host connection confirmation
176         if  (bytes.size() != 14) {
177                 finalise_init (false);
178                 ostringstream os;
179                 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
180                 throw MackieControlException (os.str());
181         }
182         
183         // send version request
184         return MidiByteArray (2, 0x13, 0x00);
185 }
186
187 void MackiePort::probe_emulation (const MidiByteArray &)
188 {
189 #if 0
190         cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
191
192         MidiByteArray version_string;
193         for  (int i = 6; i < 11; ++i) version_string << bytes[i];
194         cout << "version_string: " << version_string << endl;
195 #endif
196         
197         // TODO investigate using serial number. Also, possibly size of bytes might
198         // give an indication. Also, apparently MCU sends non-documented messages
199         // sometimes.
200         if (!_initialising)
201         {
202                 //cout << "MackiePort::probe_emulation out of sequence." << endl;
203                 return;
204         }
205
206         finalise_init (true);
207 }
208
209 void MackiePort::init()
210 {
211         DEBUG_TRACE (DEBUG::MackieControl,  "MackiePort::init\n");
212
213         init_mutex.lock();
214         _initialising = true;
215
216         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
217
218         // emit pre-init signal
219         init_event();
220         
221         // kick off initialisation. See docs in header file for init()
222         
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));
227         
228         finalise_init (true);
229 }
230
231 void MackiePort::finalise_init (bool yn)
232 {
233         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
234
235         bool emulation_ok = false;
236         
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) {
243
244                 // TODO same as code in mackie_control_protocol.cc
245                 if  (ARDOUR::Config->get_mackie_emulation() == "bcf") {
246                         _emulation = bcf2000;
247                         emulation_ok = true;
248                 } else if  (ARDOUR::Config->get_mackie_emulation() == "mcu")  {
249                         _emulation = mackie;
250                         emulation_ok = true;
251                 } else {
252                         cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
253                         emulation_ok = false;
254                 }
255         }
256         
257         yn = yn && emulation_ok;
258         
259         SurfacePort::active (yn);
260
261         if (yn) {
262                 active_event();
263                 
264                 // start handling messages from controls
265                 connect_to_signals ();
266         }
267
268         _initialising = false;
269         init_cond.signal();
270         init_mutex.unlock();
271
272         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
273 }
274
275 void MackiePort::connect_to_signals ()
276 {
277         if (!_connected) {
278
279                 MIDI::Parser* p = input_port().parser();
280
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));
294                 
295                 _connected = true;
296         }
297 }
298
299 bool MackiePort::wait_for_init()
300 {
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");
306         }
307         DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
308         return SurfacePort::active();
309 }
310
311 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
312 {
313         MidiByteArray bytes (count, raw_bytes);
314
315         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
316
317         switch (bytes[5])
318         {
319                 case 0x01:
320                         write_sysex (host_connection_query (bytes));
321                         break;
322                 case 0x03:
323                         // not used right now
324                         write_sysex (host_connection_confirmation (bytes));
325                         break;
326                 case 0x04:
327                         inactive_event ();
328                         cout << "host connection error" << bytes << endl;
329                         break;
330                 case 0x14:
331                         probe_emulation (bytes);
332                         break;
333                 default:
334                         cout << "unknown sysex: " << bytes << endl;
335         }
336 }
337
338 void
339 MackiePort::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
340 {
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()));
343
344         Control* control = _mcp.surface().faders[(8*number()) + fader_id];
345
346         if (control) {
347                 float midi_pos = pb >> 4; // only the top 10 bytes are used
348                 _mcp.handle_control_event (*this, *control, midi_pos / 1023.0);
349         } else {
350                 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
351         }
352 }
353
354 void 
355 MackiePort::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
356 {
357         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_note_on %1 = %2\n", ev->note_number, ev->velocity));
358
359         Control* control = _mcp.surface().buttons[(8*number()) + ev->note_number];
360
361         if (control) {
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);
365         } else {
366                 DEBUG_TRACE (DEBUG::MackieControl, "button not found\n");
367         }
368 }
369
370 void 
371 MackiePort::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
372 {
373         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_controller %1 = %2\n", ev->controller_number, ev->value));
374
375         Control* control = _mcp.surface().pots[(8*number()) + ev->controller_number];
376
377         if (!control && ev->controller_number == Control::jog_base_id) {
378                 control = _mcp.surface().controls_by_name["jog"];
379         }
380
381         if (control) {
382                 ControlState state;
383                 
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.
391                         */
392                         state.ticks = 1;
393                 }
394                 state.delta = float (state.ticks) / float (0x3f);
395                 
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.
398                 */
399                 
400                 control->set_in_use (true);
401                 _mcp.add_in_use_timeout (*this, *control, control);
402
403                 control_event (*this, *control, state);
404         } else {
405                 DEBUG_TRACE (DEBUG::MackieControl, "pot not found\n");
406         }
407 }
408
409 void
410 MackiePort::control_event (SurfacePort& sp, Control& c, const ControlState& cs)
411 {
412         _mcp.handle_control_event (sp, c, cs);
413 }