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<AutomationTimeAxisView> track (
846 new AutomationTimeAxisView (
850 boost::shared_ptr<AutomationControl> (),
856 _route->describe_parameter(param)
860 add_automation_child (param, track, show);
866 MidiTimeAxisView::route_active_changed ()
868 RouteUI::route_active_changed ();
871 if (_route->active()) {
872 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
873 controls_base_selected_name = "MidiTrackControlsBaseSelected";
874 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
876 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
877 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
878 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
884 if (_route->active()) {
885 controls_ebox.set_name ("BusControlsBaseUnselected");
886 controls_base_selected_name = "BusControlsBaseSelected";
887 controls_base_unselected_name = "BusControlsBaseUnselected";
889 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
890 controls_base_selected_name = "BusControlsBaseInactiveSelected";
891 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
899 MidiTimeAxisView::add_note_selection (uint8_t note)
901 if (!_editor.internal_editing()) {
905 uint16_t chn_mask = _channel_selector.get_selected_channels();
907 if (_view->num_selected_regionviews() == 0) {
908 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
910 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
915 MidiTimeAxisView::extend_note_selection (uint8_t note)
917 if (!_editor.internal_editing()) {
921 uint16_t chn_mask = _channel_selector.get_selected_channels();
923 if (_view->num_selected_regionviews() == 0) {
924 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
926 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
931 MidiTimeAxisView::toggle_note_selection (uint8_t note)
933 if (!_editor.internal_editing()) {
937 uint16_t chn_mask = _channel_selector.get_selected_channels();
939 if (_view->num_selected_regionviews() == 0) {
940 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
942 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
947 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
949 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
953 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
955 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
959 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
961 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
965 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
967 /* hide all automation tracks that use the wrong channel(s) and show all those that use
971 uint16_t selected_channels = _channel_selector.get_selected_channels();
972 bool changed = false;
976 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
978 for (uint32_t chn = 0; chn < 16; ++chn) {
979 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
980 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
986 if ((selected_channels & (0x0001 << chn)) == 0) {
987 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
988 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
990 changed = track->set_visibility (false) || changed;
992 changed = track->set_visibility (true) || changed;
999 /* TODO: Bender, Pressure */
1001 /* invalidate the controller menu, so that we rebuilt it next time */
1002 _controller_menu_map.clear ();
1003 delete controller_menu;
1004 controller_menu = 0;
1007 _route->gui_changed ("track_height", this);
1012 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1014 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1019 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1020 if (i != _controller_menu_map.end()) {
1024 i = _channel_command_menu_map.find (param);
1025 if (i != _channel_command_menu_map.end()) {
1032 boost::shared_ptr<MidiRegion>
1033 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1035 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1037 real_editor->begin_reversible_command (Operations::create_region);
1038 playlist()->clear_changes ();
1040 real_editor->snap_to (pos, 0);
1042 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1043 view()->trackview().track()->name());
1046 plist.add (ARDOUR::Properties::start, 0);
1047 plist.add (ARDOUR::Properties::length, length);
1048 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1050 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1052 playlist()->add_region (region, pos);
1053 _session->add_command (new StatefulDiffCommand (playlist()));
1056 real_editor->commit_reversible_command ();
1059 return boost::dynamic_pointer_cast<MidiRegion>(region);
1063 MidiTimeAxisView::ensure_step_editor ()
1065 if (!_step_editor) {
1066 _step_editor = new StepEditor (_editor, midi_track(), *this);
1071 MidiTimeAxisView::start_step_editing ()
1073 ensure_step_editor ();
1074 _step_editor->start_step_editing ();
1078 MidiTimeAxisView::stop_step_editing ()
1081 _step_editor->stop_step_editing ();