Don't handle possible phase change if no audio channels in mackie control
[ardour.git] / libs / surfaces / mackie / strip.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3         Copyright (C) 2012 Paul Davis
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 2 of the License, or
8         (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to the Free Software
17         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <sstream>
21 #include <stdint.h>
22 #include "strip.h"
23
24 #include <sys/time.h>
25
26 #include <glibmm/convert.h>
27
28 #include "midi++/port.h"
29
30 #include "pbd/compose.h"
31 #include "pbd/convert.h"
32
33 #include "ardour/amp.h"
34 #include "ardour/bundle.h"
35 #include "ardour/debug.h"
36 #include "ardour/midi_ui.h"
37 #include "ardour/meter.h"
38 #include "ardour/pannable.h"
39 #include "ardour/panner.h"
40 #include "ardour/panner_shell.h"
41 #include "ardour/rc_configuration.h"
42 #include "ardour/route.h"
43 #include "ardour/session.h"
44 #include "ardour/send.h"
45 #include "ardour/track.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/user_bundle.h"
48
49 #include "mackie_control_protocol.h"
50 #include "surface_port.h"
51 #include "surface.h"
52 #include "button.h"
53 #include "led.h"
54 #include "pot.h"
55 #include "fader.h"
56 #include "jog.h"
57 #include "meter.h"
58
59 using namespace std;
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace ArdourSurface;
63 using namespace Mackie;
64
65 #ifndef timeradd /// only avail with __USE_BSD
66 #define timeradd(a,b,result)                         \
67   do {                                               \
68     (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;    \
69     (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
70     if ((result)->tv_usec >= 1000000)                \
71     {                                                \
72       ++(result)->tv_sec;                            \
73       (result)->tv_usec -= 1000000;                  \
74     }                                                \
75   } while (0)
76 #endif
77
78 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
79
80 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
81         : Group (name)
82         , _solo (0)
83         , _recenable (0)
84         , _mute (0)
85         , _select (0)
86         , _vselect (0)
87         , _fader_touch (0)
88         , _vpot (0)
89         , _fader (0)
90         , _meter (0)
91         , _index (index)
92         , _surface (&s)
93         , _controls_locked (false)
94         , _transport_is_rolling (false)
95         , _metering_active (true)
96         , _block_vpot_mode_redisplay_until (0)
97         , _block_screen_redisplay_until (0)
98         , _pan_mode (PanAzimuthAutomation)
99         , _trim_mode (TrimAutomation)
100         , _last_gain_position_written (-1.0)
101         , _last_pan_azi_position_written (-1.0)
102         , _last_pan_width_position_written (-1.0)
103         , _last_trim_position_written (-1.0)
104         , redisplay_requests (256)
105 {
106         _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
107         _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
108
109         if (s.mcp().device_info().has_meters()) {
110                 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
111         }
112
113         for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
114                 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
115                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
116                                                                    _surface->number(), index, Button::id_to_name (bb->bid()),
117                                                                    bb->id(), b->second.base_id));
118         }
119 }
120
121 Strip::~Strip ()
122 {
123         /* surface is responsible for deleting all controls */
124 }
125
126 void
127 Strip::add (Control & control)
128 {
129         Button* button;
130
131         Group::add (control);
132
133         /* fader, vpot, meter were all set explicitly */
134
135         if ((button = dynamic_cast<Button*>(&control)) != 0) {
136                 switch (button->bid()) {
137                 case Button::RecEnable:
138                         _recenable = button;
139                         break;
140                 case Button::Mute:
141                         _mute = button;
142                         break;
143                 case Button::Solo:
144                         _solo = button;
145                         break;
146                 case Button::Select:
147                         _select = button;
148                         break;
149                 case Button::VSelect:
150                         _vselect = button;
151                         break;
152                 case Button::FaderTouch:
153                         _fader_touch = button;
154                         break;
155                 default:
156                         break;
157                 }
158         }
159 }
160
161 void
162 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
163 {
164         if (_controls_locked) {
165                 return;
166         }
167
168         route_connections.drop_connections ();
169
170         _solo->set_control (boost::shared_ptr<AutomationControl>());
171         _mute->set_control (boost::shared_ptr<AutomationControl>());
172         _select->set_control (boost::shared_ptr<AutomationControl>());
173         _recenable->set_control (boost::shared_ptr<AutomationControl>());
174         _fader->set_control (boost::shared_ptr<AutomationControl>());
175         _vpot->set_control (boost::shared_ptr<AutomationControl>());
176
177         _route = r;
178
179         control_by_parameter.clear ();
180
181         control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
182         control_by_parameter[PanWidthAutomation] = (Control*) 0;
183         control_by_parameter[PanElevationAutomation] = (Control*) 0;
184         control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
185         control_by_parameter[PanLFEAutomation] = (Control*) 0;
186         control_by_parameter[GainAutomation] = (Control*) 0;
187         control_by_parameter[TrimAutomation] = (Control*) 0;
188         control_by_parameter[PhaseAutomation] = (Control*) 0;
189
190         reset_saved_values ();
191
192         if (!r) {
193                 zero ();
194                 return;
195         }
196
197         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
198                                                            _surface->number(), _index, _route->name()));
199
200         _solo->set_control (_route->solo_control());
201         _mute->set_control (_route->mute_control());
202
203         _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
204         _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
205
206         _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
207
208         if (_route->trim() && route()->trim()->active()) {
209                 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
210         }
211
212         if (_route->phase_invert().size()) {
213                 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
214                 _route->phase_control()->set_channel(0);
215         }
216
217         boost::shared_ptr<Pannable> pannable = _route->pannable();
218
219         if (pannable && _route->panner()) {
220                 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
221                 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
222         }
223         _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
224         _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
225
226         boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
227
228         if (trk) {
229                 _recenable->set_control (trk->rec_enable_control());
230                 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
231
232
233         }
234
235         // TODO this works when a currently-banked route is made inactive, but not
236         // when a route is activated which should be currently banked.
237
238         _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
239         _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
240
241         /* setup legal VPot modes for this route */
242
243         possible_pot_parameters.clear();
244
245         if (pannable) {
246                 boost::shared_ptr<Panner> panner = _route->panner();
247                 if (panner) {
248                         set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
249                         set<Evoral::Parameter>::iterator a;
250
251                         if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
252                                 possible_pot_parameters.push_back (PanAzimuthAutomation);
253                         }
254
255                         if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
256                                 possible_pot_parameters.push_back (PanWidthAutomation);
257                         }
258                 }
259         }
260
261         if (_route->trim() && route()->trim()->active()) {
262                 possible_pot_parameters.push_back (TrimAutomation);
263         }
264
265         possible_trim_parameters.clear();
266
267         if (_route->trim() && route()->trim()->active()) {
268                 possible_trim_parameters.push_back (TrimAutomation);
269                 _trim_mode = TrimAutomation;
270         }
271
272         if (_route->phase_invert().size()) {
273                 possible_trim_parameters.push_back (PhaseAutomation);
274                 if (_trim_mode != TrimAutomation) {
275                         _trim_mode = PhaseAutomation;
276                 }
277         }
278
279         /* Update */
280         _pan_mode = PanAzimuthAutomation;
281         potmode_changed (false);
282         notify_all ();
283
284 }
285
286 void
287 Strip::notify_all()
288 {
289         if (!_route) {
290                 zero ();
291                 return;
292         }
293
294         notify_solo_changed ();
295         notify_mute_changed ();
296         notify_gain_changed ();
297         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
298         notify_panner_azi_changed ();
299         notify_panner_width_changed ();
300         notify_record_enable_changed ();
301         notify_trim_changed ();
302         notify_phase_changed ();
303 }
304
305 void
306 Strip::notify_solo_changed ()
307 {
308         if (_route && _solo) {
309                 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
310         }
311 }
312
313 void
314 Strip::notify_mute_changed ()
315 {
316         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
317         if (_route && _mute) {
318                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
319                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
320
321                 _surface->write (_mute->set_state (_route->muted() ? on : off));
322         }
323 }
324
325 void
326 Strip::notify_record_enable_changed ()
327 {
328         if (_route && _recenable)  {
329                 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
330         }
331 }
332
333 void
334 Strip::notify_active_changed ()
335 {
336         _surface->mcp().refresh_current_bank();
337 }
338
339 void
340 Strip::notify_route_deleted ()
341 {
342         _surface->mcp().refresh_current_bank();
343 }
344
345 void
346 Strip::notify_gain_changed (bool force_update)
347 {
348         if (_route) {
349
350                 Control* control;
351
352                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
353                         control = _vpot;
354                 } else {
355                         control = _fader;
356                 }
357
358                 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
359
360                 float gain_coefficient = ac->get_value();
361                 float normalized_position = ac->internal_to_interface (gain_coefficient);
362
363
364                 if (force_update || normalized_position != _last_gain_position_written) {
365
366                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
367                                 if (!control->in_use()) {
368                                         _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
369                                 }
370                                 queue_parameter_display (GainAutomation, gain_coefficient);
371                         } else {
372                                 if (!control->in_use()) {
373                                         _surface->write (_fader->set_position (normalized_position));
374                                 }
375                                 queue_parameter_display (GainAutomation, gain_coefficient);
376                         }
377
378                         _last_gain_position_written = normalized_position;
379                 }
380         }
381 }
382
383 void
384 Strip::notify_trim_changed (bool force_update)
385 {
386         if (_route) {
387
388                 if (!_route->trim() || !route()->trim()->active()) {
389                         _surface->write (_vpot->zero());
390                         return;
391                 }
392                 Control* control = 0;
393                 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
394
395                 if (i == control_by_parameter.end()) {
396                         return;
397                 }
398
399                 control = i->second;
400
401                 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
402
403                 float gain_coefficient = ac->get_value();
404                 float normalized_position = ac->internal_to_interface (gain_coefficient);
405
406                 if (force_update || normalized_position != _last_trim_position_written) {
407                         if (control == _fader) {
408                                 if (!_fader->in_use()) {
409                                         _surface->write (_fader->set_position (normalized_position));
410                                         queue_parameter_display (TrimAutomation, gain_coefficient);
411                                 }
412                         } else if (control == _vpot) {
413                                 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
414                                 queue_parameter_display (TrimAutomation, gain_coefficient);
415                         }
416                         _last_trim_position_written = normalized_position;
417                 }
418         }
419 }
420
421 void
422 Strip::notify_phase_changed (bool force_update)
423 {
424         if (_route) {
425                 if (!_route->phase_invert().size()) {
426                         _surface->write (_vpot->zero());
427                         return;
428                 }
429
430                 Control* control = 0;
431                 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
432
433                 if (i == control_by_parameter.end()) {
434                         return;
435                 }
436
437                 control = i->second;
438
439                 float normalized_position = _route->phase_control()->get_value();
440
441                 if (control == _fader) {
442                         if (!_fader->in_use()) {
443                                 _surface->write (_fader->set_position (normalized_position));
444                                 queue_parameter_display (PhaseAutomation, normalized_position);
445                         }
446                 } else if (control == _vpot) {
447                         _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
448                         queue_parameter_display (PhaseAutomation, normalized_position);
449                 }
450         }
451 }
452
453 void
454 Strip::notify_property_changed (const PropertyChange& what_changed)
455 {
456         if (!what_changed.contains (ARDOUR::Properties::name)) {
457                 return;
458         }
459
460         show_route_name ();
461 }
462
463 void
464 Strip::show_route_name ()
465 {
466         if (!_route) {
467                 return;
468         }
469         string line1;
470         string fullname = _route->name();
471
472         if (fullname.length() <= 6) {
473                 line1 = fullname;
474         } else {
475                 line1 = PBD::short_version (fullname, 6);
476         }
477
478         _surface->write (display (0, line1));
479 }
480
481 void
482 Strip::notify_panner_azi_changed (bool force_update)
483 {
484         if (_route) {
485
486                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
487
488                 boost::shared_ptr<Pannable> pannable = _route->pannable();
489
490                 if (!pannable || !_route->panner()) {
491                         _surface->write (_vpot->zero());
492                         return;
493                 }
494
495                 Control* control = 0;
496                 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
497
498                 if (i == control_by_parameter.end()) {
499                         return;
500                 }
501
502                 control = i->second;
503
504                 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
505
506                 if (force_update || pos != _last_pan_azi_position_written) {
507
508                         if (control == _fader) {
509                                 if (!_fader->in_use()) {
510                                         _surface->write (_fader->set_position (pos));
511                                         queue_parameter_display (PanAzimuthAutomation, pos);
512                                 }
513                         } else if (control == _vpot) {
514                                 _surface->write (_vpot->set (pos, true, Pot::dot));
515                                 queue_parameter_display (PanAzimuthAutomation, pos);
516                         }
517
518                         _last_pan_azi_position_written = pos;
519                 }
520         }
521 }
522
523 void
524 Strip::notify_panner_width_changed (bool force_update)
525 {
526         if (_route) {
527
528                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
529
530                 boost::shared_ptr<Pannable> pannable = _route->pannable();
531
532                 if (!pannable || !_route->panner()) {
533                         _surface->write (_vpot->zero());
534                         return;
535                 }
536
537                 Control* control = 0;
538                 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
539
540                 if (i == control_by_parameter.end()) {
541                         return;
542                 }
543
544                 control = i->second;
545
546                 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
547
548                 if (force_update || pos != _last_pan_azi_position_written) {
549
550                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
551
552                                 if (control == _fader) {
553                                         if (!control->in_use()) {
554                                                 _surface->write (_fader->set_position (pos));
555                                                 queue_parameter_display (PanWidthAutomation, pos);
556                                         }
557                                 }
558
559                         } else if (control == _vpot) {
560                                 _surface->write (_vpot->set (pos, true, Pot::spread));
561                                 queue_parameter_display (PanWidthAutomation, pos);
562                         }
563
564                         _last_pan_azi_position_written = pos;
565                 }
566         }
567 }
568
569 void
570 Strip::select_event (Button&, ButtonState bs)
571 {
572         DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
573
574         if (bs == press) {
575
576                 int ms = _surface->mcp().main_modifier_state();
577
578                 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
579                         _controls_locked = !_controls_locked;
580                         _surface->write (display (1,_controls_locked ?  "Locked" : "Unlock"));
581                         block_vpot_mode_display_for (1000);
582                         return;
583                 }
584
585                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
586                         /* reset to default */
587                         boost::shared_ptr<AutomationControl> ac = _fader->control ();
588                         if (ac) {
589                                 ac->set_value (ac->normal());
590                         }
591                         return;
592                 }
593
594                 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
595                 _surface->mcp().add_down_select_button (_surface->number(), _index);
596                 _surface->mcp().select_range ();
597
598         } else {
599                 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
600                 _surface->mcp().remove_down_select_button (_surface->number(), _index);
601         }
602 }
603
604 void
605 Strip::vselect_event (Button&, ButtonState bs)
606 {
607         if (bs == press) {
608
609                 int ms = _surface->mcp().main_modifier_state();
610
611                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
612
613                         boost::shared_ptr<AutomationControl> ac = _vpot->control ();
614
615                         if (ac) {
616
617                                 /* reset to default/normal value */
618                                 ac->set_value (ac->normal());
619                         }
620
621                 }  else {
622
623                         DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
624                         next_pot_mode ();
625                 }
626
627         }
628 }
629
630 void
631 Strip::fader_touch_event (Button&, ButtonState bs)
632 {
633         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
634
635         if (bs == press) {
636
637                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
638
639                 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
640                         if (ac) {
641                                 ac->set_value (ac->normal());
642                         }
643                 } else {
644
645                         _fader->set_in_use (true);
646                         _fader->start_touch (_surface->mcp().transport_frame());
647
648                         if (ac) {
649                                 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
650                         }
651                 }
652
653         } else {
654
655                 _fader->set_in_use (false);
656                 _fader->stop_touch (_surface->mcp().transport_frame(), true);
657
658         }
659 }
660
661
662 void
663 Strip::handle_button (Button& button, ButtonState bs)
664 {
665         boost::shared_ptr<AutomationControl> control;
666
667         if (bs == press) {
668                 button.set_in_use (true);
669         } else {
670                 button.set_in_use (false);
671         }
672
673         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
674
675         switch (button.bid()) {
676         case Button::Select:
677                 select_event (button, bs);
678                 break;
679
680         case Button::VSelect:
681                 vselect_event (button, bs);
682                 break;
683
684         case Button::FaderTouch:
685                 fader_touch_event (button, bs);
686                 break;
687
688         default:
689                 if ((control = button.control ())) {
690                         if (bs == press) {
691                                 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
692                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
693
694                                 float new_value;
695                                 int ms = _surface->mcp().main_modifier_state();
696
697                                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
698                                         /* reset to default/normal value */
699                                         new_value = control->normal();
700                                 } else {
701                                         new_value = control->get_value() ? 0.0 : 1.0;
702                                 }
703
704                                 /* get all controls that either have their
705                                  * button down or are within a range of
706                                  * several down buttons
707                                  */
708
709                                 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
710
711
712                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
713                                                                             controls.size(), control->parameter().type(), new_value));
714
715                                 /* apply change */
716
717                                 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
718                                         (*c)->set_value (new_value);
719                                 }
720
721                         } else {
722                                 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
723                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
724                         }
725                 }
726                 break;
727         }
728 }
729
730 void
731 Strip::queue_parameter_display (AutomationType type, float val)
732 {
733         RedisplayRequest req;
734
735         req.type = type;
736         req.val = val;
737
738         redisplay_requests.write (&req, 1);
739 }
740
741 void
742 Strip::do_parameter_display (AutomationType type, float val)
743 {
744         bool screen_hold = false;
745
746         switch (type) {
747         case GainAutomation:
748                 if (val == 0.0) {
749                         _surface->write (display (1, " -inf "));
750                 } else {
751                         char buf[16];
752                         float dB = accurate_coefficient_to_dB (val);
753                         snprintf (buf, sizeof (buf), "%6.1f", dB);
754                         _surface->write (display (1, buf));
755                         screen_hold = true;
756                 }
757                 break;
758
759         case PanAzimuthAutomation:
760                 if (_route) {
761                         boost::shared_ptr<Pannable> p = _route->pannable();
762                         if (p && _route->panner()) {
763                                 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
764                                 _surface->write (display (1, str));
765                                 screen_hold = true;
766                         }
767                 }
768                 break;
769
770         case PanWidthAutomation:
771                 if (_route) {
772                         char buf[16];
773                         snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
774                         _surface->write (display (1, buf));
775                         screen_hold = true;
776                 }
777                 break;
778
779         case TrimAutomation:
780                 if (_route) {
781                         char buf[16];
782                         float dB = accurate_coefficient_to_dB (val);
783                         snprintf (buf, sizeof (buf), "%6.1f", dB);
784                         _surface->write (display (1, buf));
785                         screen_hold = true;
786                 }
787                 break;
788
789         case PhaseAutomation:
790                 if (_route) {
791                         if (_route->phase_control()->get_value() < 0.5) {
792                                 _surface->write (display (1, "Normal"));
793                         } else {
794                                 _surface->write (display (1, "Invert"));
795                         }
796                         screen_hold = true;
797                 }
798                 break;
799
800         default:
801                 break;
802         }
803
804         if (screen_hold) {
805                 block_vpot_mode_display_for (1000);
806         }
807 }
808
809 void
810 Strip::handle_fader_touch (Fader& fader, bool touch_on)
811 {
812         if (touch_on) {
813                 fader.start_touch (_surface->mcp().transport_frame());
814         } else {
815                 fader.stop_touch (_surface->mcp().transport_frame(), false);
816         }
817 }
818
819 void
820 Strip::handle_fader (Fader& fader, float position)
821 {
822         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
823         boost::shared_ptr<AutomationControl> ac = fader.control();
824         if (!ac) {
825                 return;
826         }
827
828         fader.set_value (position);
829
830         /* From the Mackie Control MIDI implementation docs:
831
832            In order to ensure absolute synchronization with the host software,
833            Mackie Control uses a closed-loop servo system for the faders,
834            meaning the faders will always move to their last received position.
835            When a host receives a Fader Position Message, it must then
836            re-transmit that message to the Mackie Control or else the faders
837            will return to their last position.
838         */
839
840         _surface->write (fader.set_position (position));
841 }
842
843 void
844 Strip::handle_pot (Pot& pot, float delta)
845 {
846         /* Pots only emit events when they move, not when they
847            stop moving. So to get a stop event, we need to use a timeout.
848         */
849
850         boost::shared_ptr<AutomationControl> ac = pot.control();
851         if (!ac) {
852                 return;
853         }
854         double p = pot.get_value ();
855         p += delta;
856         p = max (ac->lower(), p);
857         p = min (ac->upper(), p);
858         pot.set_value (p);
859 }
860
861 void
862 Strip::periodic (ARDOUR::microseconds_t now)
863 {
864         bool reshow_vpot_mode = false;
865         bool reshow_name = false;
866
867         if (!_route) {
868                 return;
869         }
870
871         if (_block_screen_redisplay_until >= now) {
872                 if (_surface->mcp().device_info().has_separate_meters()) {
873                         goto meters;
874                 }
875                 /* no drawing here, for now */
876                 return;
877
878         } else if (_block_screen_redisplay_until) {
879
880                 /* timeout reached, reset */
881
882                 _block_screen_redisplay_until = 0;
883                 reshow_vpot_mode = true;
884                 reshow_name = true;
885         }
886
887         if (_block_vpot_mode_redisplay_until >= now) {
888                 return;
889         } else if (_block_vpot_mode_redisplay_until) {
890
891                 /* timeout reached, reset */
892
893                 _block_vpot_mode_redisplay_until = 0;
894                 reshow_vpot_mode = true;
895         }
896
897         if (reshow_name) {
898                 show_route_name ();
899         }
900
901         if (reshow_vpot_mode) {
902                 return_to_vpot_mode_display ();
903         } else {
904                 /* no point doing this if we just switched back to vpot mode
905                    display */
906                 update_automation ();
907         }
908
909   meters:
910         update_meter ();
911 }
912
913 void
914 Strip::redisplay (ARDOUR::microseconds_t now)
915 {
916         RedisplayRequest req;
917         bool have_request = false;
918
919         while (redisplay_requests.read (&req, 1) == 1) {
920                 /* read them all */
921                 have_request = true;
922         }
923
924         if (_block_screen_redisplay_until >= now) {
925                 return;
926         }
927
928         if (have_request) {
929                 do_parameter_display (req.type, req.val);
930         }
931 }
932
933 void
934 Strip::update_automation ()
935 {
936         ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
937
938         if (gain_state == Touch || gain_state == Play) {
939                 notify_gain_changed (false);
940         }
941
942         if (_route->panner()) {
943                 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
944                 if (panner_state == Touch || panner_state == Play) {
945                         notify_panner_azi_changed (false);
946                         notify_panner_width_changed (false);
947                 }
948         }
949         if (_route->trim() && route()->trim()->active()) {
950                 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
951                 if (trim_state == Touch || trim_state == Play) {
952                         notify_trim_changed (false);
953                 }
954         }
955 }
956
957 void
958 Strip::update_meter ()
959 {
960         if (_meter && _transport_is_rolling && _metering_active) {
961                 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
962                 _meter->send_update (*_surface, dB);
963         }
964 }
965
966 void
967 Strip::zero ()
968 {
969         for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
970                 _surface->write ((*it)->zero ());
971         }
972
973         _surface->write (blank_display (0));
974         _surface->write (blank_display (1));
975 }
976
977 MidiByteArray
978 Strip::blank_display (uint32_t line_number)
979 {
980         return display (line_number, string());
981 }
982
983 MidiByteArray
984 Strip::display (uint32_t line_number, const std::string& line)
985 {
986         assert (line_number <= 1);
987
988         MidiByteArray retval;
989
990         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
991
992         // sysex header
993         retval << _surface->sysex_hdr();
994
995         // code for display
996         retval << 0x12;
997         // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
998         retval << (_index * 7 + (line_number * 0x38));
999
1000         // ascii data to display. @param line is UTF-8
1001         string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1002         string::size_type len = ascii.length();
1003         if (len > 6) {
1004                 ascii = ascii.substr (0, 6);
1005                 len = 6;
1006         }
1007         retval << ascii;
1008         // pad with " " out to 6 chars
1009         for (int i = len; i < 6; ++i) {
1010                 retval << ' ';
1011         }
1012
1013         // column spacer, unless it's the right-hand column
1014         if (_index < 7) {
1015                 retval << ' ';
1016         }
1017
1018         // sysex trailer
1019         retval << MIDI::eox;
1020
1021         return retval;
1022 }
1023
1024 void
1025 Strip::lock_controls ()
1026 {
1027         _controls_locked = true;
1028 }
1029
1030 void
1031 Strip::unlock_controls ()
1032 {
1033         _controls_locked = false;
1034 }
1035
1036 void
1037 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1038 {
1039         for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1040                 if ((*i) == _route) {
1041                         _surface->write (_select->set_state (on));
1042                         return;
1043                 }
1044         }
1045
1046         _surface->write (_select->set_state (off));
1047 }
1048
1049 string
1050 Strip::vpot_mode_string () const
1051 {
1052         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1053
1054         if (!ac) {
1055                 return string();
1056         }
1057
1058         switch (ac->parameter().type()) {
1059         case GainAutomation:
1060                 return "Fader";
1061         case TrimAutomation:
1062                 return "Trim";
1063         case PhaseAutomation:
1064                 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1065         case PanAzimuthAutomation:
1066                 return "Pan";
1067         case PanWidthAutomation:
1068                 return "Width";
1069         case PanElevationAutomation:
1070                 return "Elev";
1071         case PanFrontBackAutomation:
1072                 return "F/Rear";
1073         case PanLFEAutomation:
1074                 return "LFE";
1075         }
1076
1077         return "???";
1078 }
1079
1080  void
1081 Strip::potmode_changed (bool notify)
1082 {
1083         if (!_route) {
1084                 return;
1085         }
1086
1087         // WIP
1088         int pm = _surface->mcp().pot_mode();
1089         switch (pm) {
1090         case MackieControlProtocol::Pan:
1091                 // This needs to set current pan mode (azimuth or width... or whatever)
1092                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1093                 set_vpot_parameter (_pan_mode);
1094                 break;
1095         case MackieControlProtocol::Trim:
1096                 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1097                 set_vpot_parameter (_trim_mode);
1098                 break;
1099         case MackieControlProtocol::Send:
1100                 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1101                 set_vpot_parameter (SendAutomation);
1102                 break;
1103         }
1104
1105         if (notify) {
1106                 notify_all ();
1107         }
1108 }
1109
1110 void
1111 Strip::block_screen_display_for (uint32_t msecs)
1112 {
1113         _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1114 }
1115
1116 void
1117 Strip::block_vpot_mode_display_for (uint32_t msecs)
1118 {
1119         _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1120 }
1121
1122 void
1123 Strip::return_to_vpot_mode_display ()
1124 {
1125         /* returns the second line of the two-line per-strip display
1126            back the mode where it shows what the VPot controls.
1127         */
1128
1129         if (_route) {
1130                 _surface->write (display (1, vpot_mode_string()));
1131         } else {
1132                 _surface->write (blank_display (1));
1133         }
1134 }
1135
1136 void
1137 Strip::next_pot_mode ()
1138 {
1139         vector<Evoral::Parameter>::iterator i;
1140
1141         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1142                 /* do not change vpot mode while in flipped mode */
1143                 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1144                 _surface->write (display (1, "Flip"));
1145                 block_vpot_mode_display_for (1000);
1146                 return;
1147         }
1148
1149
1150         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1151
1152         if (!ac) {
1153                 return;
1154         }
1155         if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1156                 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1157                         return;
1158                 }
1159
1160                 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1161                         if ((*i) == ac->parameter()) {
1162                                 break;
1163                         }
1164                 }
1165
1166                 /* move to the next mode in the list, or back to the start (which will
1167                 also happen if the current mode is not in the current pot mode list)
1168                 */
1169
1170                 if (i != possible_pot_parameters.end()) {
1171                         ++i;
1172                 }
1173
1174                 if (i == possible_pot_parameters.end()) {
1175                         i = possible_pot_parameters.begin();
1176                 }
1177                 set_vpot_parameter (*i);
1178         } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1179                                 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1180                         return;
1181                 }
1182
1183                 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1184                         if ((*i) == ac->parameter()) {
1185                                 break;
1186                         }
1187                 }
1188                 if ((*i).type() == PhaseAutomation && _route->phase_invert().size() > 1) {
1189                         // There are more than one channel of phase
1190                         if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1191                                 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1192                                 set_vpot_parameter (*i);
1193                                 return;
1194                         } else {
1195                                 _route->phase_control()->set_channel(0);
1196                         }
1197                 }
1198                 /* move to the next mode in the list, or back to the start (which will
1199                 also happen if the current mode is not in the current pot mode list)
1200                 */
1201
1202                 if (i != possible_trim_parameters.end()) {
1203                         ++i;
1204                 }
1205
1206                 if (i == possible_trim_parameters.end()) {
1207                         i = possible_trim_parameters.begin();
1208                 }
1209                 set_vpot_parameter (*i);
1210         }
1211
1212 }
1213
1214 void
1215 Strip::set_vpot_parameter (Evoral::Parameter p)
1216 {
1217         boost::shared_ptr<Pannable> pannable;
1218
1219         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p.type()));
1220
1221         reset_saved_values ();
1222
1223         /* unset any mapping between the vpot and any existing parameters */
1224
1225         for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1226
1227                 if (i != control_by_parameter.end() && i->second == _vpot) {
1228                         i->second = 0;
1229                 }
1230         }
1231
1232         switch (p.type()) {
1233         case PanAzimuthAutomation:
1234                 _pan_mode = PanAzimuthAutomation;
1235                 pannable = _route->pannable ();
1236                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1237                         /* gain to vpot, pan azi to fader */
1238                         _vpot->set_control (_route->gain_control());
1239                         control_by_parameter[GainAutomation] = _vpot;
1240                         if (pannable) {
1241                                 _fader->set_control (pannable->pan_azimuth_control);
1242                                 control_by_parameter[PanAzimuthAutomation] = _fader;
1243                         } else {
1244                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1245                                 control_by_parameter[PanAzimuthAutomation] = 0;
1246                         }
1247                 } else {
1248                         /* gain to fader, pan azi to vpot */
1249                         _fader->set_control (_route->gain_control());
1250                         control_by_parameter[GainAutomation] = _fader;
1251                         if (pannable) {
1252                                 _vpot->set_control (pannable->pan_azimuth_control);
1253                                 control_by_parameter[PanAzimuthAutomation] = _vpot;
1254                         } else {
1255                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1256                                 control_by_parameter[PanAzimuthAutomation] = 0;
1257                         }
1258                 }
1259                 break;
1260         case PanWidthAutomation:
1261                 _pan_mode = PanWidthAutomation;
1262                 pannable = _route->pannable ();
1263                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1264                         /* gain to vpot, pan width to fader */
1265                         _vpot->set_control (_route->gain_control());
1266                         control_by_parameter[GainAutomation] = _vpot;
1267                         if (pannable) {
1268                                 _fader->set_control (pannable->pan_width_control);
1269                                 control_by_parameter[PanWidthAutomation] = _fader;
1270                         } else {
1271                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1272                                 control_by_parameter[PanWidthAutomation] = 0;
1273                         }
1274                 } else {
1275                         /* gain to fader, pan width to vpot */
1276                         _fader->set_control (_route->gain_control());
1277                         control_by_parameter[GainAutomation] = _fader;
1278                         if (pannable) {
1279                                 _vpot->set_control (pannable->pan_width_control);
1280                                 control_by_parameter[PanWidthAutomation] = _vpot;
1281                         } else {
1282                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1283                                 control_by_parameter[PanWidthAutomation] = 0;
1284                         }
1285                 }
1286                 break;
1287         case PanElevationAutomation:
1288                 break;
1289         case PanFrontBackAutomation:
1290                 break;
1291         case PanLFEAutomation:
1292                 break;
1293         case TrimAutomation:
1294                 _trim_mode = TrimAutomation;
1295                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1296                         /* gain to vpot, trim to fader */
1297                         _vpot->set_control (_route->gain_control());
1298                         control_by_parameter[GainAutomation] = _vpot;
1299                         if (_route->trim() && route()->trim()->active()) {
1300                                 _fader->set_control (_route->trim_control());
1301                                 control_by_parameter[TrimAutomation] = _fader;
1302                         } else {
1303                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1304                                 control_by_parameter[TrimAutomation] = 0;
1305                         }
1306                 } else {
1307                         /* gain to fader, trim to vpot */
1308                         _fader->set_control (_route->gain_control());
1309                         control_by_parameter[GainAutomation] = _fader;
1310                         if (_route->trim() && route()->trim()->active()) {
1311                                 _vpot->set_control (_route->trim_control());
1312                                 control_by_parameter[TrimAutomation] = _vpot;
1313                         } else {
1314                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1315                                 control_by_parameter[TrimAutomation] = 0;
1316                         }
1317                 }
1318                 break;
1319         case PhaseAutomation:
1320                 _trim_mode = PhaseAutomation;
1321                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1322                         /* gain to vpot, phase to fader */
1323                         _vpot->set_control (_route->gain_control());
1324                         control_by_parameter[GainAutomation] = _vpot;
1325                         if (_route->phase_invert().size()) {
1326                                 _fader->set_control (_route->phase_control());
1327                                 control_by_parameter[PhaseAutomation] = _fader;
1328                         } else {
1329                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1330                                 control_by_parameter[PhaseAutomation] = 0;
1331                         }
1332                 } else {
1333                         /* gain to fader, phase to vpot */
1334                         _fader->set_control (_route->gain_control());
1335                         control_by_parameter[GainAutomation] = _fader;
1336                         if (_route->phase_invert().size()) {
1337                                 _vpot->set_control (_route->phase_control());
1338                                 control_by_parameter[PhaseAutomation] = _vpot;
1339                         } else {
1340                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1341                                 control_by_parameter[PhaseAutomation] = 0;
1342                         }
1343                 }
1344                 break;
1345         case SendAutomation:
1346                 // deal with sends ... needs sends yet :)
1347                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1348                         // gain to vpot, trim to fader
1349                         _vpot->set_control (_route->gain_control());
1350                         control_by_parameter[GainAutomation] = _vpot;
1351                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1352                 } else {
1353                         // gain to fader, trim to vpot
1354                         _fader->set_control (_route->gain_control());
1355                         control_by_parameter[GainAutomation] = _fader;
1356                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1357                 }
1358                 break;
1359         default:
1360                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1361                 break;
1362
1363         }
1364
1365         _surface->write (display (1, vpot_mode_string()));
1366 }
1367
1368 bool
1369 Strip::is_midi_track () const
1370 {
1371         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1372 }
1373
1374 void
1375 Strip::reset_saved_values ()
1376 {
1377         _last_pan_azi_position_written = -1.0;
1378         _last_pan_width_position_written = -1.0;
1379         _last_gain_position_written = -1.0;
1380         _last_trim_position_written = -1.0;
1381
1382 }
1383
1384 void
1385 Strip::notify_metering_state_changed()
1386 {
1387         if (!_route || !_meter) {
1388                 return;
1389         }
1390
1391         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1392         bool metering_active = _surface->mcp().metering_active ();
1393
1394         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1395                 return;
1396         }
1397
1398         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1399
1400         if (!transport_is_rolling || !metering_active) {
1401                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1402                 notify_panner_azi_changed (true);
1403         }
1404
1405         _transport_is_rolling = transport_is_rolling;
1406         _metering_active = metering_active;
1407 }