get faderport i/o working, basics of identifying control activity
[ardour.git] / libs / surfaces / faderport / faderport.cc
1 /*
2     Copyright (C) 2006 Paul Davis
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
20 #include <stdint.h>
21
22 #include <sstream>
23 #include <algorithm>
24
25 #include <glibmm/fileutils.h>
26 #include <glibmm/miscutils.h>
27
28 #include "pbd/controllable_descriptor.h"
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/file_utils.h"
32 #include "pbd/xml++.h"
33 #include "pbd/compose.h"
34
35 #include "midi++/port.h"
36
37 #include "ardour/audioengine.h"
38 #include "ardour/filesystem_paths.h"
39 #include "ardour/session.h"
40 #include "ardour/route.h"
41 #include "ardour/midi_ui.h"
42 #include "ardour/midi_port.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/midiport_manager.h"
45 #include "ardour/debug.h"
46 #include "ardour/async_midi_port.h"
47
48 #include "faderport.h"
49
50 using namespace ARDOUR;
51 using namespace PBD;
52 using namespace Glib;
53 using namespace std;
54
55 #include "i18n.h"
56
57 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
58
59 FaderPort::FaderPort (Session& s)
60         : ControlProtocol (s, _("Faderport"))
61         , _motorised (true)
62         , _threshold (10)
63         , gui (0)
64         , connection_state (ConnectionState (0))
65         , _device_active (false)
66         , fader_msb (0)
67         , fader_lsb (0)
68 {
69         boost::shared_ptr<ARDOUR::Port> inp;
70         boost::shared_ptr<ARDOUR::Port> outp;
71
72         inp  = AudioEngine::instance()->register_input_port (DataType::MIDI, "Faderport Recv", true);
73         outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "Faderport Send", true);
74
75         _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(inp);
76         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(outp);
77
78         if (_input_port == 0 || _output_port == 0) {
79                 throw failed_constructor();
80         }
81
82         do_feedback = false;
83         _feedback_interval = 10 * 1000; // microseconds
84         last_feedback_time = 0;
85         native_counter = 0;
86
87         _current_bank = 0;
88         _bank_size = 0;
89
90         /* handle device inquiry response */
91         _input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
92         /* handle switches */
93         _input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::switch_handler, this, _1, _2));
94         /* handle encoder */
95         _input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
96         /* handle fader */
97         _input_port->parser()->controller.connect_same_thread (midi_connections, boost::bind (&FaderPort::fader_handler, this, _1, _2));
98
99         /* This connection means that whenever data is ready from the input
100          * port, the relevant thread will invoke our ::midi_input_handler()
101          * method, which will read the data, and invoke the parser.
102          */
103
104         _input_port->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &FaderPort::midi_input_handler), _input_port));
105         _input_port->xthread().attach (midi_ui_context()->main_loop()->get_context());
106
107         Session::SendFeedback.connect_same_thread (*this, boost::bind (&FaderPort::send_feedback, this));
108         //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderPort::send_feedback, this), midi_ui_context());;
109
110         /* this one is cross-thread */
111
112         Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderPort::reset_controllables, this), midi_ui_context());
113
114         /* Catch port connections and disconnections */
115         ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), midi_ui_context());
116
117 }
118
119 FaderPort::~FaderPort ()
120 {
121         if (_input_port) {
122                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering input port %1\n", boost::shared_ptr<ARDOUR::Port>(_input_port)->name()));
123                 AudioEngine::instance()->unregister_port (_input_port);
124                 _input_port.reset ();
125         }
126
127         if (_output_port) {
128 //              _output_port->drain (10000);  //ToDo:  is this necessary?  It hangs the shutdown, for me
129                 DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering output port %1\n", boost::shared_ptr<ARDOUR::Port>(_output_port)->name()));
130                 AudioEngine::instance()->unregister_port (_output_port);
131                 _output_port.reset ();
132         }
133
134         tear_down_gui ();
135 }
136
137 void
138 FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
139 {
140         switch (tb->controller_number) {
141         case Mute:
142                 cerr << "Mute\n";
143                 break;
144         case Solo:
145                 cerr << "Solo\n";
146                 break;
147         case Rec:
148                 cerr << "Rec\n";
149                 break;
150         case Left:
151                 cerr << "Left\n";
152                 break;
153         case Bank:
154                 cerr << "Bank\n";
155                 break;
156         case Right:
157                 cerr << "Right\n";
158                 break;
159         case Output:
160                 cerr << "Output\n";
161                 break;
162         case Read:
163                 cerr << "Read\n";
164                 break;
165         case Write:
166                 cerr << "Write\n";
167                 break;
168         case Touch:
169                 cerr << "Touch\n";
170                 break;
171         case Off:
172                 cerr << "Off\n";
173                 break;
174         case Mix:
175                 cerr << "Mix\n";
176                 break;
177         case Proj:
178                 cerr << "Proj\n";
179                 break;
180         case Trns:
181                 cerr << "Trns\n";
182                 break;
183         case Undo:
184                 cerr << "Undo\n";
185                 break;
186         case Shift:
187                 cerr << "Shift\n";
188                 break;
189         case Punch:
190                 cerr << "Punch\n";
191                 break;
192         case User:
193                 cerr << "User\n";
194                 break;
195         case Loop:
196                 cerr << "Loop\n";
197                 break;
198         case Rewind:
199                 cerr << "Rewind\n";
200                 break;
201         case Ffwd:
202                 cerr << "Ffwd\n";
203                 break;
204         case Stop:
205                 cerr << "Stop\n";
206                 break;
207         case Play:
208                 cerr << "Play\n";
209                 break;
210         case RecEnable:
211                 cerr << "RecEnable\n";
212                 break;
213         case Fader:
214                 cerr << "Fader touch\n";
215                 break;
216         default:
217                 cerr << "eh?\n";
218         }
219
220         /* send feedback to turn on the LED */
221
222         MIDI::byte buf[3];
223         buf[0] = 0xa0;
224         buf[1] = tb->controller_number;
225         buf[2] = tb->value;
226
227         _output_port->write (buf, 3, 0);
228 }
229
230 void
231 FaderPort::encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb)
232 {
233         if (pb < 8192) {
234                 cerr << "Encoder right\n";
235         } else {
236                 cerr << "Encoder left\n";
237         }
238 }
239
240 void
241 FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
242 {
243         bool was_fader = false;
244
245         if (tb->controller_number == 0x0) {
246                 fader_msb = tb->value;
247                 was_fader = true;
248         } else if (tb->controller_number == 0x20) {
249                 fader_lsb = tb->value;
250                 was_fader = true;
251         }
252
253         if (was_fader) {
254                 cerr << "Fader now at " << ((fader_msb<<7)|fader_lsb) << endl;
255         }
256 }
257
258 void
259 FaderPort::sysex_handler (MIDI::Parser &p, MIDI::byte *buf, size_t sz)
260 {
261         if (sz < 17) {
262                 return;
263         }
264
265         if (buf[2] == 0x7f &&
266             buf[3] == 0x06 &&
267             buf[4] == 0x02 &&
268             buf[5] == 0x0 &&
269             buf[6] == 0x1 &&
270             buf[7] == 0x06 &&
271             buf[8] == 0x02 &&
272             buf[9] == 0x0 &&
273             buf[10] == 0x01 &&
274             buf[11] == 0x0) {
275                 _device_active = true;
276
277                 cerr << "FaderPort identified\n";
278
279                 /* put it into native mode */
280
281                 MIDI::byte native[3];
282                 native[0] = 0x91;
283                 native[1] = 0x00;
284                 native[2] = 0x64;
285
286                 _output_port->write (native, 3, 0);
287         }
288 }
289
290 int
291 FaderPort::set_active (bool /*yn*/)
292 {
293         return 0;
294 }
295
296 void
297 FaderPort::set_feedback_interval (microseconds_t ms)
298 {
299         _feedback_interval = ms;
300 }
301
302 void
303 FaderPort::send_feedback ()
304 {
305         /* This is executed in RT "process" context", so no blocking calls
306          */
307
308         if (!do_feedback) {
309                 return;
310         }
311
312         microseconds_t now = get_microseconds ();
313
314         if (last_feedback_time != 0) {
315                 if ((now - last_feedback_time) < _feedback_interval) {
316                         return;
317                 }
318         }
319
320         last_feedback_time = now;
321 }
322
323 bool
324 FaderPort::midi_input_handler (Glib::IOCondition ioc, boost::shared_ptr<ARDOUR::AsyncMIDIPort> port)
325 {
326         DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on  %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
327
328         if (ioc & ~IO_IN) {
329                 return false;
330         }
331
332         if (ioc & IO_IN) {
333
334                 if (port) {
335                         port->clear ();
336                 }
337
338                 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
339                 framepos_t now = session->engine().sample_time();
340                 port->parse (now);
341         }
342
343         return true;
344 }
345
346
347 XMLNode&
348 FaderPort::get_state ()
349 {
350         XMLNode& node (ControlProtocol::get_state());
351
352         XMLNode* child;
353
354         child = new XMLNode (X_("Input"));
355         child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_input_port)->get_state());
356         node.add_child_nocopy (*child);
357
358
359         child = new XMLNode (X_("Output"));
360         child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
361         node.add_child_nocopy (*child);
362
363         return node;
364 }
365
366 int
367 FaderPort::set_state (const XMLNode& node, int version)
368 {
369         XMLNodeList nlist;
370         XMLNodeConstIterator niter;
371         XMLNode const* child;
372
373         if (ControlProtocol::set_state (node, version)) {
374                 return -1;
375         }
376
377         if ((child = node.child (X_("Input"))) != 0) {
378                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
379                 if (portnode) {
380                         boost::shared_ptr<ARDOUR::Port>(_input_port)->set_state (*portnode, version);
381                 }
382         }
383
384         if ((child = node.child (X_("Output"))) != 0) {
385                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
386                 if (portnode) {
387                         boost::shared_ptr<ARDOUR::Port>(_output_port)->set_state (*portnode, version);
388                 }
389         }
390
391         return 0;
392 }
393
394 int
395 FaderPort::set_feedback (bool yn)
396 {
397         do_feedback = yn;
398         last_feedback_time = 0;
399         return 0;
400 }
401
402 bool
403 FaderPort::get_feedback () const
404 {
405         return do_feedback;
406 }
407
408 void
409 FaderPort::set_current_bank (uint32_t b)
410 {
411         _current_bank = b;
412 //      reset_controllables ();
413 }
414
415 void
416 FaderPort::next_bank ()
417 {
418         _current_bank++;
419 //      reset_controllables ();
420 }
421
422 void
423 FaderPort::prev_bank()
424 {
425         if (_current_bank) {
426                 _current_bank--;
427 //              reset_controllables ();
428         }
429 }
430
431 void
432 FaderPort::set_motorised (bool m)
433 {
434         _motorised = m;
435 }
436
437 void
438 FaderPort::set_threshold (int t)
439 {
440         _threshold = t;
441 }
442
443 void
444 FaderPort::reset_controllables ()
445 {
446 }
447
448 bool
449 FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
450 {
451         if (!_input_port || !_output_port) {
452                 return false;
453         }
454
455         string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
456         string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
457
458         std::cerr << "Checking " << name1 << (yn ? " + " : " - " ) << name2 << " vs. " << ni << " & " << no << std::endl;
459
460         if (ni == name1 || ni == name2) {
461                 if (yn) {
462                         connection_state |= InputConnected;
463                 } else {
464                         connection_state &= ~InputConnected;
465                 }
466         } else if (no == name1 || no == name2) {
467                 if (yn) {
468                         connection_state |= OutputConnected;
469                 } else {
470                         connection_state &= ~OutputConnected;
471                 }
472         } else {
473                 /* not our ports */
474                 return false;
475         }
476
477         if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
478
479                 /* XXX this is a horrible hack. Without a short sleep here,
480                    something prevents the device wakeup messages from being
481                    sent and/or the responses from being received.
482                 */
483
484                 g_usleep (100000);
485                 connected ();
486
487         } else {
488                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
489                 _device_active = false;
490         }
491
492         return true; /* connection status changed */
493 }
494
495 void
496 FaderPort::connected ()
497 {
498         std::cerr << "faderport connected\n";
499
500         /* send device inquiry */
501
502         MIDI::byte buf[6];
503
504         buf[0] = 0xf0;
505         buf[1] = 0x7e;
506         buf[2] = 0x7f;
507         buf[3] = 0x06;
508         buf[4] = 0x01;
509         buf[5] = 0xf7;
510
511         _output_port->write (buf, 6, 0);
512 }