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 ensure_step_editor ();
251 _step_editor->check_step_edit ();
255 MidiTimeAxisView::model_changed()
257 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
258 .custom_device_mode_names_by_model(_model_selector.get_active_text());
260 _custom_device_mode_selector.clear_items();
262 for (std::list<std::string>::const_iterator i = device_modes.begin();
263 i != device_modes.end(); ++i) {
264 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
265 _custom_device_mode_selector.append_text(*i);
268 _custom_device_mode_selector.set_active(0);
271 void MidiTimeAxisView::custom_device_mode_changed()
273 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
274 _custom_device_mode_selector.get_active_text());
278 MidiTimeAxisView::midi_view()
280 return dynamic_cast<MidiStreamView*>(_view);
284 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
287 xml_node->add_property ("shown-editor", "yes");
289 guint32 ret = TimeAxisView::show_at (y, nth, parent);
294 MidiTimeAxisView::hide ()
297 xml_node->add_property ("shown-editor", "no");
299 TimeAxisView::hide ();
303 MidiTimeAxisView::set_height (uint32_t h)
305 RouteTimeAxisView::set_height (h);
307 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
308 _midi_controls_box.show_all ();
310 _midi_controls_box.hide();
313 if (height >= KEYBOARD_MIN_HEIGHT) {
314 if (is_track() && _range_scroomer)
315 _range_scroomer->show();
316 if (is_track() && _piano_roll_header)
317 _piano_roll_header->show();
319 if (is_track() && _range_scroomer)
320 _range_scroomer->hide();
321 if (is_track() && _piano_roll_header)
322 _piano_roll_header->hide();
327 MidiTimeAxisView::append_extra_display_menu_items ()
329 using namespace Menu_Helpers;
331 MenuList& items = display_menu->items();
334 Menu *range_menu = manage(new Menu);
335 MenuList& range_items = range_menu->items();
336 range_menu->set_name ("ArdourContextMenu");
338 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
339 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
340 MidiStreamView::FullRange)));
342 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
343 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
344 MidiStreamView::ContentsRange)));
346 items.push_back (MenuElem (_("Note range"), *range_menu));
347 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
348 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
350 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
351 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
355 MidiTimeAxisView::build_def_channel_menu ()
357 using namespace Menu_Helpers;
359 default_channel_menu = manage (new Menu ());
361 uint8_t defchn = midi_track()->default_channel();
362 MenuList& def_channel_items = default_channel_menu->items();
364 RadioMenuItem::Group dc_group;
366 for (int i = 0; i < 16; ++i) {
368 snprintf (buf, sizeof (buf), "%d", i+1);
370 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
371 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
372 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
373 item->set_active ((i == defchn));
376 return default_channel_menu;
380 MidiTimeAxisView::set_default_channel (int chn)
382 midi_track()->set_default_channel (chn);
386 MidiTimeAxisView::toggle_midi_thru ()
388 if (!_midi_thru_item) {
392 bool view_yn = _midi_thru_item->get_active();
393 if (view_yn != midi_track()->midi_thru()) {
394 midi_track()->set_midi_thru (view_yn);
399 MidiTimeAxisView::build_automation_action_menu ()
401 using namespace Menu_Helpers;
403 /* If we have a controller menu, we need to detach it before
404 RouteTimeAxis::build_automation_action_menu destroys the
405 menu it is attached to. Otherwise GTK destroys
406 controller_menu's gobj, meaning that it can't be reattached
407 below. See bug #3134.
410 if (controller_menu) {
411 detach_menu (*controller_menu);
414 _channel_command_menu_map.clear ();
415 RouteTimeAxisView::build_automation_action_menu ();
417 MenuList& automation_items = automation_action_menu->items();
419 uint16_t selected_channels = _channel_selector.get_selected_channels();
421 if (selected_channels != 0) {
423 automation_items.push_back (SeparatorElem());
425 /* these 2 MIDI "command" types are semantically more like automation than note data,
426 but they are not MIDI controllers. We give them special status in this menu, since
427 they will not show up in the controller list and anyone who actually knows
428 something about MIDI (!) would not expect to find them there.
431 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
432 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
434 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
435 since it might need to be updated after a channel mode change or other change. Also detach it
436 first in case it has been used anywhere else.
439 build_controller_menu ();
441 automation_items.push_back (SeparatorElem());
442 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
444 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
450 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
452 uint16_t selected_channels = _channel_selector.get_selected_channels();
454 for (uint8_t chn = 0; chn < 16; chn++) {
455 if (selected_channels & (0x0001 << chn)) {
457 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
458 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
461 menu->set_active (yn);
468 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
470 using namespace Menu_Helpers;
472 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
475 uint16_t selected_channels = _channel_selector.get_selected_channels();
478 for (uint8_t chn = 0; chn < 16; chn++) {
479 if (selected_channels & (0x0001 << chn)) {
488 /* multiple channels - create a submenu, with 1 item per channel */
490 Menu* chn_menu = manage (new Menu);
491 MenuList& chn_items (chn_menu->items());
492 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
494 /* add a couple of items to hide/show all of them */
496 chn_items.push_back (MenuElem (_("Hide all channels"),
497 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
498 false, param_without_channel)));
499 chn_items.push_back (MenuElem (_("Show all channels"),
500 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
501 true, param_without_channel)));
503 for (uint8_t chn = 0; chn < 16; chn++) {
504 if (selected_channels & (0x0001 << chn)) {
506 /* for each selected channel, add a menu item for this controller */
508 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
509 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
510 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
511 fully_qualified_param)));
513 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
514 bool visible = false;
517 if (track->marked_for_display()) {
522 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
523 _channel_command_menu_map[fully_qualified_param] = cmi;
524 cmi->set_active (visible);
528 /* now create an item in the parent menu that has the per-channel list as a submenu */
530 items.push_back (MenuElem (label, *chn_menu));
534 /* just one channel - create a single menu item for this command+channel combination*/
536 for (uint8_t chn = 0; chn < 16; chn++) {
537 if (selected_channels & (0x0001 << chn)) {
539 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
540 items.push_back (CheckMenuElem (label,
541 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
542 fully_qualified_param)));
544 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
545 bool visible = false;
548 if (track->marked_for_display()) {
553 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
554 _channel_command_menu_map[fully_qualified_param] = cmi;
555 cmi->set_active (visible);
557 /* one channel only */
565 MidiTimeAxisView::build_controller_menu ()
567 using namespace Menu_Helpers;
569 if (controller_menu) {
570 /* it exists and has not been invalidated by a channel mode change, so just return it */
574 controller_menu = new Menu; // explicitly managed by us
575 MenuList& items (controller_menu->items());
577 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
578 for each controller+channel combination covering the currently selected channels for this track
581 uint16_t selected_channels = _channel_selector.get_selected_channels();
583 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
588 for (uint8_t chn = 0; chn < 16; chn++) {
589 if (selected_channels & (0x0001 << chn)) {
596 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
597 bank select controllers, as they are handled by the `patch' code */
599 for (int i = 0; i < 127; i += 16) {
601 Menu* ctl_menu = manage (new Menu);
602 MenuList& ctl_items (ctl_menu->items());
605 /* for each controller, consider whether to create a submenu or a single item */
607 for (int ctl = i; ctl < i+16; ++ctl) {
609 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
615 /* multiple channels - create a submenu, with 1 item per channel */
617 Menu* chn_menu = manage (new Menu);
618 MenuList& chn_items (chn_menu->items());
620 /* add a couple of items to hide/show this controller on all channels */
622 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
623 chn_items.push_back (MenuElem (_("Hide all channels"),
624 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
625 false, param_without_channel)));
626 chn_items.push_back (MenuElem (_("Show all channels"),
627 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
628 true, param_without_channel)));
630 for (uint8_t chn = 0; chn < 16; chn++) {
631 if (selected_channels & (0x0001 << chn)) {
633 /* for each selected channel, add a menu item for this controller */
635 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
636 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
637 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
638 fully_qualified_param)));
640 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
641 bool visible = false;
644 if (track->marked_for_display()) {
649 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
650 _controller_menu_map[fully_qualified_param] = cmi;
651 cmi->set_active (visible);
655 /* add the per-channel menu to the list of controllers, with the name of the controller */
656 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
657 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
661 /* just one channel - create a single menu item for this ctl+channel combination*/
663 for (uint8_t chn = 0; chn < 16; chn++) {
664 if (selected_channels & (0x0001 << chn)) {
666 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
667 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
668 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
669 fully_qualified_param)));
671 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
672 bool visible = false;
675 if (track->marked_for_display()) {
680 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
681 _controller_menu_map[fully_qualified_param] = cmi;
682 cmi->set_active (visible);
684 /* one channel only */
691 /* add the menu for this block of controllers to the overall controller menu */
693 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
698 MidiTimeAxisView::build_note_mode_menu()
700 using namespace Menu_Helpers;
702 Menu* mode_menu = manage (new Menu);
703 MenuList& items = mode_menu->items();
704 mode_menu->set_name ("ArdourContextMenu");
706 RadioMenuItem::Group mode_group;
707 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
708 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
709 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
710 _note_mode_item->set_active(_note_mode == Sustained);
712 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
713 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
714 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
715 _percussion_mode_item->set_active(_note_mode == Percussive);
721 MidiTimeAxisView::build_color_mode_menu()
723 using namespace Menu_Helpers;
725 Menu* mode_menu = manage (new Menu);
726 MenuList& items = mode_menu->items();
727 mode_menu->set_name ("ArdourContextMenu");
729 RadioMenuItem::Group mode_group;
730 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
731 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
732 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
733 _meter_color_mode_item->set_active(_color_mode == MeterColors);
735 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
736 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
737 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
738 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
740 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
741 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
742 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
743 _channel_color_mode_item->set_active(_color_mode == TrackColor);
749 MidiTimeAxisView::set_note_mode(NoteMode mode)
751 if (_note_mode != mode || midi_track()->note_mode() != mode) {
753 midi_track()->set_note_mode(mode);
754 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
755 _view->redisplay_track();
760 MidiTimeAxisView::set_color_mode(ColorMode mode)
762 if (_color_mode != mode) {
763 if (mode == ChannelColors) {
764 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
766 _channel_selector.set_default_channel_color();
770 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
771 _view->redisplay_track();
776 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
778 if (!_ignore_signals)
779 midi_view()->set_note_range(range);
784 MidiTimeAxisView::update_range()
786 MidiGhostRegion* mgr;
788 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
789 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
796 MidiTimeAxisView::show_all_automation ()
799 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
801 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
802 create_automation_child(*i, true);
806 RouteTimeAxisView::show_all_automation ();
810 MidiTimeAxisView::show_existing_automation ()
813 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
815 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
816 create_automation_child(*i, true);
820 RouteTimeAxisView::show_existing_automation ();
823 /** Create an automation track for the given parameter (pitch bend, channel pressure).
826 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
828 if (param.type() == NullAutomation) {
829 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
833 AutomationTracks::iterator existing = _automation_tracks.find (param);
834 if (existing != _automation_tracks.end()) {
838 if (param.type() == GainAutomation) {
839 create_gain_automation_child (param, show);
842 /* These controllers are region "automation", so we do not create
843 * an AutomationList/Line for the track */
845 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
848 boost::shared_ptr<AutomationTimeAxisView> track (
849 new AutomationTimeAxisView (
858 _route->describe_parameter(param)
862 add_automation_child (param, track, show);
868 MidiTimeAxisView::route_active_changed ()
870 RouteUI::route_active_changed ();
873 if (_route->active()) {
874 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
875 controls_base_selected_name = "MidiTrackControlsBaseSelected";
876 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
878 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
879 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
880 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
886 if (_route->active()) {
887 controls_ebox.set_name ("BusControlsBaseUnselected");
888 controls_base_selected_name = "BusControlsBaseSelected";
889 controls_base_unselected_name = "BusControlsBaseUnselected";
891 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
892 controls_base_selected_name = "BusControlsBaseInactiveSelected";
893 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
901 MidiTimeAxisView::add_note_selection (uint8_t note)
903 if (!_editor.internal_editing()) {
907 uint16_t chn_mask = _channel_selector.get_selected_channels();
909 if (_view->num_selected_regionviews() == 0) {
910 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
912 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
917 MidiTimeAxisView::extend_note_selection (uint8_t note)
919 if (!_editor.internal_editing()) {
923 uint16_t chn_mask = _channel_selector.get_selected_channels();
925 if (_view->num_selected_regionviews() == 0) {
926 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
928 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
933 MidiTimeAxisView::toggle_note_selection (uint8_t note)
935 if (!_editor.internal_editing()) {
939 uint16_t chn_mask = _channel_selector.get_selected_channels();
941 if (_view->num_selected_regionviews() == 0) {
942 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
944 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
949 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
951 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
955 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
957 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
961 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
963 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
967 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
969 /* hide all automation tracks that use the wrong channel(s) and show all those that use
973 uint16_t selected_channels = _channel_selector.get_selected_channels();
974 bool changed = false;
978 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
980 for (uint32_t chn = 0; chn < 16; ++chn) {
981 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
982 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
988 if ((selected_channels & (0x0001 << chn)) == 0) {
989 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
990 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
992 changed = track->set_visibility (false) || changed;
994 changed = track->set_visibility (true) || changed;
1001 /* TODO: Bender, Pressure */
1003 /* invalidate the controller menu, so that we rebuilt it next time */
1004 _controller_menu_map.clear ();
1005 delete controller_menu;
1006 controller_menu = 0;
1009 _route->gui_changed ("track_height", this);
1014 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1016 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1021 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1022 if (i != _controller_menu_map.end()) {
1026 i = _channel_command_menu_map.find (param);
1027 if (i != _channel_command_menu_map.end()) {
1034 boost::shared_ptr<MidiRegion>
1035 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1037 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1039 real_editor->begin_reversible_command (Operations::create_region);
1040 playlist()->clear_changes ();
1042 real_editor->snap_to (pos, 0);
1044 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1045 view()->trackview().track()->name());
1048 plist.add (ARDOUR::Properties::start, 0);
1049 plist.add (ARDOUR::Properties::length, length);
1050 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1052 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1054 playlist()->add_region (region, pos);
1055 _session->add_command (new StatefulDiffCommand (playlist()));
1058 real_editor->commit_reversible_command ();
1061 return boost::dynamic_pointer_cast<MidiRegion>(region);
1065 MidiTimeAxisView::ensure_step_editor ()
1067 if (!_step_editor) {
1068 _step_editor = new StepEditor (_editor, midi_track(), *this);
1073 MidiTimeAxisView::start_step_editing ()
1075 ensure_step_editor ();
1076 _step_editor->start_step_editing ();
1080 MidiTimeAxisView::stop_step_editing ()
1083 _step_editor->stop_step_editing ();