Added nicer looking wrapper methods for ChanCount::get(DataType), sedified code to...
[ardour.git] / gtk2_ardour / audio_time_axis.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
20 #include <cstdlib>
21 #include <cmath>
22 #include <cassert>
23
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27
28 #include <sigc++/bind.h>
29
30 #include <pbd/error.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/memento_command.h>
33
34 #include <gtkmm2ext/gtk_ui.h>
35 #include <gtkmm2ext/selector.h>
36 #include <gtkmm2ext/stop_signal.h>
37 #include <gtkmm2ext/bindable_button.h>
38 #include <gtkmm2ext/utils.h>
39
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audio_diskstream.h>
42 #include <ardour/insert.h>
43 #include <ardour/location.h>
44 #include <ardour/panner.h>
45 #include <ardour/playlist.h>
46 #include <ardour/session.h>
47 #include <ardour/session_playlist.h>
48 #include <ardour/utils.h>
49
50 #include "ardour_ui.h"
51 #include "audio_time_axis.h"
52 #include "automation_gain_line.h"
53 #include "automation_pan_line.h"
54 #include "canvas_impl.h"
55 #include "crossfade_view.h"
56 #include "enums.h"
57 #include "gain_automation_time_axis.h"
58 #include "keyboard.h"
59 #include "pan_automation_time_axis.h"
60 #include "playlist_selector.h"
61 #include "prompter.h"
62 #include "public_editor.h"
63 #include "audio_region_view.h"
64 #include "simplerect.h"
65 #include "audio_streamview.h"
66 #include "utils.h"
67
68 #include <ardour/audio_track.h>
69
70 #include "i18n.h"
71
72 using namespace ARDOUR;
73 using namespace PBD;
74 using namespace Gtk;
75 using namespace Editing;
76
77
78 AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
79         : AxisView(sess)
80         , RouteTimeAxisView(ed, sess, rt, canvas)
81 {
82         // Make sure things are sane...
83         assert(!is_track() || is_audio_track());
84
85         subplugin_menu.set_name ("ArdourContextMenu");
86         gain_track = 0;
87         pan_track = 0;
88         waveform_item = 0;
89         pan_automation_item = 0;
90         gain_automation_item = 0;
91
92         _view = new AudioStreamView (*this);
93
94         add_gain_automation_child ();
95         add_pan_automation_child ();
96
97         ignore_toggle = false;
98
99         mute_button->set_active (false);
100         solo_button->set_active (false);
101         
102         if (is_audio_track())
103                 controls_ebox.set_name ("AudioTimeAxisViewControlsBaseUnselected");
104         else // bus
105                 controls_ebox.set_name ("AudioBusControlsBaseUnselected");
106
107         /* map current state of the route */
108
109         redirects_changed (0);
110         reset_redirect_automation_curves ();
111
112         ensure_xml_node ();
113
114         set_state (*xml_node);
115         
116         _route->panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans));
117
118         update_control_names ();
119
120         if (is_audio_track()) {
121
122                 /* ask for notifications of any new RegionViews */
123                 _view->RegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added));
124                 _view->attach ();
125         }
126
127         post_construct ();
128 }
129
130 AudioTimeAxisView::~AudioTimeAxisView ()
131 {
132 }
133
134 AudioStreamView*
135 AudioTimeAxisView::audio_view()
136 {
137         return dynamic_cast<AudioStreamView*>(_view);
138 }
139
140 guint32
141 AudioTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
142 {
143         ensure_xml_node ();
144         xml_node->add_property ("shown_editor", "yes");
145                 
146         return TimeAxisView::show_at (y, nth, parent);
147 }
148
149 void
150 AudioTimeAxisView::hide ()
151 {
152         ensure_xml_node ();
153         xml_node->add_property ("shown_editor", "no");
154
155         TimeAxisView::hide ();
156 }
157
158 void
159 AudioTimeAxisView::set_state (const XMLNode& node)
160 {
161         const XMLProperty *prop;
162         
163         TimeAxisView::set_state (node);
164         
165         if ((prop = node.property ("shown_editor")) != 0) {
166                 if (prop->value() == "no") {
167                         _marked_for_display = false;
168                 } else {
169                         _marked_for_display = true;
170                 }
171         } else {
172                 _marked_for_display = true;
173         }
174         
175         XMLNodeList nlist = node.children();
176         XMLNodeConstIterator niter;
177         XMLNode *child_node;
178         
179         
180         show_gain_automation = false;
181         show_pan_automation  = false;
182         
183         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
184                 child_node = *niter;
185
186                 if (child_node->name() == "gain") {
187                         XMLProperty *prop=child_node->property ("shown");
188                         
189                         if (prop != 0) {
190                                 if (prop->value() == "yes") {
191                                         show_gain_automation = true;
192                                 }
193                         }
194                         continue;
195                 }
196                 
197                 if (child_node->name() == "pan") {
198                         XMLProperty *prop=child_node->property ("shown");
199                         
200                         if (prop != 0) {
201                                 if (prop->value() == "yes") {
202                                         show_pan_automation = true;
203                                 }                       
204                         }
205                         continue;
206                 }
207         }
208 }
209
210 void
211 AudioTimeAxisView::build_automation_action_menu ()
212 {
213         using namespace Menu_Helpers;
214
215         RouteTimeAxisView::build_automation_action_menu ();
216
217         MenuList& automation_items = automation_action_menu->items();
218         
219         automation_items.push_back (SeparatorElem());
220
221         automation_items.push_back (CheckMenuElem (_("Fader"), 
222                                                    mem_fun(*this, &AudioTimeAxisView::toggle_gain_track)));
223         gain_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
224         gain_automation_item->set_active(show_gain_automation);
225
226         automation_items.push_back (CheckMenuElem (_("Pan"),
227                                                    mem_fun(*this, &AudioTimeAxisView::toggle_pan_track)));
228         pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
229         pan_automation_item->set_active(show_pan_automation);
230         
231 }
232
233 void
234 AudioTimeAxisView::append_extra_display_menu_items ()
235 {
236         using namespace Menu_Helpers;
237
238         MenuList& items = display_menu->items();
239
240         // crossfade stuff
241         items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
242         items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
243
244         // waveform menu
245         Menu *waveform_menu = manage(new Menu);
246         MenuList& waveform_items = waveform_menu->items();
247         waveform_menu->set_name ("ArdourContextMenu");
248         
249         waveform_items.push_back (CheckMenuElem (_("Show waveforms"), mem_fun(*this, &AudioTimeAxisView::toggle_waveforms)));
250         waveform_item = static_cast<CheckMenuItem *> (&waveform_items.back());
251         ignore_toggle = true;
252         waveform_item->set_active (editor.show_waveforms());
253         ignore_toggle = false;
254
255         waveform_items.push_back (SeparatorElem());
256         
257         RadioMenuItem::Group group;
258         
259         waveform_items.push_back (RadioMenuElem (group, _("Traditional"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Traditional)));
260         traditional_item = static_cast<RadioMenuItem *> (&waveform_items.back());
261
262         waveform_items.push_back (RadioMenuElem (group, _("Rectified"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Rectified)));
263         rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
264
265         waveform_items.push_back (SeparatorElem());
266         
267         RadioMenuItem::Group group2;
268
269         waveform_items.push_back (RadioMenuElem (group2, _("Linear"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LinearWaveform)));
270         linearscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
271
272         waveform_items.push_back (RadioMenuElem (group2, _("Logarithmic"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LogWaveform)));
273         logscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
274
275         // setting initial item state
276         AudioStreamView* asv = audio_view();
277         if (asv) {
278                 ignore_toggle = true;
279                 if (asv->get_waveform_shape() == Rectified) 
280                         rectified_item->set_active(true);
281                 else traditional_item->set_active(true);
282
283                 if (asv->get_waveform_scale() == LogWaveform) 
284                         logscale_item->set_active(true);
285                 else linearscale_item->set_active(true);
286                 ignore_toggle = false;
287         }
288
289         items.push_back (MenuElem (_("Waveform"), *waveform_menu));
290 }
291
292 void
293 AudioTimeAxisView::toggle_waveforms ()
294 {
295         AudioStreamView* asv = audio_view();
296         assert(asv);
297
298         if (asv && waveform_item && !ignore_toggle) {
299                 asv->set_show_waveforms (waveform_item->get_active());
300         }
301 }
302
303 void
304 AudioTimeAxisView::set_show_waveforms (bool yn)
305 {
306         AudioStreamView* asv = audio_view();
307         assert(asv);
308
309         if (waveform_item) {
310                 waveform_item->set_active (yn);
311         } else {
312                 asv->set_show_waveforms (yn);
313         }
314 }
315
316 void
317 AudioTimeAxisView::set_show_waveforms_recording (bool yn)
318 {
319         AudioStreamView* asv = audio_view();
320
321         if (asv) {
322                 asv->set_show_waveforms_recording (yn);
323         }
324 }
325
326 void
327 AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
328 {
329         AudioStreamView* asv = audio_view();
330
331         if (asv && !ignore_toggle) {
332                 asv->set_waveform_shape (shape);
333         }
334
335         map_frozen ();
336 }       
337
338 void
339 AudioTimeAxisView::set_waveform_scale (WaveformScale scale)
340 {
341         AudioStreamView* asv = audio_view();
342
343         if (asv && !ignore_toggle) {
344                 asv->set_waveform_scale (scale);
345         }
346
347         map_frozen ();
348 }       
349
350 void
351 AudioTimeAxisView::add_gain_automation_child ()
352 {
353         XMLProperty* prop;
354         AutomationLine* line;
355
356         gain_track = new GainAutomationTimeAxisView (_session,
357                                                      _route,
358                                                      editor,
359                                                      *this,
360                                                      parent_canvas,
361                                                      _("gain"),
362                                                      _route->gain_automation_curve());
363         
364         line = new AutomationGainLine ("automation gain",
365                                        _session,
366                                        *gain_track,
367                                        *gain_track->canvas_display,
368                                        _route->gain_automation_curve());
369
370         line->set_line_color (color_map[cAutomationLine]);
371         
372
373         gain_track->add_line (*line);
374
375         add_child (gain_track);
376
377         gain_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::gain_hidden));
378
379         bool hideit = true;
380         
381         XMLNode* node;
382
383         if ((node = gain_track->get_state_node()) != 0) {
384                 if  ((prop = node->property ("shown")) != 0) {
385                         if (prop->value() == "yes") {
386                                 hideit = false;
387                         }
388                 } 
389         }
390
391         if (hideit) {
392                 gain_track->hide ();
393         }
394 }
395
396 void
397 AudioTimeAxisView::add_pan_automation_child ()
398 {
399         XMLProperty* prop;
400
401         pan_track = new PanAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, _("pan"));
402
403         update_pans ();
404         
405         add_child (pan_track);
406
407         pan_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::pan_hidden));
408
409         ensure_xml_node ();
410         bool hideit = true;
411         
412         XMLNode* node;
413
414         if ((node = pan_track->get_state_node()) != 0) {
415                 if ((prop = node->property ("shown")) != 0) {
416                         if (prop->value() == "yes") {
417                                 hideit = false;
418                         }
419                 } 
420         }
421
422         if (hideit) {
423                 pan_track->hide ();
424         }
425 }
426
427 void
428 AudioTimeAxisView::update_pans ()
429 {
430         Panner::iterator p;
431         
432         pan_track->clear_lines ();
433         
434         /* we don't draw lines for "greater than stereo" panning.
435          */
436
437         if (_route->n_outputs().n_audio() > 2) {
438                 return;
439         }
440
441         for (p = _route->panner().begin(); p != _route->panner().end(); ++p) {
442
443                 AutomationLine* line;
444
445                 line = new AutomationPanLine ("automation pan", _session, *pan_track,
446                                               *pan_track->canvas_display, 
447                                               (*p)->automation());
448
449                 if (p == _route->panner().begin()) {
450                         /* first line is a nice orange */
451                         line->set_line_color (color_map[cLeftPanAutomationLine]);
452                 } else {
453                         /* second line is a nice blue */
454                         line->set_line_color (color_map[cRightPanAutomationLine]);
455                 }
456
457                 pan_track->add_line (*line);
458         }
459 }
460                 
461 void
462 AudioTimeAxisView::toggle_gain_track ()
463 {
464
465         bool showit = gain_automation_item->get_active();
466
467         if (showit != gain_track->marked_for_display()) {
468                 if (showit) {
469                         gain_track->set_marked_for_display (true);
470                         gain_track->canvas_display->show();
471                         gain_track->get_state_node()->add_property ("shown", X_("yes"));
472                 } else {
473                         gain_track->set_marked_for_display (false);
474                         gain_track->hide ();
475                         gain_track->get_state_node()->add_property ("shown", X_("no"));
476                 }
477
478                 /* now trigger a redisplay */
479                 
480                 if (!no_redraw) {
481                          _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
482                 }
483         }
484 }
485
486 void
487 AudioTimeAxisView::gain_hidden ()
488 {
489         gain_track->get_state_node()->add_property (X_("shown"), X_("no"));
490
491         if (gain_automation_item && !_hidden) {
492                 gain_automation_item->set_active (false);
493         }
494
495          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
496 }
497
498 void
499 AudioTimeAxisView::toggle_pan_track ()
500 {
501         bool showit = pan_automation_item->get_active();
502
503         if (showit != pan_track->marked_for_display()) {
504                 if (showit) {
505                         pan_track->set_marked_for_display (true);
506                         pan_track->canvas_display->show();
507                         pan_track->get_state_node()->add_property ("shown", X_("yes"));
508                 } else {
509                         pan_track->set_marked_for_display (false);
510                         pan_track->hide ();
511                         pan_track->get_state_node()->add_property ("shown", X_("no"));
512                 }
513
514                 /* now trigger a redisplay */
515                 
516                 if (!no_redraw) {
517                          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
518                 }
519         }
520 }
521
522 void
523 AudioTimeAxisView::pan_hidden ()
524 {
525         pan_track->get_state_node()->add_property ("shown", "no");
526
527         if (pan_automation_item && !_hidden) {
528                 pan_automation_item->set_active (false);
529         }
530
531          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
532 }
533
534 void
535 AudioTimeAxisView::show_all_automation ()
536 {
537         no_redraw = true;
538
539         pan_automation_item->set_active (true);
540         gain_automation_item->set_active (true);
541         
542         RouteTimeAxisView::show_all_automation ();
543
544         no_redraw = false;
545
546          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
547 }
548
549 void
550 AudioTimeAxisView::show_existing_automation ()
551 {
552         no_redraw = true;
553
554         pan_automation_item->set_active (true);
555         gain_automation_item->set_active (true);
556
557         RouteTimeAxisView::show_existing_automation ();
558
559         no_redraw = false;
560
561          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
562 }
563
564 void
565 AudioTimeAxisView::hide_all_automation ()
566 {
567         no_redraw = true;
568
569         pan_automation_item->set_active (false);
570         gain_automation_item->set_active (false);
571
572         RouteTimeAxisView::hide_all_automation();
573
574         no_redraw = false;
575          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
576 }
577
578 void
579 AudioTimeAxisView::show_all_xfades ()
580 {
581         AudioStreamView* asv = audio_view();
582
583         if (asv) {
584                 asv->show_all_xfades ();
585         }
586 }
587
588 void
589 AudioTimeAxisView::hide_all_xfades ()
590 {
591         AudioStreamView* asv = audio_view();
592         
593         if (asv) {
594                 asv->hide_all_xfades ();
595         }
596 }
597
598 void
599 AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi)
600 {
601         AudioStreamView* asv = audio_view();
602         AudioRegionView* rv;
603
604         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
605                 asv->hide_xfades_involving (*rv);
606         }
607 }
608
609 void
610 AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
611 {
612         AudioStreamView* asv = audio_view();
613         AudioRegionView* rv;
614
615         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
616                 asv->reveal_xfades_involving (*rv);
617         }
618 }
619
620 void
621 AudioTimeAxisView::route_active_changed ()
622 {
623         RouteTimeAxisView::route_active_changed ();
624         update_control_names ();
625 }
626
627
628 /**
629  *    Set up the names of the controls so that they are coloured
630  *    correctly depending on whether this route is inactive or
631  *    selected.
632  */
633
634 void
635 AudioTimeAxisView::update_control_names ()
636 {
637         if (is_audio_track()) {
638                 if (_route->active()) {
639                         controls_ebox.set_name ("AudioTrackControlsBaseUnselected");
640                         controls_base_selected_name = "AudioTrackControlsBaseSelected";
641                         controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
642                 } else {
643                         controls_ebox.set_name ("AudioTrackControlsBaseInactiveUnselected");
644                         controls_base_selected_name = "AudioTrackControlsBaseInactiveSelected";
645                         controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected";
646                 }
647         } else {
648                 if (_route->active()) {
649                         controls_ebox.set_name ("BusControlsBaseUnselected");
650                         controls_base_selected_name = "BusControlsBaseSelected";
651                         controls_base_unselected_name = "BusControlsBaseUnselected";
652                 } else {
653                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
654                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
655                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
656                 }
657         }
658 }
659
660 XMLNode* 
661 AudioTimeAxisView::get_child_xml_node (const string & childname)
662 {
663         return RouteUI::get_child_xml_node (childname);
664 }
665