for MCP devices that don't handshake, turn them on as soon as we call ::connectivity_...
[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 "midi++/port.h"
27
28 #include "pbd/compose.h"
29 #include "pbd/convert.h"
30
31 #include "ardour/amp.h"
32 #include "ardour/bundle.h"
33 #include "ardour/debug.h"
34 #include "ardour/midi_ui.h"
35 #include "ardour/meter.h"
36 #include "ardour/pannable.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/route.h"
41 #include "ardour/session.h"
42 #include "ardour/send.h"
43 #include "ardour/track.h"
44 #include "ardour/user_bundle.h"
45
46 #include "mackie_control_protocol.h"
47 #include "surface_port.h"
48 #include "surface.h"
49 #include "button.h"
50 #include "led.h"
51 #include "pot.h"
52 #include "fader.h"
53 #include "jog.h"
54 #include "meter.h"
55
56 using namespace Mackie;
57 using namespace std;
58 using namespace ARDOUR;
59 using namespace PBD;
60
61 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
62
63 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
64         : Group (name)
65         , _solo (0)
66         , _recenable (0)
67         , _mute (0)
68         , _select (0)
69         , _vselect (0)
70         , _fader_touch (0)
71         , _vpot (0)
72         , _fader (0)
73         , _meter (0)
74         , _index (index)
75         , _surface (&s)
76         , _controls_locked (false)
77         , _transport_is_rolling (false)
78         , _metering_active (true)
79         , _reset_display_at (0)
80         , _last_gain_position_written (-1.0)
81         , _last_pan_azi_position_written (-1.0)
82         , _last_pan_width_position_written (-1.0)
83 {
84         _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
85         _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
86
87         if (s.mcp().device_info().has_meters()) {
88                 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
89         }
90
91         for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
92                 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
93                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
94                                                                    _surface->number(), index, Button::id_to_name (bb->bid()), 
95                                                                    bb->id(), b->second.base_id));
96         }
97 }       
98
99 Strip::~Strip ()
100 {
101         /* surface is responsible for deleting all controls */
102 }
103
104 void 
105 Strip::add (Control & control)
106 {
107         Button* button;
108
109         Group::add (control);
110
111         /* fader, vpot, meter were all set explicitly */
112
113         if ((button = dynamic_cast<Button*>(&control)) != 0) {
114                 switch (button->bid()) {
115                 case Button::RecEnable:
116                         _recenable = button;
117                         break;
118                 case Button::Mute:
119                         _mute = button;
120                         break;
121                 case Button::Solo:
122                         _solo = button;
123                         break;
124                 case Button::Select:
125                         _select = button;
126                         break;
127                 case Button::VSelect:
128                         _vselect = button;
129                         break;
130                 case Button::FaderTouch:
131                         _fader_touch = button;
132                         break;
133                 default:
134                         break;
135                 }
136         }
137 }
138
139 void
140 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
141 {
142         if (_controls_locked) {
143                 return;
144         }
145
146         route_connections.drop_connections ();
147         
148         _solo->set_control (boost::shared_ptr<AutomationControl>());
149         _mute->set_control (boost::shared_ptr<AutomationControl>());
150         _select->set_control (boost::shared_ptr<AutomationControl>());
151         _recenable->set_control (boost::shared_ptr<AutomationControl>());
152         _fader->set_control (boost::shared_ptr<AutomationControl>());
153         _vpot->set_control (boost::shared_ptr<AutomationControl>());
154
155         _route = r;
156
157         control_by_parameter.clear ();
158         reset_saved_values ();
159
160         if (!r) {
161                 zero ();
162                 return;
163         }
164
165         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
166                                                            _surface->number(), _index, _route->name()));
167         
168         _solo->set_control (_route->solo_control());
169         _mute->set_control (_route->mute_control());
170
171         set_vpot_parameter (PanAzimuthAutomation);
172         
173         _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
174         _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
175
176         _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
177
178         boost::shared_ptr<Pannable> pannable = _route->pannable();
179
180         if (pannable && pannable->panner()) {
181                 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
182                 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
183         }
184         _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
185         _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
186         
187         boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
188         
189         if (trk) {
190                 _recenable->set_control (trk->rec_enable_control());
191                 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
192
193                 
194         }
195         
196         // TODO this works when a currently-banked route is made inactive, but not
197         // when a route is activated which should be currently banked.
198         
199         _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
200         _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
201         
202         /* Update */
203         
204         notify_all ();
205
206         /* setup legal VPot modes for this route */
207         
208         build_input_list (_route->input()->n_ports());
209         build_output_list (_route->output()->n_ports());
210
211         possible_pot_parameters.clear();
212
213         if (pannable) {
214                 boost::shared_ptr<Panner> panner = pannable->panner();
215                 if (panner) {
216                         set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
217                         set<Evoral::Parameter>::iterator a;
218                         
219                         if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
220                                 possible_pot_parameters.push_back (PanAzimuthAutomation);
221                         }
222                         
223                         if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
224                                 possible_pot_parameters.push_back (PanWidthAutomation);
225                         }
226                 }
227         }
228 }
229
230 void 
231 Strip::notify_all()
232 {
233         if (!_route) {
234                 zero ();
235                 return;
236         }
237
238         notify_solo_changed ();
239         notify_mute_changed ();
240         notify_gain_changed ();
241         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
242         notify_panner_azi_changed ();
243         notify_panner_width_changed ();
244         notify_record_enable_changed ();
245 }
246
247 void 
248 Strip::notify_solo_changed ()
249 {
250         if (_route && _solo) {
251                 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
252         }
253 }
254
255 void 
256 Strip::notify_mute_changed ()
257 {
258         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
259         if (_route && _mute) {
260                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
261                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
262
263                 _surface->write (_mute->set_state (_route->muted() ? on : off));
264         }
265 }
266
267 void 
268 Strip::notify_record_enable_changed ()
269 {
270         if (_route && _recenable)  {
271                 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
272         }
273 }
274
275 void 
276 Strip::notify_active_changed ()
277 {
278         _surface->mcp().refresh_current_bank();
279 }
280
281 void 
282 Strip::notify_route_deleted ()
283 {
284         _surface->mcp().refresh_current_bank();
285 }
286
287 void 
288 Strip::notify_gain_changed (bool force_update)
289 {
290         if (_route) {
291                 
292                 Control* control;
293
294                 if (_surface->mcp().flip_mode()) {
295                         control = _vpot;
296                 } else {
297                         control = _fader;
298                 }
299
300                 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
301                 
302                 float gain_coefficient = ac->get_value();
303                 float normalized_position = ac->internal_to_interface (gain_coefficient);
304
305                 if (force_update || normalized_position != _last_gain_position_written) {
306                         
307                         if (_surface->mcp().flip_mode()) {
308                                 if (!control->in_use()) {
309                                         _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
310                                 }
311                                 do_parameter_display (GainAutomation, gain_coefficient);
312                         } else {
313                                 if (!control->in_use()) {
314                                         _surface->write (_fader->set_position (normalized_position));
315                                 }
316                                 do_parameter_display (GainAutomation, gain_coefficient);
317                         }
318
319                         queue_display_reset (2000);
320                         _last_gain_position_written = normalized_position;
321                 }
322         }
323 }
324
325 void 
326 Strip::notify_property_changed (const PropertyChange& what_changed)
327 {
328         if (!what_changed.contains (ARDOUR::Properties::name)) {
329                 return;
330         }
331
332         if (_route) {
333                 string line1;
334                 string fullname = _route->name();
335                 
336                 if (fullname.length() <= 6) {
337                         line1 = fullname;
338                 } else {
339                         line1 = PBD::short_version (fullname, 6);
340                 }
341
342                 _surface->write (display (0, line1));
343         }
344 }
345
346 void 
347 Strip::notify_panner_azi_changed (bool force_update)
348 {
349         if (_route) {
350
351                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
352
353                 boost::shared_ptr<Pannable> pannable = _route->pannable();
354
355                 if (!pannable || !pannable->panner()) {
356                         _surface->write (_vpot->zero());
357                         return;
358                 }
359
360                 Control* control = control_by_parameter[PanAzimuthAutomation];
361
362                 if (!control) {
363                         return;
364                 }
365
366                 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
367                 
368                 if (force_update || pos != _last_pan_azi_position_written) {
369
370                         if (control == _fader) {
371                                 if (!_fader->in_use()) {
372                                         _surface->write (_fader->set_position (pos));
373                                 }
374                         } else if (control == _vpot) {
375                                 _surface->write (_vpot->set (pos, true, Pot::dot));
376                         }
377                         
378                         do_parameter_display (PanAzimuthAutomation, pos);
379                         queue_display_reset (2000);
380                         _last_pan_azi_position_written = pos;
381                 }
382         }
383 }
384
385 void 
386 Strip::notify_panner_width_changed (bool force_update)
387 {
388         if (_route) {
389
390                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
391
392                 boost::shared_ptr<Pannable> pannable = _route->pannable();
393
394                 if (!pannable || !pannable->panner()) {
395                         _surface->write (_vpot->zero());
396                         return;
397                 }
398
399
400                 Control* control = control_by_parameter[PanWidthAutomation];
401
402                 if (!control) {
403                         return;
404                 }       
405                         
406                 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
407                 
408                 if (force_update || pos != _last_pan_azi_position_written) {
409                         
410                         if (_surface->mcp().flip_mode()) {
411
412                                 if (control == _fader) {
413                                         if (!control->in_use()) {
414                                                 _surface->write (_fader->set_position (pos));
415                                         }
416                                 }
417
418                         } else if (control == _vpot) {
419                                 _surface->write (_vpot->set (pos, true, Pot::spread));
420                         }
421                         
422                         do_parameter_display (PanWidthAutomation, pos);
423                         queue_display_reset (2000);
424                         _last_pan_azi_position_written = pos;
425                 }
426         }
427 }
428
429 void
430 Strip::select_event (Button&, ButtonState bs)
431 {
432         DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
433         
434         if (bs == press) {
435                 
436                 int ms = _surface->mcp().modifier_state();
437
438                 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
439                         _controls_locked = !_controls_locked;
440                         _surface->write (display (1,_controls_locked ?  "Locked" : "Unlock"));
441                         queue_display_reset (1000);
442                         return;
443                 }
444                 
445                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
446                         /* reset to default */
447                         boost::shared_ptr<AutomationControl> ac = _fader->control ();
448                         if (ac) {
449                                 ac->set_value (ac->normal());
450                         }
451                         return;
452                 }
453                 
454                 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
455                 _surface->mcp().add_down_select_button (_surface->number(), _index);                    
456                 _surface->mcp().select_range ();
457                 
458         } else {
459                 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
460                 _surface->mcp().remove_down_select_button (_surface->number(), _index);                 
461         }
462 }
463
464 void
465 Strip::vselect_event (Button&, ButtonState bs)
466 {
467         if (bs == press) {
468
469                 int ms = _surface->mcp().modifier_state();
470                                 
471                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
472
473                         boost::shared_ptr<AutomationControl> ac = _vpot->control ();
474                                 
475                         if (ac) {
476                                 
477                                 /* reset to default/normal value */
478                                 ac->set_value (ac->normal());
479                         }
480
481                 }  else {
482
483                         DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
484                         next_pot_mode ();
485                 }
486
487         }
488 }
489
490 void
491 Strip::fader_touch_event (Button&, ButtonState bs)
492 {
493         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
494         
495         if (bs == press) {
496
497                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
498
499                 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
500                         if (ac) {
501                                 ac->set_value (ac->normal());
502                         }
503                 } else {
504                 
505                         _fader->set_in_use (true);
506                         _fader->start_touch (_surface->mcp().transport_frame());
507                         
508                         if (ac) {
509                                 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
510                                 queue_display_reset (2000);
511                         }
512                 }
513                         
514         } else {
515                 
516                 _fader->set_in_use (false);
517                 _fader->stop_touch (_surface->mcp().transport_frame(), true);
518                 
519         }
520 }       
521
522
523 void
524 Strip::handle_button (Button& button, ButtonState bs)
525 {
526         boost::shared_ptr<AutomationControl> control;
527
528         if (bs == press) {
529                 button.set_in_use (true);
530         } else {
531                 button.set_in_use (false);
532         }
533
534         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
535         
536         switch (button.bid()) {
537         case Button::Select:
538                 select_event (button, bs);
539                 break;
540                 
541         case Button::VSelect:
542                 vselect_event (button, bs);
543                 break;
544
545         case Button::FaderTouch:
546                 fader_touch_event (button, bs);
547                 break;
548
549         default:
550                 if ((control = button.control ())) {
551                         if (bs == press) {
552                                 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
553                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
554                                 
555                                 float new_value;
556                                 int ms = _surface->mcp().modifier_state();
557                                 
558                                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
559                                         /* reset to default/normal value */
560                                         new_value = control->normal();
561                                 } else {
562                                         new_value = control->get_value() ? 0.0 : 1.0;
563                                 }
564                                 
565                                 /* get all controls that either have their
566                                  * button down or are within a range of
567                                  * several down buttons
568                                  */
569                                 
570                                 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
571                                 
572                                 
573                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
574                                                                             controls.size(), control->parameter().type(), new_value));
575
576                                 /* apply change */
577                                 
578                                 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
579                                         (*c)->set_value (new_value);
580                                 }
581                                 
582                         } else {
583                                 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
584                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
585                         }
586                 }
587                 break;
588         }
589 }
590
591 void
592 Strip::do_parameter_display (AutomationType type, float val)
593 {
594         switch (type) {
595         case GainAutomation:
596                 if (val == 0.0) {
597                         _surface->write (display (1, " -inf "));
598                 } else {
599                         char buf[16];
600                         float dB = accurate_coefficient_to_dB (val);
601                         snprintf (buf, sizeof (buf), "%6.1f", dB);
602                         _surface->write (display (1, buf));
603                 }               
604                 break;
605
606         case PanAzimuthAutomation:
607                 if (_route) {
608                         boost::shared_ptr<Pannable> p = _route->pannable();
609                         if (p && p->panner()) {
610                                 string str = p->panner()->value_as_string (p->pan_azimuth_control);
611                                 _surface->write (display (1, str));
612                         }
613                 }
614                 break;
615
616         case PanWidthAutomation:
617                 if (_route) {
618                         char buf[16];
619                         snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
620                         _surface->write (display (1, buf));
621                 }
622                 break;
623
624         default:
625                 break;
626         }
627 }
628
629 void
630 Strip::handle_fader (Fader& fader, float position)
631 {
632         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
633
634         fader.set_value (position);
635         fader.start_touch (_surface->mcp().transport_frame());
636         queue_display_reset (2000);
637
638         // must echo bytes back to slider now, because
639         // the notifier only works if the fader is not being
640         // touched. Which it is if we're getting input.
641
642         _surface->write (fader.set_position (position));
643 }
644
645 void
646 Strip::handle_pot (Pot& pot, float delta)
647 {
648         /* Pots only emit events when they move, not when they
649            stop moving. So to get a stop event, we need to use a timeout.
650         */
651         
652         boost::shared_ptr<AutomationControl> ac = pot.control();
653         double p = pot.get_value ();
654         p += delta;
655         p = max (ac->lower(), p);
656         p = min (ac->upper(), p);
657         pot.set_value (p);
658 }
659
660 void
661 Strip::periodic (uint64_t usecs)
662 {
663         if (!_route) {
664                 return;
665         }
666
667         update_automation ();
668         update_meter ();
669
670         if (_reset_display_at && _reset_display_at < usecs) {
671                 reset_display ();
672         }
673 }
674
675 void 
676 Strip::update_automation ()
677 {
678         ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
679
680         if (gain_state == Touch || gain_state == Play) {
681                 notify_gain_changed (false);
682         }
683
684         if (_route->panner()) {
685                 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
686                 if (panner_state == Touch || panner_state == Play) {
687                         notify_panner_azi_changed (false);
688                         notify_panner_width_changed (false);
689                 }
690         }
691 }
692
693 void
694 Strip::update_meter ()
695 {
696         if (_meter && _transport_is_rolling && _metering_active) {
697                 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
698                 _meter->send_update (*_surface, dB);
699         }
700 }
701
702 void
703 Strip::zero ()
704 {
705         for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
706                 _surface->write ((*it)->zero ());
707         }
708
709         _surface->write (blank_display (0));
710         _surface->write (blank_display (1));
711 }
712
713 MidiByteArray
714 Strip::blank_display (uint32_t line_number)
715 {
716         return display (line_number, string());
717 }
718
719 MidiByteArray
720 Strip::display (uint32_t line_number, const std::string& line)
721 {
722         assert (line_number <= 1);
723
724         MidiByteArray retval;
725
726         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
727
728         // sysex header
729         retval << _surface->sysex_hdr();
730         
731         // code for display
732         retval << 0x12;
733         // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
734         retval << (_index * 7 + (line_number * 0x38));
735         
736         // ascii data to display
737         retval << line;
738         // pad with " " out to 6 chars
739         for (int i = line.length(); i < 6; ++i) {
740                 retval << ' ';
741         }
742         
743         // column spacer, unless it's the right-hand column
744         if (_index < 7) {
745                 retval << ' ';
746         }
747
748         // sysex trailer
749         retval << MIDI::eox;
750         
751         return retval;
752 }
753
754 void
755 Strip::lock_controls ()
756 {
757         _controls_locked = true;
758 }
759
760 void
761 Strip::unlock_controls ()
762 {
763         _controls_locked = false;
764 }
765
766 void
767 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
768 {
769         for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
770                 if ((*i) == _route) {
771                         _surface->write (_select->set_state (on));
772                         return;
773                 }
774         }
775
776         _surface->write (_select->set_state (off));
777 }
778
779 string
780 Strip::vpot_mode_string () const
781 {
782         boost::shared_ptr<AutomationControl> ac = _vpot->control();
783         
784         if (!ac) {
785                 return string();
786         }
787
788         switch (ac->parameter().type()) {
789         case GainAutomation:
790                 return "Fader";
791         case PanAzimuthAutomation:
792                 return "Pan";
793         case PanWidthAutomation:
794                 return "Width";
795         case PanElevationAutomation:
796                 return "Elev";
797         case PanFrontBackAutomation:
798                 return "F/Rear";
799         case PanLFEAutomation:
800                 return "LFE";
801         }
802
803         return "???";
804 }
805
806 void
807 Strip::flip_mode_changed (bool notify)
808 {
809         if (!_route) {
810                 return;
811         }
812
813         reset_saved_values ();
814
815         boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
816         boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
817
818         _fader->set_control (vpot_controllable);
819         _vpot->set_control (fader_controllable);
820
821         control_by_parameter[fader_controllable->parameter()] = _vpot;
822         control_by_parameter[vpot_controllable->parameter()] = _fader;
823
824         _surface->write (display (1, vpot_mode_string ()));
825
826         if (notify) {
827                 notify_all ();
828         }
829 }
830
831 void
832 Strip::queue_display_reset (uint32_t msecs)
833 {
834         struct timeval now;
835         struct timeval delta;
836         struct timeval when;
837         gettimeofday (&now, 0);
838         
839         delta.tv_sec = msecs/1000;
840         delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
841         
842         timeradd (&now, &delta, &when);
843
844         _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
845 }
846
847 void
848 Strip::clear_display_reset ()
849 {
850         _reset_display_at = 0;
851 }
852
853 void
854 Strip::reset_display ()
855 {
856         if (_route) {
857                 _surface->write (display (1, vpot_mode_string()));
858         } else {
859                 _surface->write (blank_display (1));
860         }
861                 
862         clear_display_reset ();
863 }
864                          
865 struct RouteCompareByName {
866         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
867                 return a->name().compare (b->name()) < 0;
868         }
869 };
870
871 void
872 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
873 {
874         if (b->ports_are_outputs() == !for_input  || b->nchannels() != channels) {
875                 return;
876         }
877
878         bm[b->name()] = b;
879 }
880
881 void
882 Strip::build_input_list (const ChanCount& channels)
883 {
884         boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
885
886         input_bundles.clear ();
887
888         /* give user bundles first chance at being in the menu */
889         
890         for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
891                 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
892                         maybe_add_to_bundle_map (input_bundles, *i, true, channels);
893                 }
894         }
895         
896         for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
897                 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
898                         maybe_add_to_bundle_map (input_bundles, *i, true, channels);
899                 }
900         }
901         
902         boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
903         RouteList copy = *routes;
904         copy.sort (RouteCompareByName ());
905
906         for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
907                 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
908         }
909
910 }
911
912 void
913 Strip::build_output_list (const ChanCount& channels)
914 {
915         boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
916
917         output_bundles.clear ();
918
919         /* give user bundles first chance at being in the menu */
920         
921         for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922                 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
923                         maybe_add_to_bundle_map (output_bundles, *i, false, channels);
924                 }
925         }
926         
927         for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
928                 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
929                         maybe_add_to_bundle_map (output_bundles, *i, false, channels);
930                 }
931         }
932         
933         boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
934         RouteList copy = *routes;
935         copy.sort (RouteCompareByName ());
936
937         for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
938                 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
939         }
940 }
941
942 void
943 Strip::next_pot_mode ()
944 {
945         vector<Evoral::Parameter>::iterator i;
946
947         if (_surface->mcp().flip_mode()) {
948                 /* do not change vpot mode while in flipped mode */
949                 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
950                 _surface->write (display (1, "Flip"));
951                 queue_display_reset (1000);
952                 return;
953         }
954
955
956         boost::shared_ptr<AutomationControl> ac = _vpot->control();
957
958         if (!ac) {
959                 return;
960         }
961
962         if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
963                 return;
964         }
965
966         for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
967                 if ((*i) == ac->parameter()) {
968                         break;
969                 }
970         }
971
972         /* move to the next mode in the list, or back to the start (which will
973            also happen if the current mode is not in the current pot mode list)
974         */
975
976         if (i != possible_pot_parameters.end()) {
977                 ++i;
978         }
979
980         if (i == possible_pot_parameters.end()) {
981                 i = possible_pot_parameters.begin();
982         }
983
984         set_vpot_parameter (*i);
985 }
986
987 void
988 Strip::set_vpot_parameter (Evoral::Parameter p)
989 {
990         boost::shared_ptr<Pannable> pannable;
991
992         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
993
994         reset_saved_values ();
995
996         switch (p.type()) {
997         case PanAzimuthAutomation:
998                 pannable = _route->pannable ();
999                 if (pannable) {
1000                         if (_surface->mcp().flip_mode()) {
1001                                 /* gain to vpot, pan azi to fader */
1002                                 _vpot->set_control (_route->gain_control());
1003                                 control_by_parameter[GainAutomation] = _vpot;
1004                                 if (pannable) {
1005                                         _fader->set_control (pannable->pan_azimuth_control);
1006                                         control_by_parameter[PanAzimuthAutomation] = _fader;
1007                                 } else {
1008                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1009                                         control_by_parameter[PanAzimuthAutomation] = 0;
1010                                 }
1011                         } else {
1012                                 /* gain to fader, pan azi to vpot */
1013                                 _fader->set_control (_route->gain_control());
1014                                 control_by_parameter[GainAutomation] = _fader;
1015                                 if (pannable) {
1016                                         _vpot->set_control (pannable->pan_azimuth_control);
1017                                         control_by_parameter[PanAzimuthAutomation] = _vpot;
1018                                 } else {
1019                                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1020                                         control_by_parameter[PanAzimuthAutomation] = 0;
1021                                 }
1022                         }
1023                 }
1024                 break;
1025         case PanWidthAutomation:
1026                 pannable = _route->pannable ();
1027                 if (pannable) {
1028                         if (_surface->mcp().flip_mode()) {
1029                                 /* gain to vpot, pan width to fader */
1030                                 _vpot->set_control (_route->gain_control());
1031                                 control_by_parameter[GainAutomation] = _vpot;
1032                                 if (pannable) {
1033                                         _fader->set_control (pannable->pan_width_control);
1034                                         control_by_parameter[PanWidthAutomation] = _fader;
1035                                 } else {
1036                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1037                                         control_by_parameter[PanWidthAutomation] = 0;
1038                                 }
1039                         } else {
1040                                 /* gain to fader, pan width to vpot */
1041                                 _fader->set_control (_route->gain_control());
1042                                 control_by_parameter[GainAutomation] = _fader;
1043                                 if (pannable) {
1044                                         _vpot->set_control (pannable->pan_width_control);
1045                                         control_by_parameter[PanWidthAutomation] = _vpot;
1046                                 } else {
1047                                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1048                                         control_by_parameter[PanWidthAutomation] = 0;
1049                                 }
1050                         }
1051                 }
1052                 break;
1053         case PanElevationAutomation:
1054                 break;
1055         case PanFrontBackAutomation:
1056                 break;
1057         case PanLFEAutomation:
1058                 break;
1059         }
1060
1061         _surface->write (display (1, vpot_mode_string()));
1062 }
1063
1064 void
1065 Strip::reset_saved_values ()
1066 {
1067         _last_pan_azi_position_written = -1.0;
1068         _last_pan_width_position_written = -1.0;
1069         _last_gain_position_written = -1.0;
1070
1071 }
1072
1073 void 
1074 Strip::notify_metering_state_changed()
1075 {
1076         if (!_route || !_meter) {
1077                 return;
1078         }
1079         
1080         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1081         bool metering_active = _surface->mcp().metering_active ();
1082         
1083         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1084                 return;
1085         }
1086         
1087         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1088         
1089         if (!transport_is_rolling || !metering_active) {
1090                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1091                 notify_panner_azi_changed (true);
1092         }
1093         
1094         _transport_is_rolling = transport_is_rolling;
1095         _metering_active = metering_active;
1096 }