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());
353 items.push_back (SeparatorElem ());
357 MidiTimeAxisView::build_def_channel_menu ()
359 using namespace Menu_Helpers;
361 default_channel_menu = manage (new Menu ());
363 uint8_t defchn = midi_track()->default_channel();
364 MenuList& def_channel_items = default_channel_menu->items();
366 RadioMenuItem::Group dc_group;
368 for (int i = 0; i < 16; ++i) {
370 snprintf (buf, sizeof (buf), "%d", i+1);
372 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
373 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
374 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
375 item->set_active ((i == defchn));
378 return default_channel_menu;
382 MidiTimeAxisView::set_default_channel (int chn)
384 midi_track()->set_default_channel (chn);
388 MidiTimeAxisView::toggle_midi_thru ()
390 if (!_midi_thru_item) {
394 bool view_yn = _midi_thru_item->get_active();
395 if (view_yn != midi_track()->midi_thru()) {
396 midi_track()->set_midi_thru (view_yn);
401 MidiTimeAxisView::build_automation_action_menu ()
403 using namespace Menu_Helpers;
405 /* If we have a controller menu, we need to detach it before
406 RouteTimeAxis::build_automation_action_menu destroys the
407 menu it is attached to. Otherwise GTK destroys
408 controller_menu's gobj, meaning that it can't be reattached
409 below. See bug #3134.
412 if (controller_menu) {
413 detach_menu (*controller_menu);
416 _channel_command_menu_map.clear ();
417 RouteTimeAxisView::build_automation_action_menu ();
419 MenuList& automation_items = automation_action_menu->items();
421 uint16_t selected_channels = _channel_selector.get_selected_channels();
423 if (selected_channels != 0) {
425 automation_items.push_back (SeparatorElem());
427 /* these 2 MIDI "command" types are semantically more like automation than note data,
428 but they are not MIDI controllers. We give them special status in this menu, since
429 they will not show up in the controller list and anyone who actually knows
430 something about MIDI (!) would not expect to find them there.
433 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
434 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
436 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
437 since it might need to be updated after a channel mode change or other change. Also detach it
438 first in case it has been used anywhere else.
441 build_controller_menu ();
443 automation_items.push_back (SeparatorElem());
444 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
446 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
447 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
453 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
455 uint16_t selected_channels = _channel_selector.get_selected_channels();
457 for (uint8_t chn = 0; chn < 16; chn++) {
458 if (selected_channels & (0x0001 << chn)) {
460 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
461 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
464 menu->set_active (yn);
471 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
473 using namespace Menu_Helpers;
475 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
478 uint16_t selected_channels = _channel_selector.get_selected_channels();
481 for (uint8_t chn = 0; chn < 16; chn++) {
482 if (selected_channels & (0x0001 << chn)) {
491 /* multiple channels - create a submenu, with 1 item per channel */
493 Menu* chn_menu = manage (new Menu);
494 MenuList& chn_items (chn_menu->items());
495 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
497 /* add a couple of items to hide/show all of them */
499 chn_items.push_back (MenuElem (_("Hide all channels"),
500 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
501 false, param_without_channel)));
502 chn_items.push_back (MenuElem (_("Show all channels"),
503 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
504 true, param_without_channel)));
506 for (uint8_t chn = 0; chn < 16; chn++) {
507 if (selected_channels & (0x0001 << chn)) {
509 /* for each selected channel, add a menu item for this controller */
511 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
512 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
513 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
514 fully_qualified_param)));
516 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
517 bool visible = false;
520 if (track->marked_for_display()) {
525 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
526 _channel_command_menu_map[fully_qualified_param] = cmi;
527 cmi->set_active (visible);
531 /* now create an item in the parent menu that has the per-channel list as a submenu */
533 items.push_back (MenuElem (label, *chn_menu));
537 /* just one channel - create a single menu item for this command+channel combination*/
539 for (uint8_t chn = 0; chn < 16; chn++) {
540 if (selected_channels & (0x0001 << chn)) {
542 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
543 items.push_back (CheckMenuElem (label,
544 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
545 fully_qualified_param)));
547 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
548 bool visible = false;
551 if (track->marked_for_display()) {
556 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
557 _channel_command_menu_map[fully_qualified_param] = cmi;
558 cmi->set_active (visible);
560 /* one channel only */
568 MidiTimeAxisView::build_controller_menu ()
570 using namespace Menu_Helpers;
572 if (controller_menu) {
573 /* it exists and has not been invalidated by a channel mode change, so just return it */
577 controller_menu = new Menu; // explicitly managed by us
578 MenuList& items (controller_menu->items());
580 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
581 for each controller+channel combination covering the currently selected channels for this track
584 uint16_t selected_channels = _channel_selector.get_selected_channels();
586 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
591 for (uint8_t chn = 0; chn < 16; chn++) {
592 if (selected_channels & (0x0001 << chn)) {
599 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
600 bank select controllers, as they are handled by the `patch' code */
602 for (int i = 0; i < 127; i += 16) {
604 Menu* ctl_menu = manage (new Menu);
605 MenuList& ctl_items (ctl_menu->items());
608 /* for each controller, consider whether to create a submenu or a single item */
610 for (int ctl = i; ctl < i+16; ++ctl) {
612 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
618 /* multiple channels - create a submenu, with 1 item per channel */
620 Menu* chn_menu = manage (new Menu);
621 MenuList& chn_items (chn_menu->items());
623 /* add a couple of items to hide/show this controller on all channels */
625 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
626 chn_items.push_back (MenuElem (_("Hide all channels"),
627 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
628 false, param_without_channel)));
629 chn_items.push_back (MenuElem (_("Show all channels"),
630 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
631 true, param_without_channel)));
633 for (uint8_t chn = 0; chn < 16; chn++) {
634 if (selected_channels & (0x0001 << chn)) {
636 /* for each selected channel, add a menu item for this controller */
638 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
639 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
640 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
641 fully_qualified_param)));
643 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
644 bool visible = false;
647 if (track->marked_for_display()) {
652 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
653 _controller_menu_map[fully_qualified_param] = cmi;
654 cmi->set_active (visible);
658 /* add the per-channel menu to the list of controllers, with the name of the controller */
659 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
660 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
664 /* just one channel - create a single menu item for this ctl+channel combination*/
666 for (uint8_t chn = 0; chn < 16; chn++) {
667 if (selected_channels & (0x0001 << chn)) {
669 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
670 ctl_items.push_back (
672 string_compose ("<b>%1</b>: %2 [%3]", ctl, midi_name (ctl), int (chn)),
673 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
674 fully_qualified_param)
677 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
679 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
680 bool visible = false;
683 if (track->marked_for_display()) {
688 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
689 _controller_menu_map[fully_qualified_param] = cmi;
690 cmi->set_active (visible);
692 /* one channel only */
699 /* add the menu for this block of controllers to the overall controller menu */
701 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
706 MidiTimeAxisView::build_note_mode_menu()
708 using namespace Menu_Helpers;
710 Menu* mode_menu = manage (new Menu);
711 MenuList& items = mode_menu->items();
712 mode_menu->set_name ("ArdourContextMenu");
714 RadioMenuItem::Group mode_group;
715 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
716 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
717 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
718 _note_mode_item->set_active(_note_mode == Sustained);
720 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
721 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
722 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
723 _percussion_mode_item->set_active(_note_mode == Percussive);
729 MidiTimeAxisView::build_color_mode_menu()
731 using namespace Menu_Helpers;
733 Menu* mode_menu = manage (new Menu);
734 MenuList& items = mode_menu->items();
735 mode_menu->set_name ("ArdourContextMenu");
737 RadioMenuItem::Group mode_group;
738 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
739 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
740 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
741 _meter_color_mode_item->set_active(_color_mode == MeterColors);
743 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
744 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
745 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
746 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
748 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
749 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
750 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
751 _channel_color_mode_item->set_active(_color_mode == TrackColor);
757 MidiTimeAxisView::set_note_mode(NoteMode mode)
759 if (_note_mode != mode || midi_track()->note_mode() != mode) {
761 midi_track()->set_note_mode(mode);
762 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
763 _view->redisplay_track();
768 MidiTimeAxisView::set_color_mode(ColorMode mode)
770 if (_color_mode != mode) {
771 if (mode == ChannelColors) {
772 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
774 _channel_selector.set_default_channel_color();
778 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
779 _view->redisplay_track();
784 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
786 if (!_ignore_signals)
787 midi_view()->set_note_range(range);
792 MidiTimeAxisView::update_range()
794 MidiGhostRegion* mgr;
796 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
797 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
804 MidiTimeAxisView::show_all_automation ()
807 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
809 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
810 create_automation_child(*i, true);
814 RouteTimeAxisView::show_all_automation ();
818 MidiTimeAxisView::show_existing_automation ()
821 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
823 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
824 create_automation_child(*i, true);
828 RouteTimeAxisView::show_existing_automation ();
831 /** Create an automation track for the given parameter (pitch bend, channel pressure).
834 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
836 if (param.type() == NullAutomation) {
837 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
841 AutomationTracks::iterator existing = _automation_tracks.find (param);
842 if (existing != _automation_tracks.end()) {
846 if (param.type() == GainAutomation) {
847 create_gain_automation_child (param, show);
850 /* These controllers are region "automation", so we do not create
851 * an AutomationList/Line for the track */
853 boost::shared_ptr<AutomationTimeAxisView> track (
854 new AutomationTimeAxisView (
857 boost::shared_ptr<Automatable> (),
858 boost::shared_ptr<AutomationControl> (),
864 _route->describe_parameter(param)
869 _view->foreach_regionview (sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
872 add_automation_child (param, track, show);
878 MidiTimeAxisView::route_active_changed ()
880 RouteUI::route_active_changed ();
883 if (_route->active()) {
884 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
885 controls_base_selected_name = "MidiTrackControlsBaseSelected";
886 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
888 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
889 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
890 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
896 if (_route->active()) {
897 controls_ebox.set_name ("BusControlsBaseUnselected");
898 controls_base_selected_name = "BusControlsBaseSelected";
899 controls_base_unselected_name = "BusControlsBaseUnselected";
901 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
902 controls_base_selected_name = "BusControlsBaseInactiveSelected";
903 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
911 MidiTimeAxisView::add_note_selection (uint8_t note)
913 if (!_editor.internal_editing()) {
917 uint16_t chn_mask = _channel_selector.get_selected_channels();
919 if (_view->num_selected_regionviews() == 0) {
920 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
922 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
927 MidiTimeAxisView::extend_note_selection (uint8_t note)
929 if (!_editor.internal_editing()) {
933 uint16_t chn_mask = _channel_selector.get_selected_channels();
935 if (_view->num_selected_regionviews() == 0) {
936 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
938 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
943 MidiTimeAxisView::toggle_note_selection (uint8_t note)
945 if (!_editor.internal_editing()) {
949 uint16_t chn_mask = _channel_selector.get_selected_channels();
951 if (_view->num_selected_regionviews() == 0) {
952 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
954 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
959 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
961 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
965 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
967 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
971 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
973 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
977 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
979 /* hide all automation tracks that use the wrong channel(s) and show all those that use
983 uint16_t selected_channels = _channel_selector.get_selected_channels();
984 bool changed = false;
988 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
990 for (uint32_t chn = 0; chn < 16; ++chn) {
991 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
992 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
998 if ((selected_channels & (0x0001 << chn)) == 0) {
999 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1000 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1002 changed = track->set_visibility (false) || changed;
1004 changed = track->set_visibility (true) || changed;
1011 /* TODO: Bender, Pressure */
1013 /* invalidate the controller menu, so that we rebuild it next time */
1014 _controller_menu_map.clear ();
1015 delete controller_menu;
1016 controller_menu = 0;
1019 _route->gui_changed ("track_height", this);
1024 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1026 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1031 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1032 if (i != _controller_menu_map.end()) {
1036 i = _channel_command_menu_map.find (param);
1037 if (i != _channel_command_menu_map.end()) {
1044 boost::shared_ptr<MidiRegion>
1045 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1047 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1049 real_editor->begin_reversible_command (Operations::create_region);
1050 playlist()->clear_changes ();
1052 real_editor->snap_to (pos, 0);
1054 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1055 view()->trackview().track()->name());
1058 plist.add (ARDOUR::Properties::start, 0);
1059 plist.add (ARDOUR::Properties::length, length);
1060 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1062 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1064 playlist()->add_region (region, pos);
1065 _session->add_command (new StatefulDiffCommand (playlist()));
1068 real_editor->commit_reversible_command ();
1071 return boost::dynamic_pointer_cast<MidiRegion>(region);
1075 MidiTimeAxisView::ensure_step_editor ()
1077 if (!_step_editor) {
1078 _step_editor = new StepEditor (_editor, midi_track(), *this);
1083 MidiTimeAxisView::start_step_editing ()
1085 ensure_step_editor ();
1086 _step_editor->start_step_editing ();
1090 MidiTimeAxisView::stop_step_editing ()
1093 _step_editor->stop_step_editing ();