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::enter_internal_edit_mode ()
251 midi_view()->enter_internal_edit_mode ();
256 MidiTimeAxisView::leave_internal_edit_mode ()
259 midi_view()->leave_internal_edit_mode ();
264 MidiTimeAxisView::check_step_edit ()
266 ensure_step_editor ();
267 _step_editor->check_step_edit ();
271 MidiTimeAxisView::model_changed()
273 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
274 .custom_device_mode_names_by_model(_model_selector.get_active_text());
276 _custom_device_mode_selector.clear_items();
278 for (std::list<std::string>::const_iterator i = device_modes.begin();
279 i != device_modes.end(); ++i) {
280 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
281 _custom_device_mode_selector.append_text(*i);
284 _custom_device_mode_selector.set_active(0);
287 void MidiTimeAxisView::custom_device_mode_changed()
289 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
290 _custom_device_mode_selector.get_active_text());
294 MidiTimeAxisView::midi_view()
296 return dynamic_cast<MidiStreamView*>(_view);
300 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
303 xml_node->add_property ("shown-editor", "yes");
305 guint32 ret = TimeAxisView::show_at (y, nth, parent);
310 MidiTimeAxisView::hide ()
313 xml_node->add_property ("shown-editor", "no");
315 TimeAxisView::hide ();
319 MidiTimeAxisView::set_height (uint32_t h)
321 RouteTimeAxisView::set_height (h);
323 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
324 _midi_controls_box.show_all ();
326 _midi_controls_box.hide();
329 if (height >= KEYBOARD_MIN_HEIGHT) {
330 if (is_track() && _range_scroomer)
331 _range_scroomer->show();
332 if (is_track() && _piano_roll_header)
333 _piano_roll_header->show();
335 if (is_track() && _range_scroomer)
336 _range_scroomer->hide();
337 if (is_track() && _piano_roll_header)
338 _piano_roll_header->hide();
343 MidiTimeAxisView::append_extra_display_menu_items ()
345 using namespace Menu_Helpers;
347 MenuList& items = display_menu->items();
350 Menu *range_menu = manage(new Menu);
351 MenuList& range_items = range_menu->items();
352 range_menu->set_name ("ArdourContextMenu");
354 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
355 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
356 MidiStreamView::FullRange)));
358 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
359 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
360 MidiStreamView::ContentsRange)));
362 items.push_back (MenuElem (_("Note range"), *range_menu));
363 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
364 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
366 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
367 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
369 items.push_back (SeparatorElem ());
373 MidiTimeAxisView::build_def_channel_menu ()
375 using namespace Menu_Helpers;
377 default_channel_menu = manage (new Menu ());
379 uint8_t defchn = midi_track()->default_channel();
380 MenuList& def_channel_items = default_channel_menu->items();
382 RadioMenuItem::Group dc_group;
384 for (int i = 0; i < 16; ++i) {
386 snprintf (buf, sizeof (buf), "%d", i+1);
388 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
389 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
390 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
391 item->set_active ((i == defchn));
394 return default_channel_menu;
398 MidiTimeAxisView::set_default_channel (int chn)
400 midi_track()->set_default_channel (chn);
404 MidiTimeAxisView::toggle_midi_thru ()
406 if (!_midi_thru_item) {
410 bool view_yn = _midi_thru_item->get_active();
411 if (view_yn != midi_track()->midi_thru()) {
412 midi_track()->set_midi_thru (view_yn);
417 MidiTimeAxisView::build_automation_action_menu ()
419 using namespace Menu_Helpers;
421 /* If we have a controller menu, we need to detach it before
422 RouteTimeAxis::build_automation_action_menu destroys the
423 menu it is attached to. Otherwise GTK destroys
424 controller_menu's gobj, meaning that it can't be reattached
425 below. See bug #3134.
428 if (controller_menu) {
429 detach_menu (*controller_menu);
432 _channel_command_menu_map.clear ();
433 RouteTimeAxisView::build_automation_action_menu ();
435 MenuList& automation_items = automation_action_menu->items();
437 uint16_t selected_channels = _channel_selector.get_selected_channels();
439 if (selected_channels != 0) {
441 automation_items.push_back (SeparatorElem());
443 /* these 2 MIDI "command" types are semantically more like automation than note data,
444 but they are not MIDI controllers. We give them special status in this menu, since
445 they will not show up in the controller list and anyone who actually knows
446 something about MIDI (!) would not expect to find them there.
449 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
450 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
452 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
453 since it might need to be updated after a channel mode change or other change. Also detach it
454 first in case it has been used anywhere else.
457 build_controller_menu ();
459 automation_items.push_back (SeparatorElem());
460 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
462 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
463 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
469 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
471 uint16_t selected_channels = _channel_selector.get_selected_channels();
473 for (uint8_t chn = 0; chn < 16; chn++) {
474 if (selected_channels & (0x0001 << chn)) {
476 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
477 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
480 menu->set_active (yn);
487 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
489 using namespace Menu_Helpers;
491 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
494 uint16_t selected_channels = _channel_selector.get_selected_channels();
497 for (uint8_t chn = 0; chn < 16; chn++) {
498 if (selected_channels & (0x0001 << chn)) {
507 /* multiple channels - create a submenu, with 1 item per channel */
509 Menu* chn_menu = manage (new Menu);
510 MenuList& chn_items (chn_menu->items());
511 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
513 /* add a couple of items to hide/show all of them */
515 chn_items.push_back (MenuElem (_("Hide all channels"),
516 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
517 false, param_without_channel)));
518 chn_items.push_back (MenuElem (_("Show all channels"),
519 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
520 true, param_without_channel)));
522 for (uint8_t chn = 0; chn < 16; chn++) {
523 if (selected_channels & (0x0001 << chn)) {
525 /* for each selected channel, add a menu item for this controller */
527 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
528 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
529 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
530 fully_qualified_param)));
532 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
533 bool visible = false;
536 if (track->marked_for_display()) {
541 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
542 _channel_command_menu_map[fully_qualified_param] = cmi;
543 cmi->set_active (visible);
547 /* now create an item in the parent menu that has the per-channel list as a submenu */
549 items.push_back (MenuElem (label, *chn_menu));
553 /* just one channel - create a single menu item for this command+channel combination*/
555 for (uint8_t chn = 0; chn < 16; chn++) {
556 if (selected_channels & (0x0001 << chn)) {
558 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
559 items.push_back (CheckMenuElem (label,
560 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
561 fully_qualified_param)));
563 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
564 bool visible = false;
567 if (track->marked_for_display()) {
572 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
573 _channel_command_menu_map[fully_qualified_param] = cmi;
574 cmi->set_active (visible);
576 /* one channel only */
584 MidiTimeAxisView::build_controller_menu ()
586 using namespace Menu_Helpers;
588 if (controller_menu) {
589 /* it exists and has not been invalidated by a channel mode change, so just return it */
593 controller_menu = new Menu; // explicitly managed by us
594 MenuList& items (controller_menu->items());
596 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
597 for each controller+channel combination covering the currently selected channels for this track
600 uint16_t selected_channels = _channel_selector.get_selected_channels();
602 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
607 for (uint8_t chn = 0; chn < 16; chn++) {
608 if (selected_channels & (0x0001 << chn)) {
615 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
616 bank select controllers, as they are handled by the `patch' code */
618 for (int i = 0; i < 127; i += 16) {
620 Menu* ctl_menu = manage (new Menu);
621 MenuList& ctl_items (ctl_menu->items());
624 /* for each controller, consider whether to create a submenu or a single item */
626 for (int ctl = i; ctl < i+16; ++ctl) {
628 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
634 /* multiple channels - create a submenu, with 1 item per channel */
636 Menu* chn_menu = manage (new Menu);
637 MenuList& chn_items (chn_menu->items());
639 /* add a couple of items to hide/show this controller on all channels */
641 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
642 chn_items.push_back (MenuElem (_("Hide all channels"),
643 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
644 false, param_without_channel)));
645 chn_items.push_back (MenuElem (_("Show all channels"),
646 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
647 true, param_without_channel)));
649 for (uint8_t chn = 0; chn < 16; chn++) {
650 if (selected_channels & (0x0001 << chn)) {
652 /* for each selected channel, add a menu item for this controller */
654 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
655 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
656 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
657 fully_qualified_param)));
659 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
660 bool visible = false;
663 if (track->marked_for_display()) {
668 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
669 _controller_menu_map[fully_qualified_param] = cmi;
670 cmi->set_active (visible);
674 /* add the per-channel menu to the list of controllers, with the name of the controller */
675 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
676 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
680 /* just one channel - create a single menu item for this ctl+channel combination*/
682 for (uint8_t chn = 0; chn < 16; chn++) {
683 if (selected_channels & (0x0001 << chn)) {
685 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
686 ctl_items.push_back (
688 string_compose ("<b>%1</b>: %2 [%3]", ctl, midi_name (ctl), int (chn)),
689 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
690 fully_qualified_param)
693 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
695 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
696 bool visible = false;
699 if (track->marked_for_display()) {
704 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
705 _controller_menu_map[fully_qualified_param] = cmi;
706 cmi->set_active (visible);
708 /* one channel only */
715 /* add the menu for this block of controllers to the overall controller menu */
717 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
722 MidiTimeAxisView::build_note_mode_menu()
724 using namespace Menu_Helpers;
726 Menu* mode_menu = manage (new Menu);
727 MenuList& items = mode_menu->items();
728 mode_menu->set_name ("ArdourContextMenu");
730 RadioMenuItem::Group mode_group;
731 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
732 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
733 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
734 _note_mode_item->set_active(_note_mode == Sustained);
736 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
737 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
738 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
739 _percussion_mode_item->set_active(_note_mode == Percussive);
745 MidiTimeAxisView::build_color_mode_menu()
747 using namespace Menu_Helpers;
749 Menu* mode_menu = manage (new Menu);
750 MenuList& items = mode_menu->items();
751 mode_menu->set_name ("ArdourContextMenu");
753 RadioMenuItem::Group mode_group;
754 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
755 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
756 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
757 _meter_color_mode_item->set_active(_color_mode == MeterColors);
759 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
760 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
761 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
762 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
764 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
765 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
766 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
767 _channel_color_mode_item->set_active(_color_mode == TrackColor);
773 MidiTimeAxisView::set_note_mode(NoteMode mode)
775 if (_note_mode != mode || midi_track()->note_mode() != mode) {
777 midi_track()->set_note_mode(mode);
778 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
779 _view->redisplay_track();
784 MidiTimeAxisView::set_color_mode(ColorMode mode)
786 if (_color_mode != mode) {
787 if (mode == ChannelColors) {
788 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
790 _channel_selector.set_default_channel_color();
794 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
795 _view->redisplay_track();
800 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
802 if (!_ignore_signals)
803 midi_view()->set_note_range(range);
808 MidiTimeAxisView::update_range()
810 MidiGhostRegion* mgr;
812 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
813 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
820 MidiTimeAxisView::show_all_automation ()
823 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
825 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
826 create_automation_child(*i, true);
830 RouteTimeAxisView::show_all_automation ();
834 MidiTimeAxisView::show_existing_automation ()
837 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
839 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
840 create_automation_child(*i, true);
844 RouteTimeAxisView::show_existing_automation ();
847 /** Create an automation track for the given parameter (pitch bend, channel pressure).
850 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
852 if (param.type() == NullAutomation) {
853 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
857 AutomationTracks::iterator existing = _automation_tracks.find (param);
858 if (existing != _automation_tracks.end()) {
862 if (param.type() == GainAutomation) {
863 create_gain_automation_child (param, show);
866 /* These controllers are region "automation", so we do not create
867 * an AutomationList/Line for the track */
869 boost::shared_ptr<AutomationTimeAxisView> track (
870 new AutomationTimeAxisView (
873 boost::shared_ptr<Automatable> (),
874 boost::shared_ptr<AutomationControl> (),
880 _route->describe_parameter(param)
885 _view->foreach_regionview (sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
888 add_automation_child (param, track, show);
894 MidiTimeAxisView::route_active_changed ()
896 RouteUI::route_active_changed ();
899 if (_route->active()) {
900 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
901 controls_base_selected_name = "MidiTrackControlsBaseSelected";
902 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
904 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
905 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
906 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
912 if (_route->active()) {
913 controls_ebox.set_name ("BusControlsBaseUnselected");
914 controls_base_selected_name = "BusControlsBaseSelected";
915 controls_base_unselected_name = "BusControlsBaseUnselected";
917 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
918 controls_base_selected_name = "BusControlsBaseInactiveSelected";
919 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
927 MidiTimeAxisView::add_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::add_note_selection_region_view), note, chn_mask));
938 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
943 MidiTimeAxisView::extend_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::extend_note_selection_region_view), note, chn_mask));
954 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
959 MidiTimeAxisView::toggle_note_selection (uint8_t note)
961 if (!_editor.internal_editing()) {
965 uint16_t chn_mask = _channel_selector.get_selected_channels();
967 if (_view->num_selected_regionviews() == 0) {
968 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
970 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
975 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
977 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
981 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
983 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
987 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
989 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
993 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
995 /* hide all automation tracks that use the wrong channel(s) and show all those that use
999 uint16_t selected_channels = _channel_selector.get_selected_channels();
1000 bool changed = false;
1004 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1006 for (uint32_t chn = 0; chn < 16; ++chn) {
1007 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1008 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1014 if ((selected_channels & (0x0001 << chn)) == 0) {
1015 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1016 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1018 changed = track->set_visibility (false) || changed;
1020 changed = track->set_visibility (true) || changed;
1027 /* TODO: Bender, Pressure */
1029 /* invalidate the controller menu, so that we rebuild it next time */
1030 _controller_menu_map.clear ();
1031 delete controller_menu;
1032 controller_menu = 0;
1035 _route->gui_changed ("track_height", this);
1040 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1042 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1047 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1048 if (i != _controller_menu_map.end()) {
1052 i = _channel_command_menu_map.find (param);
1053 if (i != _channel_command_menu_map.end()) {
1060 boost::shared_ptr<MidiRegion>
1061 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1063 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1065 real_editor->begin_reversible_command (Operations::create_region);
1066 playlist()->clear_changes ();
1068 real_editor->snap_to (pos, 0);
1070 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1071 view()->trackview().track()->name());
1074 plist.add (ARDOUR::Properties::start, 0);
1075 plist.add (ARDOUR::Properties::length, length);
1076 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1078 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1080 playlist()->add_region (region, pos);
1081 _session->add_command (new StatefulDiffCommand (playlist()));
1084 real_editor->commit_reversible_command ();
1087 return boost::dynamic_pointer_cast<MidiRegion>(region);
1091 MidiTimeAxisView::ensure_step_editor ()
1093 if (!_step_editor) {
1094 _step_editor = new StepEditor (_editor, midi_track(), *this);
1099 MidiTimeAxisView::start_step_editing ()
1101 ensure_step_editor ();
1102 _step_editor->start_step_editing ();
1106 MidiTimeAxisView::stop_step_editing ()
1109 _step_editor->stop_step_editing ();