2 Copyright (C) 2000 Paul Davis
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.
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.
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.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/whitespace.h"
31 #include "pbd/basename.h"
32 #include "pbd/enumwriter.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/stateful_diff_command.h"
36 #include "gtkmm2ext/gtk_ui.h"
37 #include "gtkmm2ext/selector.h"
38 #include "gtkmm2ext/bindable_button.h"
39 #include "gtkmm2ext/utils.h"
41 #include "ardour/file_source.h"
42 #include "ardour/midi_playlist.h"
43 #include "ardour/midi_diskstream.h"
44 #include "ardour/midi_patch_manager.h"
45 #include "ardour/midi_source.h"
46 #include "ardour/processor.h"
47 #include "ardour/ladspa_plugin.h"
48 #include "ardour/location.h"
49 #include "ardour/playlist.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/session.h"
52 #include "ardour/session_playlist.h"
53 #include "ardour/tempo.h"
54 #include "ardour/utils.h"
55 #include "ardour/operations.h"
57 #include "midi++/names.h"
59 #include "add_midi_cc_track_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_line.h"
62 #include "automation_time_axis.h"
63 #include "canvas-note-event.h"
64 #include "canvas_impl.h"
65 #include "crossfade_view.h"
68 #include "ghostregion.h"
69 #include "gui_thread.h"
71 #include "midi_scroomer.h"
72 #include "midi_streamview.h"
73 #include "midi_region_view.h"
74 #include "midi_time_axis.h"
75 #include "piano_roll_header.h"
76 #include "playlist_selector.h"
77 #include "plugin_selector.h"
78 #include "plugin_ui.h"
79 #include "point_selection.h"
81 #include "region_view.h"
82 #include "rgb_macros.h"
83 #include "selection.h"
84 #include "step_editor.h"
85 #include "simplerect.h"
88 #include "ardour/midi_track.h"
92 using namespace ARDOUR;
95 using namespace Gtkmm2ext;
96 using namespace Editing;
98 // Minimum height at which a control is displayed
99 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
100 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
102 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
103 boost::shared_ptr<Route> rt, Canvas& canvas)
104 : AxisView(sess) // virtually inherited
105 , RouteTimeAxisView(ed, sess, rt, canvas)
106 , _ignore_signals(false)
108 , _piano_roll_header(0)
109 , _note_mode(Sustained)
111 , _percussion_mode_item(0)
112 , _color_mode(MeterColors)
113 , _meter_color_mode_item(0)
114 , _channel_color_mode_item(0)
115 , _track_color_mode_item(0)
116 , _step_edit_item (0)
117 , _midi_thru_item (0)
118 , default_channel_menu (0)
119 , controller_menu (0)
122 subplugin_menu.set_name ("ArdourContextMenu");
124 _view = new MidiStreamView (*this);
126 ignore_toggle = false;
128 mute_button->set_active (false);
129 solo_button->set_active (false);
131 if (is_midi_track()) {
132 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
133 _note_mode = midi_track()->note_mode();
134 } else { // MIDI bus (which doesn't exist yet..)
135 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
138 /* map current state of the route */
140 processors_changed (RouteProcessorChange ());
144 set_state (*xml_node, Stateful::loading_state_version);
146 _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
149 _piano_roll_header = new PianoRollHeader(*midi_view());
151 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
152 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
153 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
155 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
157 controls_hbox.pack_start(*_range_scroomer);
158 controls_hbox.pack_start(*_piano_roll_header);
160 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
161 controls_base_selected_name = "MidiTrackControlsBaseSelected";
162 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
164 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
166 /* ask for notifications of any new RegionViews */
167 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
169 if (!_editor.have_idled()) {
170 /* first idle will do what we need */
176 HBox* midi_controls_hbox = manage(new HBox());
178 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
180 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
181 for (; m != patch_manager.all_models().end(); ++m) {
182 _model_selector.append_text(m->c_str());
185 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
187 _custom_device_mode_selector.signal_changed().connect(
188 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
190 // TODO: persist the choice
191 // this initializes the comboboxes and sends out the signal
192 _model_selector.set_active(0);
194 midi_controls_hbox->pack_start(_channel_selector, true, false);
195 if (!patch_manager.all_models().empty()) {
196 _midi_controls_box.pack_start(_model_selector, true, false);
197 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
200 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
202 controls_vbox.pack_start(_midi_controls_box, false, false);
204 // restore channel selector settings
205 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
206 _channel_selector.mode_changed.connect(
207 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
208 _channel_selector.mode_changed.connect(
209 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
212 if ((prop = xml_node->property ("color-mode")) != 0) {
213 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
214 if (_color_mode == ChannelColors) {
215 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
219 if ((prop = xml_node->property ("note-mode")) != 0) {
220 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
221 if (_percussion_mode_item) {
222 _percussion_mode_item->set_active (_note_mode == Percussive);
228 MidiTimeAxisView::first_idle ()
235 MidiTimeAxisView::~MidiTimeAxisView ()
237 delete _piano_roll_header;
238 _piano_roll_header = 0;
240 delete _range_scroomer;
243 delete controller_menu;
248 MidiTimeAxisView::check_step_edit ()
250 _step_editor->check_step_edit ();
254 MidiTimeAxisView::model_changed()
256 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
257 .custom_device_mode_names_by_model(_model_selector.get_active_text());
259 _custom_device_mode_selector.clear_items();
261 for (std::list<std::string>::const_iterator i = device_modes.begin();
262 i != device_modes.end(); ++i) {
263 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
264 _custom_device_mode_selector.append_text(*i);
267 _custom_device_mode_selector.set_active(0);
270 void MidiTimeAxisView::custom_device_mode_changed()
272 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
273 _custom_device_mode_selector.get_active_text());
277 MidiTimeAxisView::midi_view()
279 return dynamic_cast<MidiStreamView*>(_view);
283 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
286 xml_node->add_property ("shown-editor", "yes");
288 guint32 ret = TimeAxisView::show_at (y, nth, parent);
293 MidiTimeAxisView::hide ()
296 xml_node->add_property ("shown-editor", "no");
298 TimeAxisView::hide ();
302 MidiTimeAxisView::set_height (uint32_t h)
304 RouteTimeAxisView::set_height (h);
306 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
307 _midi_controls_box.show_all ();
309 _midi_controls_box.hide();
312 if (height >= KEYBOARD_MIN_HEIGHT) {
313 if (is_track() && _range_scroomer)
314 _range_scroomer->show();
315 if (is_track() && _piano_roll_header)
316 _piano_roll_header->show();
318 if (is_track() && _range_scroomer)
319 _range_scroomer->hide();
320 if (is_track() && _piano_roll_header)
321 _piano_roll_header->hide();
326 MidiTimeAxisView::append_extra_display_menu_items ()
328 using namespace Menu_Helpers;
330 MenuList& items = display_menu->items();
333 Menu *range_menu = manage(new Menu);
334 MenuList& range_items = range_menu->items();
335 range_menu->set_name ("ArdourContextMenu");
337 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
338 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
339 MidiStreamView::FullRange)));
341 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
342 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
343 MidiStreamView::ContentsRange)));
345 items.push_back (MenuElem (_("Note range"), *range_menu));
346 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
347 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
349 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
350 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
354 MidiTimeAxisView::build_def_channel_menu ()
356 using namespace Menu_Helpers;
358 default_channel_menu = manage (new Menu ());
360 uint8_t defchn = midi_track()->default_channel();
361 MenuList& def_channel_items = default_channel_menu->items();
363 RadioMenuItem::Group dc_group;
365 for (int i = 0; i < 16; ++i) {
367 snprintf (buf, sizeof (buf), "%d", i+1);
369 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
370 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
371 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
372 item->set_active ((i == defchn));
375 return default_channel_menu;
379 MidiTimeAxisView::set_default_channel (int chn)
381 midi_track()->set_default_channel (chn);
385 MidiTimeAxisView::toggle_midi_thru ()
387 if (!_midi_thru_item) {
391 bool view_yn = _midi_thru_item->get_active();
392 if (view_yn != midi_track()->midi_thru()) {
393 midi_track()->set_midi_thru (view_yn);
398 MidiTimeAxisView::build_automation_action_menu ()
400 using namespace Menu_Helpers;
402 /* If we have a controller menu, we need to detach it before
403 RouteTimeAxis::build_automation_action_menu destroys the
404 menu it is attached to. Otherwise GTK destroys
405 controller_menu's gobj, meaning that it can't be reattached
406 below. See bug #3134.
409 if (controller_menu) {
410 detach_menu (*controller_menu);
413 _channel_command_menu_map.clear ();
414 RouteTimeAxisView::build_automation_action_menu ();
416 MenuList& automation_items = automation_action_menu->items();
418 uint16_t selected_channels = _channel_selector.get_selected_channels();
420 if (selected_channels != 0) {
422 automation_items.push_back (SeparatorElem());
424 /* these 2 MIDI "command" types are semantically more like automation than note data,
425 but they are not MIDI controllers. We give them special status in this menu, since
426 they will not show up in the controller list and anyone who actually knows
427 something about MIDI (!) would not expect to find them there.
430 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
431 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
433 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
434 since it might need to be updated after a channel mode change or other change. Also detach it
435 first in case it has been used anywhere else.
438 build_controller_menu ();
440 automation_items.push_back (SeparatorElem());
441 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
443 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
449 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
451 uint16_t selected_channels = _channel_selector.get_selected_channels();
453 for (uint8_t chn = 0; chn < 16; chn++) {
454 if (selected_channels & (0x0001 << chn)) {
456 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
457 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
460 menu->set_active (yn);
467 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
469 using namespace Menu_Helpers;
471 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
474 uint16_t selected_channels = _channel_selector.get_selected_channels();
477 for (uint8_t chn = 0; chn < 16; chn++) {
478 if (selected_channels & (0x0001 << chn)) {
487 /* multiple channels - create a submenu, with 1 item per channel */
489 Menu* chn_menu = manage (new Menu);
490 MenuList& chn_items (chn_menu->items());
491 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
493 /* add a couple of items to hide/show all of them */
495 chn_items.push_back (MenuElem (_("Hide all channels"),
496 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
497 false, param_without_channel)));
498 chn_items.push_back (MenuElem (_("Show all channels"),
499 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
500 true, param_without_channel)));
502 for (uint8_t chn = 0; chn < 16; chn++) {
503 if (selected_channels & (0x0001 << chn)) {
505 /* for each selected channel, add a menu item for this controller */
507 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
508 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
509 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
510 fully_qualified_param)));
512 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
513 bool visible = false;
516 if (track->marked_for_display()) {
521 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
522 _channel_command_menu_map[fully_qualified_param] = cmi;
523 cmi->set_active (visible);
527 /* now create an item in the parent menu that has the per-channel list as a submenu */
529 items.push_back (MenuElem (label, *chn_menu));
533 /* just one channel - create a single menu item for this command+channel combination*/
535 for (uint8_t chn = 0; chn < 16; chn++) {
536 if (selected_channels & (0x0001 << chn)) {
538 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
539 items.push_back (CheckMenuElem (label,
540 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
541 fully_qualified_param)));
543 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
544 bool visible = false;
547 if (track->marked_for_display()) {
552 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
553 _channel_command_menu_map[fully_qualified_param] = cmi;
554 cmi->set_active (visible);
556 /* one channel only */
564 MidiTimeAxisView::build_controller_menu ()
566 using namespace Menu_Helpers;
568 if (controller_menu) {
569 /* it exists and has not been invalidated by a channel mode change, so just return it */
573 controller_menu = new Menu; // explicitly managed by us
574 MenuList& items (controller_menu->items());
576 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
577 for each controller+channel combination covering the currently selected channels for this track
580 uint16_t selected_channels = _channel_selector.get_selected_channels();
582 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
587 for (uint8_t chn = 0; chn < 16; chn++) {
588 if (selected_channels & (0x0001 << chn)) {
595 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
596 bank select controllers, as they are handled by the `patch' code */
598 for (int i = 0; i < 127; i += 16) {
600 Menu* ctl_menu = manage (new Menu);
601 MenuList& ctl_items (ctl_menu->items());
604 /* for each controller, consider whether to create a submenu or a single item */
606 for (int ctl = i; ctl < i+16; ++ctl) {
608 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
614 /* multiple channels - create a submenu, with 1 item per channel */
616 Menu* chn_menu = manage (new Menu);
617 MenuList& chn_items (chn_menu->items());
619 /* add a couple of items to hide/show this controller on all channels */
621 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
622 chn_items.push_back (MenuElem (_("Hide all channels"),
623 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
624 false, param_without_channel)));
625 chn_items.push_back (MenuElem (_("Show all channels"),
626 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
627 true, param_without_channel)));
629 for (uint8_t chn = 0; chn < 16; chn++) {
630 if (selected_channels & (0x0001 << chn)) {
632 /* for each selected channel, add a menu item for this controller */
634 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
635 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
636 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
637 fully_qualified_param)));
639 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
640 bool visible = false;
643 if (track->marked_for_display()) {
648 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
649 _controller_menu_map[fully_qualified_param] = cmi;
650 cmi->set_active (visible);
654 /* add the per-channel menu to the list of controllers, with the name of the controller */
655 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
656 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
660 /* just one channel - create a single menu item for this ctl+channel combination*/
662 for (uint8_t chn = 0; chn < 16; chn++) {
663 if (selected_channels & (0x0001 << chn)) {
665 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
666 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
667 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
668 fully_qualified_param)));
670 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
671 bool visible = false;
674 if (track->marked_for_display()) {
679 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
680 _controller_menu_map[fully_qualified_param] = cmi;
681 cmi->set_active (visible);
683 /* one channel only */
690 /* add the menu for this block of controllers to the overall controller menu */
692 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
697 MidiTimeAxisView::build_note_mode_menu()
699 using namespace Menu_Helpers;
701 Menu* mode_menu = manage (new Menu);
702 MenuList& items = mode_menu->items();
703 mode_menu->set_name ("ArdourContextMenu");
705 RadioMenuItem::Group mode_group;
706 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
707 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
708 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
709 _note_mode_item->set_active(_note_mode == Sustained);
711 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
712 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
713 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
714 _percussion_mode_item->set_active(_note_mode == Percussive);
720 MidiTimeAxisView::build_color_mode_menu()
722 using namespace Menu_Helpers;
724 Menu* mode_menu = manage (new Menu);
725 MenuList& items = mode_menu->items();
726 mode_menu->set_name ("ArdourContextMenu");
728 RadioMenuItem::Group mode_group;
729 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
730 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
731 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
732 _meter_color_mode_item->set_active(_color_mode == MeterColors);
734 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
735 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
736 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
737 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
739 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
740 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
741 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
742 _channel_color_mode_item->set_active(_color_mode == TrackColor);
748 MidiTimeAxisView::set_note_mode(NoteMode mode)
750 if (_note_mode != mode || midi_track()->note_mode() != mode) {
752 midi_track()->set_note_mode(mode);
753 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
754 _view->redisplay_track();
759 MidiTimeAxisView::set_color_mode(ColorMode mode)
761 if (_color_mode != mode) {
762 if (mode == ChannelColors) {
763 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
765 _channel_selector.set_default_channel_color();
769 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
770 _view->redisplay_track();
775 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
777 if (!_ignore_signals)
778 midi_view()->set_note_range(range);
783 MidiTimeAxisView::update_range()
785 MidiGhostRegion* mgr;
787 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
788 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
795 MidiTimeAxisView::show_all_automation ()
798 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
800 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
801 create_automation_child(*i, true);
805 RouteTimeAxisView::show_all_automation ();
809 MidiTimeAxisView::show_existing_automation ()
812 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
814 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
815 create_automation_child(*i, true);
819 RouteTimeAxisView::show_existing_automation ();
822 /** Create an automation track for the given parameter (pitch bend, channel pressure).
825 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
827 if (param.type() == NullAutomation) {
828 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
832 AutomationTracks::iterator existing = _automation_tracks.find (param);
833 if (existing != _automation_tracks.end()) {
837 if (param.type() == GainAutomation) {
838 create_gain_automation_child (param, show);
841 /* These controllers are region "automation", so we do not create
842 * an AutomationList/Line for the track */
844 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
847 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
848 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
853 _route->describe_parameter(param)));
855 add_automation_child (param, track, show);
861 MidiTimeAxisView::route_active_changed ()
863 RouteUI::route_active_changed ();
866 if (_route->active()) {
867 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
868 controls_base_selected_name = "MidiTrackControlsBaseSelected";
869 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
871 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
872 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
873 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
879 if (_route->active()) {
880 controls_ebox.set_name ("BusControlsBaseUnselected");
881 controls_base_selected_name = "BusControlsBaseSelected";
882 controls_base_unselected_name = "BusControlsBaseUnselected";
884 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
885 controls_base_selected_name = "BusControlsBaseInactiveSelected";
886 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
894 MidiTimeAxisView::add_note_selection (uint8_t note)
896 if (!_editor.internal_editing()) {
900 uint16_t chn_mask = _channel_selector.get_selected_channels();
902 if (_view->num_selected_regionviews() == 0) {
903 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
905 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
910 MidiTimeAxisView::extend_note_selection (uint8_t note)
912 if (!_editor.internal_editing()) {
916 uint16_t chn_mask = _channel_selector.get_selected_channels();
918 if (_view->num_selected_regionviews() == 0) {
919 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
921 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
926 MidiTimeAxisView::toggle_note_selection (uint8_t note)
928 if (!_editor.internal_editing()) {
932 uint16_t chn_mask = _channel_selector.get_selected_channels();
934 if (_view->num_selected_regionviews() == 0) {
935 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
937 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
942 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
944 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
948 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
950 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
954 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
956 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
960 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
962 /* hide all automation tracks that use the wrong channel(s) and show all those that use
966 uint16_t selected_channels = _channel_selector.get_selected_channels();
967 bool changed = false;
971 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
973 for (uint32_t chn = 0; chn < 16; ++chn) {
974 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
975 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
981 if ((selected_channels & (0x0001 << chn)) == 0) {
982 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
983 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
985 changed = track->set_visibility (false) || changed;
987 changed = track->set_visibility (true) || changed;
994 /* TODO: Bender, Pressure */
996 /* invalidate the controller menu, so that we rebuilt it next time */
997 _controller_menu_map.clear ();
998 delete controller_menu;
1002 _route->gui_changed ("track_height", this);
1007 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1009 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1014 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1015 if (i != _controller_menu_map.end()) {
1019 i = _channel_command_menu_map.find (param);
1020 if (i != _channel_command_menu_map.end()) {
1027 boost::shared_ptr<MidiRegion>
1028 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1030 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1032 real_editor->begin_reversible_command (Operations::create_region);
1033 playlist()->clear_changes ();
1035 real_editor->snap_to (pos, 0);
1037 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1038 view()->trackview().track()->name());
1041 plist.add (ARDOUR::Properties::start, 0);
1042 plist.add (ARDOUR::Properties::length, length);
1043 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1045 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1047 playlist()->add_region (region, pos);
1048 _session->add_command (new StatefulDiffCommand (playlist()));
1051 real_editor->commit_reversible_command ();
1054 return boost::dynamic_pointer_cast<MidiRegion>(region);
1058 MidiTimeAxisView::start_step_editing ()
1060 if (!_step_editor) {
1061 _step_editor = new StepEditor (_editor, midi_track(), *this);
1064 _step_editor->start_step_editing ();
1068 MidiTimeAxisView::stop_step_editing ()
1071 _step_editor->stop_step_editing ();