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