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