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