The great audio processing overhaul.
[ardour.git] / gtk2_ardour / mixer_strip.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20 #include <algorithm>
21
22 #include <sigc++/bind.h>
23
24 #include "pbd/convert.h"
25 #include "pbd/enumwriter.h"
26 #include "pbd/replace_all.h"
27
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
30 #include <gtkmm2ext/choice.h>
31 #include <gtkmm2ext/stop_signal.h>
32 #include <gtkmm2ext/doi.h>
33 #include <gtkmm2ext/slider_controller.h>
34 #include <gtkmm2ext/bindable_button.h>
35
36 #include "ardour/ardour.h"
37 #include "ardour/session.h"
38 #include "ardour/audioengine.h"
39 #include "ardour/route.h"
40 #include "ardour/route_group.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_diskstream.h"
43 #include "ardour/panner.h"
44 #include "ardour/send.h"
45 #include "ardour/processor.h"
46 #include "ardour/profile.h"
47 #include "ardour/ladspa_plugin.h"
48 #include "ardour/user_bundle.h"
49
50 #include "ardour_ui.h"
51 #include "ardour_dialog.h"
52 #include "mixer_strip.h"
53 #include "mixer_ui.h"
54 #include "keyboard.h"
55 #include "public_editor.h"
56 #include "send_ui.h"
57 #include "io_selector.h"
58 #include "utils.h"
59 #include "gui_thread.h"
60
61 #include "i18n.h"
62
63 using namespace sigc;
64 using namespace ARDOUR;
65 using namespace PBD;
66 using namespace Gtk;
67 using namespace Gtkmm2ext;
68 using namespace std;
69
70 int MixerStrip::scrollbar_height = 0;
71
72 #ifdef VARISPEED_IN_MIXER_STRIP
73 static void 
74 speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
75 {
76         float val = adj.get_value ();
77
78         if (val == 1.0) {
79                 strcpy (buf, "1");
80         } else {
81                 snprintf (buf, 32, "%.3f", val);
82         }
83 }
84 #endif 
85
86 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
87         : AxisView(sess)
88         , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
89         ,_mixer(mx)
90         , _mixer_owned (in_mixer)
91         , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
92         , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
93         , gpm (sess)
94         , panners (sess)
95         , button_table (3, 2)
96         , middle_button_table (1, 2)
97         , bottom_button_table (1, 2)
98         , meter_point_label (_("pre"))
99         , comment_button (_("Comments"))
100         , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
101         , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
102                          
103 {
104         init ();
105         
106         if (!_mixer_owned) {
107                 /* the editor mixer strip: don't destroy it every time
108                    the underlying route goes away.
109                 */
110                 
111                 self_destruct = false;
112         }
113 }
114
115 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
116         : AxisView(sess)
117         , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
118         ,_mixer(mx)
119         , _mixer_owned (in_mixer)
120         , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
121         , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
122         , gpm (sess)
123         , panners (sess)
124         , button_table (3, 2)
125         , middle_button_table (1, 2)
126         , bottom_button_table (1, 2)
127         , meter_point_label (_("pre"))
128         , comment_button (_("Comments"))
129         , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
130         , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
131                          
132 {
133         init ();
134         set_route (rt);
135 }
136
137 void
138 MixerStrip::init ()
139 {
140         input_selector = 0;
141         output_selector = 0;
142         group_menu = 0;
143         _marked_for_display = false;
144         route_ops_menu = 0;
145         ignore_comment_edit = false;
146         ignore_toggle = false;
147         ignore_speed_adjustment = false;
148         comment_window = 0;
149         comment_area = 0;
150         _width_owner = 0;
151         spacer = 0;
152
153         Gtk::Image* img;
154
155         img = manage (new Gtk::Image (::get_icon("strip_width")));
156         img->show ();
157
158         width_button.add (*img);
159
160         img = manage (new Gtk::Image (::get_icon("hide")));
161         img->show ();
162
163         hide_button.add (*img);
164
165         input_label.set_text (_("Input"));
166         ARDOUR_UI::instance()->set_tip (&input_button, _("Button 1 to choose inputs from a port matrix, button 3 to select inputs from a menu"), "");
167         input_button.add (input_label);
168         input_button.set_name ("MixerIOButton");
169         input_label.set_name ("MixerIOButtonLabel");
170         Gtkmm2ext::set_size_request_to_display_given_text (input_button, "longest label", 4, 4);
171
172         output_label.set_text (_("Output"));
173         ARDOUR_UI::instance()->set_tip (&output_button, _("Button 1 to choose outputs from a port matrix, button 3 to select inputs from a menu"), "");
174         output_button.add (output_label);
175         output_button.set_name ("MixerIOButton");
176         output_label.set_name ("MixerIOButtonLabel");
177         Gtkmm2ext::set_size_request_to_display_given_text (output_button, "longest label", 4, 4);
178
179         ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Select metering point"), "");
180         meter_point_button.add (meter_point_label);
181         meter_point_button.set_name ("MixerStripMeterPreButton");
182         meter_point_label.set_name ("MixerStripMeterPreButton");
183         
184         /* TRANSLATORS: this string should be longest of the strings
185            used to describe meter points. In english, it's "input".
186         */
187         set_size_request_to_display_given_text (meter_point_button, _("tupni"), 5, 5);
188     
189         bottom_button_table.attach (meter_point_button, 1, 2, 0, 1);
190     
191         meter_point_button.signal_button_press_event().connect (mem_fun (gpm, &GainMeter::meter_press), false);
192         /* XXX what is this meant to do? */
193         //meter_point_button.signal_button_release_event().connect (mem_fun (gpm, &GainMeter::meter_release), false);
194
195         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
196
197         mute_button->set_name ("MixerMuteButton");
198         solo_button->set_name ("MixerSoloButton");
199
200         button_table.set_homogeneous (true);
201         button_table.set_spacings (0);
202
203         button_table.attach (name_button, 0, 2, 0, 1);
204         button_table.attach (input_button, 0, 2, 1, 2);
205
206         middle_button_table.set_homogeneous (true);
207         middle_button_table.set_spacings (0);
208         middle_button_table.attach (*mute_button, 0, 1, 0, 1);
209         middle_button_table.attach (*solo_button, 1, 2, 0, 1);
210
211         bottom_button_table.set_col_spacings (0);
212         bottom_button_table.set_homogeneous (true);
213         bottom_button_table.attach (group_button, 0, 1, 0, 1);
214         
215         name_button.add (name_label);
216         name_button.set_name ("MixerNameButton");
217         Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
218
219         name_label.set_name ("MixerNameButtonLabel");
220         ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
221         group_button.add (group_label);
222         group_button.set_name ("MixerGroupButton");
223         group_label.set_name ("MixerGroupButtonLabel");
224
225         comment_button.set_name ("MixerCommentButton");
226
227         comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
228         
229         global_vpacker.set_border_width (0);
230         global_vpacker.set_spacing (0);
231
232         width_button.set_name ("MixerWidthButton");
233         hide_button.set_name ("MixerHideButton");
234         top_event_box.set_name ("MixerTopEventBox");
235
236         width_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::width_clicked));
237         hide_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::hide_clicked));
238
239         width_hide_box.pack_start (width_button, false, true);
240         width_hide_box.pack_start (top_event_box, true, true);
241         width_hide_box.pack_end (hide_button, false, true);
242         gain_meter_alignment.set_padding(0, 4, 0, 0);
243         gain_meter_alignment.add(gpm);
244
245         whvbox.pack_start (width_hide_box, true, true);
246
247         global_vpacker.pack_start (whvbox, Gtk::PACK_SHRINK);
248         global_vpacker.pack_start (button_table,Gtk::PACK_SHRINK);
249         global_vpacker.pack_start (pre_processor_box, true, true);
250         global_vpacker.pack_start (middle_button_table,Gtk::PACK_SHRINK);
251         global_vpacker.pack_start (gain_meter_alignment,Gtk::PACK_SHRINK);
252         global_vpacker.pack_start (bottom_button_table,Gtk::PACK_SHRINK);
253         global_vpacker.pack_start (post_processor_box, true, true);
254         if (!is_midi_track()) {
255                 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
256         }
257         global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
258         global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
259
260         global_frame.add (global_vpacker);
261         global_frame.set_shadow_type (Gtk::SHADOW_IN);
262         global_frame.set_name ("BaseFrame");
263
264         add (global_frame);
265
266         /* force setting of visible selected status */
267
268         _selected = true;
269         set_selected (false);
270
271         _packed = false;
272         _embedded = false;
273
274         _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
275         _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
276
277         input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
278         output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
279
280         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
281         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
282         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
283         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
284
285         /* we don't need this if its not an audio track, but we don't know that yet and it doesn't
286            hurt (much).
287         */
288
289         rec_enable_button->set_name ("MixerRecordEnableButton");
290         rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
291         rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
292
293         name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
294         group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
295
296         _width = (Width) -1;
297
298         /* start off as a passthru strip. we'll correct this, if necessary,
299            in update_diskstream_display().
300         */
301
302         /* start off as a passthru strip. we'll correct this, if necessary,
303            in update_diskstream_display().
304         */
305
306         if (is_midi_track())
307                 set_name ("MidiTrackStripBase");
308         else
309                 set_name ("AudioTrackStripBase");
310
311         add_events (Gdk::BUTTON_RELEASE_MASK);
312 }
313
314 MixerStrip::~MixerStrip ()
315 {
316         GoingAway(); /* EMIT_SIGNAL */
317
318         delete input_selector;
319         delete output_selector;
320 }
321
322 void
323 MixerStrip::set_route (boost::shared_ptr<Route> rt)
324 {
325         if (rec_enable_button->get_parent()) {
326                 button_table.remove (*rec_enable_button);
327         }
328
329 #ifdef VARISPEED_IN_MIXER_STRIP
330         if (speed_frame->get_parent()) {
331                 button_table.remove (*speed_frame);
332         }
333 #endif
334
335         RouteUI::set_route (rt);
336
337         delete input_selector;
338         input_selector = 0;
339
340         delete output_selector;
341         output_selector = 0;
342
343         panners.set_io (rt);
344         gpm.set_io (rt);
345         pre_processor_box.set_route (rt);
346         post_processor_box.set_route (rt);
347
348         if (set_color_from_route()) {
349                 set_color (unique_random_color());
350         }
351
352         if (_mixer_owned && (route()->is_master() || route()->is_control())) {
353                 
354                 if (scrollbar_height == 0) {
355                         HScrollbar scrollbar;
356                         Gtk::Requisition requisition(scrollbar.size_request ());
357                         scrollbar_height = requisition.height;
358                 }
359
360                 spacer = manage (new EventBox);
361                 spacer->set_size_request (-1, scrollbar_height);
362                 global_vpacker.pack_start (*spacer, false, false);
363         }
364
365         if (is_audio_track()) {
366
367                 boost::shared_ptr<AudioTrack> at = audio_track();
368
369                 connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
370
371 #ifdef VARISPEED_IN_MIXER_STRIP
372                 speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
373                 
374                 speed_frame.set_name ("BaseFrame");
375                 speed_frame.set_shadow_type (Gtk::SHADOW_IN);
376                 speed_frame.add (speed_spinner);
377                 
378                 speed_spinner.set_print_func (speed_printer, 0);
379
380                 ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
381
382                 button_table.attach (speed_frame, 0, 2, 5, 6);
383 #endif /* VARISPEED_IN_MIXER_STRIP */
384
385                 button_table.attach (*rec_enable_button, 0, 2, 2, 3);
386                 rec_enable_button->show();
387         }
388
389         if (_route->phase_invert()) {
390                 name_label.set_text (X_("Ø ") + name_label.get_text());
391         } else {
392                 name_label.set_text (_route->name());
393         }
394
395         switch (_route->meter_point()) {
396         case MeterInput:
397                 meter_point_label.set_text (_("input"));
398                 break;
399                 
400         case MeterPreFader:
401                 meter_point_label.set_text (_("pre"));
402                 break;
403                 
404         case MeterPostFader:
405                 meter_point_label.set_text (_("post"));
406                 break;
407         }
408
409         delete route_ops_menu;
410         route_ops_menu = 0;
411         
412         ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
413                                                    _("Click to Add/Edit Comments"):
414                                                    _route->comment());
415
416         connections.push_back (_route->meter_change.connect (
417                         mem_fun(*this, &MixerStrip::meter_changed)));
418         connections.push_back (_route->input_changed.connect (
419                         mem_fun(*this, &MixerStrip::input_changed)));
420         connections.push_back (_route->output_changed.connect (
421                         mem_fun(*this, &MixerStrip::output_changed)));
422         connections.push_back (_route->mix_group_changed.connect (
423                         mem_fun(*this, &MixerStrip::mix_group_changed)));
424
425         if (_route->panner()) {
426                 connections.push_back (_route->panner()->Changed.connect (
427                         mem_fun(*this, &MixerStrip::connect_to_pan)));
428         }
429
430         if (is_audio_track()) {
431                 connections.push_back (audio_track()->DiskstreamChanged.connect (
432                         mem_fun(*this, &MixerStrip::diskstream_changed)));
433                 connections.push_back (get_diskstream()->SpeedChanged.connect (
434                         mem_fun(*this, &MixerStrip::speed_changed)));
435         }
436
437         connections.push_back (_route->NameChanged.connect (
438                         mem_fun(*this, &RouteUI::name_changed)));
439         connections.push_back (_route->comment_changed.connect (
440                         mem_fun(*this, &MixerStrip::comment_changed)));
441         connections.push_back (_route->gui_changed.connect (
442                         mem_fun(*this, &MixerStrip::route_gui_changed)));
443
444         set_stuff_from_route ();
445
446         /* now force an update of all the various elements */
447
448         pre_processor_box.update();
449         post_processor_box.update();
450         mute_changed (0);
451         solo_changed (0);
452         name_changed ();
453         comment_changed (0);
454         mix_group_changed (0);
455
456         connect_to_pan ();
457
458         panners.setup_pan ();
459
460         if (is_audio_track()) {
461                 speed_changed ();
462         }
463
464         update_diskstream_display ();
465         update_input_display ();
466         update_output_display ();
467
468         add_events (Gdk::BUTTON_RELEASE_MASK);
469
470         pre_processor_box.show();
471
472         if (!route()->is_master() && !route()->is_control()) {
473                 /* we don't allow master or control routes to be hidden */
474                 hide_button.show();
475         }
476
477         width_button.show();
478         width_hide_box.show();
479         whvbox.show ();
480         global_frame.show();
481         global_vpacker.show();
482         button_table.show();
483         middle_button_table.show();
484         bottom_button_table.show();
485         pre_processor_box.show_all ();
486         gpm.show_all ();
487         panners.show_all ();
488         gain_meter_alignment.show ();
489         post_processor_box.show_all ();
490         gain_unit_button.show();
491         gain_unit_label.show();
492         meter_point_button.show();
493         meter_point_label.show();
494         diskstream_button.show();
495         diskstream_label.show();
496         input_button.show();
497         input_label.show();
498         output_button.show();
499         output_label.show();
500         name_label.show();
501         name_button.show();
502         comment_button.show();
503         group_button.show();
504         group_label.show();
505         speed_spinner.show();
506         speed_label.show();
507         speed_frame.show();
508
509         show ();
510 }
511
512 void
513 MixerStrip::set_stuff_from_route ()
514 {
515         XMLProperty *prop;
516
517         ensure_xml_node ();
518
519         /* if width is not set, it will be set by the MixerUI or editor */
520
521         if ((prop = xml_node->property ("strip-width")) != 0) {
522                 set_width (Width (string_2_enum (prop->value(), _width)), this);
523         }
524
525         if ((prop = xml_node->property ("shown-mixer")) != 0) {
526                 if (prop->value() == "no") {
527                         _marked_for_display = false;
528                 } else {
529                         _marked_for_display = true;
530                 }
531         } else {
532                 /* backwards compatibility */
533                 _marked_for_display = true;
534         }
535 }
536
537 void
538 MixerStrip::set_width (Width w, void* owner)
539 {
540         /* always set the gpm width again, things may be hidden */
541
542         gpm.set_width (w);
543         panners.set_width (w);
544         pre_processor_box.set_width (w);
545         post_processor_box.set_width (w);
546
547         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
548
549         _width_owner = owner;
550
551         ensure_xml_node ();
552         
553         _width = w;
554
555         if (_width_owner == this) {
556                 xml_node->add_property ("strip-width", enum_2_string (_width));
557         }
558
559         switch (w) {
560         case Wide:
561
562                 if (rec_enable_button)  {
563                         ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("Record"));
564                 }
565                 ((Gtk::Label*)mute_button->get_child())->set_text  (_("Mute"));
566                 ((Gtk::Label*)solo_button->get_child())->set_text (_("Solo"));
567
568                 if (_route->comment() == "") {
569                         comment_button.unset_bg (STATE_NORMAL);
570                         ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
571                 } else {
572                         comment_button.modify_bg (STATE_NORMAL, color());
573                         ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
574                 }
575
576                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
577                                 gpm.astyle_string(gain_automation->automation_style()));
578                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
579                                 gpm.astate_string(gain_automation->automation_state()));
580
581                 if (_route->panner()) {
582                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
583                                         panners.astyle_string(_route->panner()->automation_style()));
584                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
585                                         panners.astate_string(_route->panner()->automation_state()));
586                 }
587
588                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
589                 set_size_request (-1, -1);
590                 break;
591
592         case Narrow:
593                 if (rec_enable_button) {
594                         ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("Rec"));
595                 }
596                 ((Gtk::Label*)mute_button->get_child())->set_text (_("M"));
597                 ((Gtk::Label*)solo_button->get_child())->set_text (_("S"));
598
599                 if (_route->comment() == "") {
600                        comment_button.unset_bg (STATE_NORMAL);
601                        ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
602                 } else {
603                        comment_button.modify_bg (STATE_NORMAL, color());
604                        ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
605                 }
606
607                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
608                                 gpm.short_astyle_string(gain_automation->automation_style()));
609                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
610                                 gpm.short_astate_string(gain_automation->automation_state()));
611                 
612                 if (_route->panner()) {
613                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
614                         panners.short_astyle_string(_route->panner()->automation_style()));
615                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
616                         panners.short_astate_string(_route->panner()->automation_state()));
617                 }
618
619                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
620                 set_size_request (max (50, gpm.get_gm_width()), -1);
621                 break;
622         }
623         update_input_display ();
624         update_output_display ();
625         mix_group_changed (0);
626         name_changed ();
627 #ifdef GTKOSX
628         WidthChanged();
629 #endif
630 }
631
632 void
633 MixerStrip::set_packed (bool yn)
634 {
635         _packed = yn;
636
637         ensure_xml_node ();
638
639         if (_packed) {
640                 xml_node->add_property ("shown-mixer", "yes");
641         } else {
642                 xml_node->add_property ("shown-mixer", "no");
643         }
644 }
645
646
647 gint
648 MixerStrip::output_press (GdkEventButton *ev)
649 {
650         using namespace Menu_Helpers;
651         if (!_session.engine().connected()) {
652                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
653                 msg.run ();
654                 return true;
655         }
656
657         MenuList& citems = output_menu.items();
658         switch (ev->button) {
659
660         case 1:
661                 edit_output_configuration ();
662                 break;
663                 
664         case 3:
665         {
666                 output_menu.set_name ("ArdourContextMenu");
667                 citems.clear();
668                 
669                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
670                 citems.push_back (SeparatorElem());
671
672                 ARDOUR::BundleList current = _route->bundles_connected_to_outputs ();
673
674                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
675                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
676                         maybe_add_bundle_to_output_menu (*i, current);
677                 }
678
679                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
680                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
681                         maybe_add_bundle_to_output_menu ((*i)->bundle_for_inputs(), current);
682                 }
683
684                 if (citems.size() == 2) {
685                         /* no routes added; remove the separator */
686                         citems.pop_back ();
687                 }
688
689                 output_menu.popup (1, ev->time);
690                 break;
691         }
692
693         default:
694                 break;
695         }
696         return TRUE;
697 }
698
699 void
700 MixerStrip::edit_output_configuration ()
701 {
702         if (output_selector == 0) {
703                 output_selector = new IOSelectorWindow (_session, _route, false);
704         } 
705
706         if (output_selector->is_visible()) {
707                 output_selector->get_toplevel()->get_window()->raise();
708         } else {
709                 output_selector->present ();
710         }
711 }
712
713 void
714 MixerStrip::edit_input_configuration ()
715 {
716         if (input_selector == 0) {
717                 input_selector = new IOSelectorWindow (_session, _route, true);
718         } 
719
720         if (input_selector->is_visible()) {
721                 input_selector->get_toplevel()->get_window()->raise();
722         } else {
723                 input_selector->present ();
724         }
725 }
726
727 gint
728 MixerStrip::input_press (GdkEventButton *ev)
729 {
730         using namespace Menu_Helpers;
731
732         MenuList& citems = input_menu.items();
733         input_menu.set_name ("ArdourContextMenu");
734         citems.clear();
735         
736         if (!_session.engine().connected()) {
737                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
738                 msg.run ();
739                 return true;
740         }
741
742         switch (ev->button) {
743
744         case 1:
745                 edit_input_configuration ();
746                 break;
747
748         case 3:
749         {
750                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
751                 citems.push_back (SeparatorElem());
752
753                 ARDOUR::BundleList current = _route->bundles_connected_to_inputs ();
754
755                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
756                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
757                         maybe_add_bundle_to_input_menu (*i, current);
758                 }
759
760                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
761                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
762                         maybe_add_bundle_to_input_menu ((*i)->bundle_for_outputs(), current);
763                 }
764
765                 if (citems.size() == 2) {
766                         /* no routes added; remove the separator */
767                         citems.pop_back ();
768                 }
769
770                 input_menu.popup (1, ev->time);
771                 break;
772         }
773         default:
774                 break;
775         }
776         return TRUE;
777 }
778
779 void
780 MixerStrip::bundle_input_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
781 {
782         if (ignore_toggle) {
783                 return;
784         }
785
786         ARDOUR::BundleList current = _route->bundles_connected_to_inputs ();
787
788         if (std::find (current.begin(), current.end(), c) == current.end()) {
789                 _route->connect_input_ports_to_bundle (c, this);
790         } else {
791                 _route->disconnect_input_ports_from_bundle (c, this);
792         }
793 }
794
795 void
796 MixerStrip::bundle_output_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
797 {
798         if (ignore_toggle) {
799                 return;
800         }
801
802         ARDOUR::BundleList current = _route->bundles_connected_to_outputs ();
803
804         if (std::find (current.begin(), current.end(), c) == current.end()) {
805                 _route->connect_output_ports_to_bundle (c, this);
806         } else {
807                 _route->disconnect_output_ports_from_bundle (c, this);
808         }
809 }
810
811 void
812 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
813 {
814         using namespace Menu_Helpers;
815
816         if (b->ports_are_outputs() == false ||
817             route()->default_type() != b->type() ||
818             b->nchannels() != _route->n_inputs().get (b->type ())) {
819                 
820                 return;
821         }
822
823         MenuList& citems = input_menu.items();
824         
825         std::string n = b->name ();
826         replace_all (n, "_", " ");
827         
828         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_input_toggled), b)));
829         
830         if (std::find (current.begin(), current.end(), b) != current.end()) {
831                 ignore_toggle = true;
832                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
833                 ignore_toggle = false;
834         }
835 }
836
837 void
838 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
839 {
840         using namespace Menu_Helpers;
841
842         if (b->ports_are_inputs() == false ||
843             route()->default_type() != b->type() ||
844             b->nchannels() != _route->n_outputs().get (b->type ())) {
845                 
846                 return;
847         }
848
849         MenuList& citems = output_menu.items();
850         
851         std::string n = b->name ();
852         replace_all (n, "_", " ");
853         
854         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_output_toggled), b)));
855         
856         if (std::find (current.begin(), current.end(), b) != current.end()) {
857                 ignore_toggle = true;
858                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
859                 ignore_toggle = false;
860         }
861 }
862
863 void
864 MixerStrip::update_diskstream_display ()
865 {
866         if (is_track()) {
867
868                 if (input_selector) {
869                         input_selector->hide_all ();
870                 }
871
872                 show_route_color ();
873
874         } else {
875
876                 show_passthru_color ();
877         }
878 }
879
880 void
881 MixerStrip::connect_to_pan ()
882 {
883         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::connect_to_pan));
884
885         panstate_connection.disconnect ();
886         panstyle_connection.disconnect ();
887
888         if (!_route->panner()) {
889                 return;
890         }
891
892         boost::shared_ptr<ARDOUR::AutomationControl> pan_control
893                 = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
894                                 _route->panner()->data().control(Evoral::Parameter(PanAutomation)));
895
896         if (pan_control) {
897                 panstate_connection = pan_control->alist()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
898                 panstyle_connection = pan_control->alist()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
899         }
900
901         panners.pan_changed (this);
902 }
903
904 void
905 MixerStrip::update_input_display ()
906 {
907         ARDOUR::BundleList const c = _route->bundles_connected_to_inputs ();
908
909         if (c.size() > 1) {
910                 input_label.set_text (_("Inputs"));
911         } else if (c.size() == 1) {
912                 input_label.set_text (c[0]->name ());
913         } else {
914                 switch (_width) {
915                 case Wide:
916                         input_label.set_text (_(" Input"));
917                         break;
918                 case Narrow:
919                         input_label.set_text (_("I"));
920                         break;
921                 }
922         }
923         panners.setup_pan ();
924 }
925
926 void
927 MixerStrip::update_output_display ()
928 {
929         ARDOUR::BundleList const c = _route->bundles_connected_to_outputs ();
930
931         /* XXX: how do we represent >1 connected bundle? */
932         if (c.size() > 1) {
933                 output_label.set_text (_("Outputs"));
934         } else if (c.size() == 1) {
935                 output_label.set_text (c[0]->name());
936         } else {
937                 switch (_width) {
938                 case Wide:
939                         output_label.set_text (_("Output"));
940                         break;
941                 case Narrow:
942                         output_label.set_text (_("O"));
943                         break;
944                 }
945         }
946
947         gpm.setup_meters ();
948         panners.setup_pan ();
949 }
950
951 void
952 MixerStrip::fast_update ()
953 {
954         gpm.update_meters ();
955 }
956
957 void
958 MixerStrip::diskstream_changed ()
959 {
960         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
961 }       
962
963 void
964 MixerStrip::input_changed (IOChange change, void *src)
965 {
966         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
967         set_width(_width, this);
968 }
969
970 void
971 MixerStrip::output_changed (IOChange change, void *src)
972 {
973         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
974         set_width(_width, this);
975 }
976
977
978 void 
979 MixerStrip::comment_editor_done_editing() 
980 {
981         string str =  comment_area->get_buffer()->get_text();
982         if (_route->comment() != str) {
983                 _route->set_comment (str, this);
984
985                 switch (_width) {
986                    
987                 case Wide:
988                         if (! str.empty()) {
989                                 comment_button.modify_bg (STATE_NORMAL, color());
990                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
991                         } else {
992                                 comment_button.unset_bg (STATE_NORMAL);
993                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
994                         }
995                         break;
996                    
997                 case Narrow:
998                         if (! str.empty()) {
999                                 comment_button.modify_bg (STATE_NORMAL, color());
1000                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
1001                         } else {
1002                                 comment_button.unset_bg (STATE_NORMAL);
1003                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
1004                         } 
1005                         break;
1006                 }
1007                  
1008                 ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
1009                                 str.empty() ? _("Click to Add/Edit Comments") : str);
1010         }
1011
1012 }
1013
1014 void
1015 MixerStrip::comment_button_clicked ()
1016 {
1017         if (comment_window == 0) {
1018                 setup_comment_editor ();
1019         }
1020
1021     int x, y, cw_width, cw_height;
1022
1023         if (comment_window->is_visible()) {
1024                 comment_window->hide ();
1025                 return;
1026         }
1027
1028         comment_window->get_size (cw_width, cw_height);
1029         comment_window->get_position(x, y);
1030         comment_window->move(x, y - (cw_height / 2) - 45);
1031         /* 
1032            half the dialog height minus the comments button height 
1033            with some window decoration fudge thrown in.
1034         */
1035
1036         comment_window->show();
1037         comment_window->present();
1038 }
1039
1040 void
1041 MixerStrip::setup_comment_editor ()
1042 {
1043         string title;
1044         title = _route->name();
1045         title += _(": comment editor");
1046
1047         comment_window = new ArdourDialog (title, false);
1048         comment_window->set_position (Gtk::WIN_POS_MOUSE);
1049         comment_window->set_skip_taskbar_hint (true);
1050         comment_window->signal_hide().connect (mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1051
1052         comment_area = manage (new TextView());
1053         comment_area->set_name ("MixerTrackCommentArea");
1054         comment_area->set_size_request (110, 178);
1055         comment_area->set_wrap_mode (WRAP_WORD);
1056         comment_area->set_editable (true);
1057         comment_area->get_buffer()->set_text (_route->comment());
1058         comment_area->show ();
1059
1060         comment_window->get_vbox()->pack_start (*comment_area);
1061         comment_window->get_action_area()->hide();
1062 }
1063
1064 void
1065 MixerStrip::comment_changed (void *src)
1066 {
1067         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
1068         
1069         if (src != this) {
1070                 ignore_comment_edit = true;
1071                 if (comment_area) {
1072                         comment_area->get_buffer()->set_text (_route->comment());
1073                 }
1074                 ignore_comment_edit = false;
1075         }
1076 }
1077
1078 void
1079 MixerStrip::set_mix_group (RouteGroup *rg)
1080 {
1081         _route->set_mix_group (rg, this);
1082 }
1083
1084 void
1085 MixerStrip::add_mix_group_to_menu (RouteGroup *rg, RadioMenuItem::Group* group)
1086 {
1087         using namespace Menu_Helpers;
1088
1089         MenuList& items = group_menu->items();
1090
1091         items.push_back (RadioMenuElem (*group, rg->name(), bind (mem_fun(*this, &MixerStrip::set_mix_group), rg)));
1092
1093         if (_route->mix_group() == rg) {
1094                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
1095         }
1096 }
1097
1098 bool
1099 MixerStrip::select_mix_group (GdkEventButton *ev)
1100 {
1101         using namespace Menu_Helpers;
1102
1103         if (group_menu == 0) {
1104                 group_menu = new Menu;
1105         } 
1106         group_menu->set_name ("ArdourContextMenu");
1107         MenuList& items = group_menu->items();
1108         RadioMenuItem::Group group;
1109
1110         switch (ev->button) {
1111         case 1:
1112
1113                 items.clear ();
1114                 items.push_back (RadioMenuElem (group, _("No group"), bind (mem_fun(*this, &MixerStrip::set_mix_group), (RouteGroup *) 0)));
1115
1116                 _session.foreach_mix_group (bind (mem_fun (*this, &MixerStrip::add_mix_group_to_menu), &group));
1117
1118                 group_menu->popup (1, ev->time);
1119                 break;
1120
1121         default:
1122                 break;
1123         }
1124         
1125         return true;
1126 }       
1127
1128 void
1129 MixerStrip::mix_group_changed (void *ignored)
1130 {
1131         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::mix_group_changed), ignored));
1132         
1133         RouteGroup *rg = _route->mix_group();
1134         
1135         if (rg) {
1136                 group_label.set_text (rg->name());
1137         } else {
1138                 switch (_width) {
1139                 case Wide:
1140                         group_label.set_text (_("Grp"));
1141                         break;
1142                 case Narrow:
1143                         group_label.set_text (_("~G"));
1144                         break;
1145                 }
1146         }
1147 }
1148
1149
1150 void 
1151 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1152 {
1153         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1154         
1155         if (what_changed == "color") {
1156                 if (set_color_from_route () == 0) {
1157                         show_route_color ();
1158                 }
1159         }
1160 }
1161
1162 void
1163 MixerStrip::show_route_color ()
1164 {
1165         name_button.modify_bg (STATE_NORMAL, color());
1166         top_event_box.modify_bg (STATE_NORMAL, color());
1167         route_active_changed ();
1168 }
1169
1170 void
1171 MixerStrip::show_passthru_color ()
1172 {
1173         route_active_changed ();
1174 }
1175
1176 void
1177 MixerStrip::build_route_ops_menu ()
1178 {
1179         using namespace Menu_Helpers;
1180         route_ops_menu = new Menu;
1181         route_ops_menu->set_name ("ArdourContextMenu");
1182
1183         MenuList& items = route_ops_menu->items();
1184
1185         items.push_back (MenuElem (_("Save As Template"), mem_fun(*this, &RouteUI::save_as_template)));
1186         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1187         rename_menu_item = &items.back();
1188         items.push_back (SeparatorElem());
1189         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1190         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1191         route_active_menu_item->set_active (_route->active());
1192
1193         items.push_back (SeparatorElem());
1194
1195         items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
1196
1197         items.push_back (SeparatorElem());
1198         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1199         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1200         polarity_menu_item->set_active (_route->phase_invert());
1201         items.push_back (CheckMenuElem (_("Protect against denormals"), mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1202         denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1203         denormal_menu_item->set_active (_route->denormal_protection());
1204
1205         if (!Profile->get_sae()) {
1206                 build_remote_control_menu ();
1207                 items.push_back (SeparatorElem());
1208                 items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
1209         }
1210
1211         items.push_back (SeparatorElem());
1212         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1213 }
1214
1215 gint
1216 MixerStrip::name_button_button_press (GdkEventButton* ev)
1217 {
1218         if (ev->button == 1 || ev->button == 3) {
1219                 list_route_operations ();
1220
1221                 /* do not allow rename if the track is record-enabled */
1222                 rename_menu_item->set_sensitive (!_route->record_enabled());
1223                 route_ops_menu->popup (1, ev->time);
1224         }
1225         return FALSE;
1226 }
1227
1228 void
1229 MixerStrip::list_route_operations ()
1230 {
1231         if (route_ops_menu == 0) {
1232                 build_route_ops_menu ();
1233         }
1234         
1235         refresh_remote_control_menu();
1236 }
1237
1238
1239 void
1240 MixerStrip::speed_adjustment_changed ()
1241 {
1242         /* since there is a usable speed adjustment, there has to be a diskstream */
1243         if (!ignore_speed_adjustment) {
1244                 get_diskstream()->set_speed (speed_adjustment.get_value());
1245         }
1246 }
1247
1248 void
1249 MixerStrip::speed_changed ()
1250 {
1251         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_speed_display));
1252 }
1253
1254 void
1255 MixerStrip::update_speed_display ()
1256 {
1257         float val;
1258         
1259         val = get_diskstream()->speed();
1260
1261         if (val != 1.0) {
1262                 speed_spinner.set_name ("MixerStripSpeedBaseNotOne");
1263         } else {
1264                 speed_spinner.set_name ("MixerStripSpeedBase");
1265         }
1266
1267         if (speed_adjustment.get_value() != val) {
1268                 ignore_speed_adjustment = true;
1269                 speed_adjustment.set_value (val);
1270                 ignore_speed_adjustment = false;
1271         }
1272 }                       
1273
1274
1275 void
1276 MixerStrip::set_selected (bool yn)
1277 {
1278         AxisView::set_selected (yn);
1279         if (_selected) {
1280                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1281                 global_frame.set_name ("MixerStripSelectedFrame");
1282         } else {
1283                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1284                 global_frame.set_name ("MixerStripFrame");
1285         }
1286         global_frame.queue_draw ();
1287 }
1288
1289 void
1290 MixerStrip::name_changed ()
1291 {
1292         switch (_width) {
1293         case Wide:
1294                 RouteUI::name_changed ();
1295                 break;
1296         case Narrow:
1297                 name_label.set_text (PBD::short_version (_route->name(), 5));
1298                 break;
1299         }
1300         if (_route->phase_invert()) {
1301                 name_label.set_text (X_("Ø ") + name_label.get_text());
1302         }
1303 }
1304
1305 void
1306 MixerStrip::width_clicked ()
1307 {
1308         switch (_width) {
1309         case Wide:
1310                 set_width (Narrow, this);
1311                 break;
1312         case Narrow:
1313                 set_width (Wide, this);
1314                 break;
1315         }
1316 }
1317
1318 void
1319 MixerStrip::hide_clicked ()
1320 {
1321         // LAME fix to reset the button status for when it is redisplayed (part 1)
1322         hide_button.set_sensitive(false);
1323         
1324         if (_embedded) {
1325                 Hiding(); /* EMIT_SIGNAL */
1326         } else {
1327                 _mixer.hide_strip (this);
1328         }
1329         
1330         // (part 2)
1331         hide_button.set_sensitive(true);
1332 }
1333
1334 void
1335 MixerStrip::set_embedded (bool yn)
1336 {
1337         _embedded = yn;
1338 }
1339
1340 void
1341 MixerStrip::map_frozen ()
1342 {
1343         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1344
1345         boost::shared_ptr<AudioTrack> at = audio_track();
1346
1347         if (at) {
1348                 switch (at->freeze_state()) {
1349                 case AudioTrack::Frozen:
1350                         pre_processor_box.set_sensitive (false);
1351                         post_processor_box.set_sensitive (false);
1352                         speed_spinner.set_sensitive (false);
1353                         break;
1354                 default:
1355                         pre_processor_box.set_sensitive (true);
1356                         post_processor_box.set_sensitive (true);
1357                         speed_spinner.set_sensitive (true);
1358                         // XXX need some way, maybe, to retoggle redirect editors
1359                         break;
1360                 }
1361         }
1362         
1363         hide_redirect_editors ();
1364 }
1365
1366 void
1367 MixerStrip::hide_redirect_editors ()
1368 {
1369         _route->foreach_processor (mem_fun (*this, &MixerStrip::hide_processor_editor));
1370 }
1371
1372 void
1373 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1374 {
1375         boost::shared_ptr<Processor> processor (p.lock ());
1376         if (!processor) {
1377                 return;
1378         }
1379         
1380         void* gui = processor->get_gui ();
1381         
1382         if (gui) {
1383                 static_cast<Gtk::Widget*>(gui)->hide ();
1384         }
1385 }
1386
1387 void
1388 MixerStrip::route_active_changed ()
1389 {
1390         RouteUI::route_active_changed ();
1391
1392         if (is_midi_track()) {
1393                 if (_route->active()) {
1394                         set_name ("MidiTrackStripBase");
1395                         gpm.set_meter_strip_name ("MidiTrackStripBase");
1396                 } else {
1397                         set_name ("MidiTrackStripBaseInactive");
1398                         gpm.set_meter_strip_name ("MidiTrackStripBaseInactive");
1399                 }
1400                 gpm.set_fader_name ("MidiTrackFader");
1401         } else if (is_audio_track()) {
1402                 if (_route->active()) {
1403                         set_name ("AudioTrackStripBase");
1404                         gpm.set_meter_strip_name ("AudioTrackMetrics");
1405                 } else {
1406                         set_name ("AudioTrackStripBaseInactive");
1407                         gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
1408                 }
1409                 gpm.set_fader_name ("AudioTrackFader");
1410         } else {
1411                 if (_route->active()) {
1412                         set_name ("AudioBusStripBase");
1413                         gpm.set_meter_strip_name ("AudioBusMetrics");
1414                 } else {
1415                         set_name ("AudioBusStripBaseInactive");
1416                         gpm.set_meter_strip_name ("AudioBusMetricsInactive");
1417                 }
1418                 gpm.set_fader_name ("AudioBusFader");
1419                 
1420                 /* (no MIDI busses yet) */
1421         }
1422 }
1423
1424 RouteGroup*
1425 MixerStrip::mix_group() const
1426 {
1427         return _route->mix_group();
1428 }
1429
1430 void
1431 MixerStrip::engine_stopped ()
1432 {
1433 }
1434
1435 void
1436 MixerStrip::engine_running ()
1437 {
1438 }
1439
1440 void
1441 MixerStrip::meter_changed (void *src)
1442 {
1443         ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
1444
1445         switch (_route->meter_point()) {
1446         case MeterInput:
1447                 meter_point_label.set_text (_("input"));
1448                 break;
1449
1450         case MeterPreFader:
1451                 meter_point_label.set_text (_("pre"));
1452                 break;
1453                 
1454         case MeterPostFader:
1455                 meter_point_label.set_text (_("post"));
1456                 break;
1457         }
1458
1459         gpm.setup_meters ();
1460         // reset peak when meter point changes
1461         gpm.reset_peak_display();
1462         set_width(_width, this);
1463 }
1464