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"
56 #include "midi++/names.h"
58 #include "add_midi_cc_track_dialog.h"
59 #include "ardour_ui.h"
60 #include "automation_line.h"
61 #include "automation_time_axis.h"
62 #include "canvas-note-event.h"
63 #include "canvas_impl.h"
64 #include "crossfade_view.h"
67 #include "ghostregion.h"
68 #include "gui_thread.h"
70 #include "midi_scroomer.h"
71 #include "midi_streamview.h"
72 #include "midi_region_view.h"
73 #include "midi_time_axis.h"
74 #include "piano_roll_header.h"
75 #include "playlist_selector.h"
76 #include "plugin_selector.h"
77 #include "plugin_ui.h"
78 #include "point_selection.h"
80 #include "region_view.h"
81 #include "rgb_macros.h"
82 #include "selection.h"
83 #include "step_editor.h"
84 #include "simplerect.h"
87 #include "ardour/midi_track.h"
91 using namespace ARDOUR;
94 using namespace Gtkmm2ext;
95 using namespace Editing;
97 // Minimum height at which a control is displayed
98 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
99 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
101 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
102 boost::shared_ptr<Route> rt, Canvas& canvas)
103 : AxisView(sess) // virtually inherited
104 , RouteTimeAxisView(ed, sess, rt, canvas)
105 , _ignore_signals(false)
107 , _piano_roll_header(0)
108 , _note_mode(Sustained)
110 , _percussion_mode_item(0)
111 , _color_mode(MeterColors)
112 , _meter_color_mode_item(0)
113 , _channel_color_mode_item(0)
114 , _track_color_mode_item(0)
115 , _step_edit_item (0)
116 , _midi_thru_item (0)
117 , default_channel_menu (0)
118 , controller_menu (0)
121 subplugin_menu.set_name ("ArdourContextMenu");
123 _view = new MidiStreamView (*this);
125 ignore_toggle = false;
127 mute_button->set_active (false);
128 solo_button->set_active (false);
130 if (is_midi_track()) {
131 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
132 _note_mode = midi_track()->note_mode();
133 } else { // MIDI bus (which doesn't exist yet..)
134 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
137 /* map current state of the route */
139 processors_changed (RouteProcessorChange ());
143 set_state (*xml_node, Stateful::loading_state_version);
145 _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
148 _piano_roll_header = new PianoRollHeader(*midi_view());
150 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
151 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
152 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
154 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
156 controls_hbox.pack_start(*_range_scroomer);
157 controls_hbox.pack_start(*_piano_roll_header);
159 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
160 controls_base_selected_name = "MidiTrackControlsBaseSelected";
161 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
163 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
165 /* ask for notifications of any new RegionViews */
166 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
168 if (!_editor.have_idled()) {
169 /* first idle will do what we need */
175 HBox* midi_controls_hbox = manage(new HBox());
177 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
179 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
180 for (; m != patch_manager.all_models().end(); ++m) {
181 _model_selector.append_text(m->c_str());
184 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
186 _custom_device_mode_selector.signal_changed().connect(
187 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
189 // TODO: persist the choice
190 // this initializes the comboboxes and sends out the signal
191 _model_selector.set_active(0);
193 midi_controls_hbox->pack_start(_channel_selector, true, false);
194 if (!patch_manager.all_models().empty()) {
195 _midi_controls_box.pack_start(_model_selector, true, false);
196 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
199 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
201 controls_vbox.pack_start(_midi_controls_box, false, false);
203 // restore channel selector settings
204 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
205 _channel_selector.mode_changed.connect(
206 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
207 _channel_selector.mode_changed.connect(
208 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
211 if ((prop = xml_node->property ("color-mode")) != 0) {
212 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
213 if (_color_mode == ChannelColors) {
214 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
218 if ((prop = xml_node->property ("note-mode")) != 0) {
219 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
220 if (_percussion_mode_item) {
221 _percussion_mode_item->set_active (_note_mode == Percussive);
227 MidiTimeAxisView::first_idle ()
234 MidiTimeAxisView::~MidiTimeAxisView ()
236 delete _piano_roll_header;
237 _piano_roll_header = 0;
239 delete _range_scroomer;
242 delete controller_menu;
247 MidiTimeAxisView::check_step_edit ()
249 _step_editor->check_step_edit ();
253 MidiTimeAxisView::model_changed()
255 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
256 .custom_device_mode_names_by_model(_model_selector.get_active_text());
258 _custom_device_mode_selector.clear_items();
260 for (std::list<std::string>::const_iterator i = device_modes.begin();
261 i != device_modes.end(); ++i) {
262 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
263 _custom_device_mode_selector.append_text(*i);
266 _custom_device_mode_selector.set_active(0);
269 void MidiTimeAxisView::custom_device_mode_changed()
271 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
272 _custom_device_mode_selector.get_active_text());
276 MidiTimeAxisView::midi_view()
278 return dynamic_cast<MidiStreamView*>(_view);
282 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
285 xml_node->add_property ("shown-editor", "yes");
287 guint32 ret = TimeAxisView::show_at (y, nth, parent);
292 MidiTimeAxisView::hide ()
295 xml_node->add_property ("shown-editor", "no");
297 TimeAxisView::hide ();
301 MidiTimeAxisView::set_height (uint32_t h)
303 RouteTimeAxisView::set_height (h);
305 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
306 _midi_controls_box.show_all ();
308 _midi_controls_box.hide();
311 if (height >= KEYBOARD_MIN_HEIGHT) {
312 if (is_track() && _range_scroomer)
313 _range_scroomer->show();
314 if (is_track() && _piano_roll_header)
315 _piano_roll_header->show();
317 if (is_track() && _range_scroomer)
318 _range_scroomer->hide();
319 if (is_track() && _piano_roll_header)
320 _piano_roll_header->hide();
325 MidiTimeAxisView::append_extra_display_menu_items ()
327 using namespace Menu_Helpers;
329 MenuList& items = display_menu->items();
332 Menu *range_menu = manage(new Menu);
333 MenuList& range_items = range_menu->items();
334 range_menu->set_name ("ArdourContextMenu");
336 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
337 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
338 MidiStreamView::FullRange)));
340 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
341 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
342 MidiStreamView::ContentsRange)));
344 items.push_back (MenuElem (_("Note range"), *range_menu));
345 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
346 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
348 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
349 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
353 MidiTimeAxisView::build_def_channel_menu ()
355 using namespace Menu_Helpers;
357 default_channel_menu = manage (new Menu ());
359 uint8_t defchn = midi_track()->default_channel();
360 MenuList& def_channel_items = default_channel_menu->items();
362 RadioMenuItem::Group dc_group;
364 for (int i = 0; i < 16; ++i) {
366 snprintf (buf, sizeof (buf), "%d", i+1);
368 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
369 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
370 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
371 item->set_active ((i == defchn));
374 return default_channel_menu;
378 MidiTimeAxisView::set_default_channel (int chn)
380 midi_track()->set_default_channel (chn);
384 MidiTimeAxisView::toggle_midi_thru ()
386 if (!_midi_thru_item) {
390 bool view_yn = _midi_thru_item->get_active();
391 if (view_yn != midi_track()->midi_thru()) {
392 midi_track()->set_midi_thru (view_yn);
397 MidiTimeAxisView::build_automation_action_menu ()
399 using namespace Menu_Helpers;
401 /* If we have a controller menu, we need to detach it before
402 RouteTimeAxis::build_automation_action_menu destroys the
403 menu it is attached to. Otherwise GTK destroys
404 controller_menu's gobj, meaning that it can't be reattached
405 below. See bug #3134.
408 if (controller_menu) {
409 detach_menu (*controller_menu);
412 _channel_command_menu_map.clear ();
413 RouteTimeAxisView::build_automation_action_menu ();
415 MenuList& automation_items = automation_action_menu->items();
417 uint16_t selected_channels = _channel_selector.get_selected_channels();
419 if (selected_channels != 0) {
421 automation_items.push_back (SeparatorElem());
423 /* these 2 MIDI "command" types are semantically more like automation than note data,
424 but they are not MIDI controllers. We give them special status in this menu, since
425 they will not show up in the controller list and anyone who actually knows
426 something about MIDI (!) would not expect to find them there.
429 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
430 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
432 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
433 since it might need to be updated after a channel mode change or other change. Also detach it
434 first in case it has been used anywhere else.
437 build_controller_menu ();
439 automation_items.push_back (SeparatorElem());
440 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
442 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
448 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
450 uint16_t selected_channels = _channel_selector.get_selected_channels();
452 for (uint8_t chn = 0; chn < 16; chn++) {
453 if (selected_channels & (0x0001 << chn)) {
455 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
456 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
459 menu->set_active (yn);
466 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
468 using namespace Menu_Helpers;
470 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
473 uint16_t selected_channels = _channel_selector.get_selected_channels();
476 for (uint8_t chn = 0; chn < 16; chn++) {
477 if (selected_channels & (0x0001 << chn)) {
486 /* multiple channels - create a submenu, with 1 item per channel */
488 Menu* chn_menu = manage (new Menu);
489 MenuList& chn_items (chn_menu->items());
490 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
492 /* add a couple of items to hide/show all of them */
494 chn_items.push_back (MenuElem (_("Hide all channels"),
495 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
496 false, param_without_channel)));
497 chn_items.push_back (MenuElem (_("Show all channels"),
498 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
499 true, param_without_channel)));
501 for (uint8_t chn = 0; chn < 16; chn++) {
502 if (selected_channels & (0x0001 << chn)) {
504 /* for each selected channel, add a menu item for this controller */
506 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
507 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
508 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
509 fully_qualified_param)));
511 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
512 bool visible = false;
515 if (track->marked_for_display()) {
520 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
521 _channel_command_menu_map[fully_qualified_param] = cmi;
522 cmi->set_active (visible);
526 /* now create an item in the parent menu that has the per-channel list as a submenu */
528 items.push_back (MenuElem (label, *chn_menu));
532 /* just one channel - create a single menu item for this command+channel combination*/
534 for (uint8_t chn = 0; chn < 16; chn++) {
535 if (selected_channels & (0x0001 << chn)) {
537 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
538 items.push_back (CheckMenuElem (label,
539 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
540 fully_qualified_param)));
542 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
543 bool visible = false;
546 if (track->marked_for_display()) {
551 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
552 _channel_command_menu_map[fully_qualified_param] = cmi;
553 cmi->set_active (visible);
555 /* one channel only */
563 MidiTimeAxisView::build_controller_menu ()
565 using namespace Menu_Helpers;
567 if (controller_menu) {
568 /* it exists and has not been invalidated by a channel mode change, so just return it */
572 controller_menu = new Menu; // explicitly managed by us
573 MenuList& items (controller_menu->items());
575 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
576 for each controller+channel combination covering the currently selected channels for this track
579 uint16_t selected_channels = _channel_selector.get_selected_channels();
581 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
586 for (uint8_t chn = 0; chn < 16; chn++) {
587 if (selected_channels & (0x0001 << chn)) {
594 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
595 bank select controllers, as they are handled by the `patch' code */
597 for (int i = 0; i < 127; i += 16) {
599 Menu* ctl_menu = manage (new Menu);
600 MenuList& ctl_items (ctl_menu->items());
603 /* for each controller, consider whether to create a submenu or a single item */
605 for (int ctl = i; ctl < i+16; ++ctl) {
607 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
613 /* multiple channels - create a submenu, with 1 item per channel */
615 Menu* chn_menu = manage (new Menu);
616 MenuList& chn_items (chn_menu->items());
618 /* add a couple of items to hide/show this controller on all channels */
620 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
621 chn_items.push_back (MenuElem (_("Hide all channels"),
622 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
623 false, param_without_channel)));
624 chn_items.push_back (MenuElem (_("Show all channels"),
625 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
626 true, param_without_channel)));
628 for (uint8_t chn = 0; chn < 16; chn++) {
629 if (selected_channels & (0x0001 << chn)) {
631 /* for each selected channel, add a menu item for this controller */
633 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
634 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
635 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
636 fully_qualified_param)));
638 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
639 bool visible = false;
642 if (track->marked_for_display()) {
647 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
648 _controller_menu_map[fully_qualified_param] = cmi;
649 cmi->set_active (visible);
653 /* add the per-channel menu to the list of controllers, with the name of the controller */
654 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
655 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
659 /* just one channel - create a single menu item for this ctl+channel combination*/
661 for (uint8_t chn = 0; chn < 16; chn++) {
662 if (selected_channels & (0x0001 << chn)) {
664 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
665 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
666 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
667 fully_qualified_param)));
669 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
670 bool visible = false;
673 if (track->marked_for_display()) {
678 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
679 _controller_menu_map[fully_qualified_param] = cmi;
680 cmi->set_active (visible);
682 /* one channel only */
689 /* add the menu for this block of controllers to the overall controller menu */
691 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
696 MidiTimeAxisView::build_note_mode_menu()
698 using namespace Menu_Helpers;
700 Menu* mode_menu = manage (new Menu);
701 MenuList& items = mode_menu->items();
702 mode_menu->set_name ("ArdourContextMenu");
704 RadioMenuItem::Group mode_group;
705 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
706 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
707 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
708 _note_mode_item->set_active(_note_mode == Sustained);
710 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
711 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
712 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
713 _percussion_mode_item->set_active(_note_mode == Percussive);
719 MidiTimeAxisView::build_color_mode_menu()
721 using namespace Menu_Helpers;
723 Menu* mode_menu = manage (new Menu);
724 MenuList& items = mode_menu->items();
725 mode_menu->set_name ("ArdourContextMenu");
727 RadioMenuItem::Group mode_group;
728 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
729 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
730 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
731 _meter_color_mode_item->set_active(_color_mode == MeterColors);
733 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
734 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
735 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
736 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
738 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
739 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
740 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
741 _channel_color_mode_item->set_active(_color_mode == TrackColor);
747 MidiTimeAxisView::set_note_mode(NoteMode mode)
749 if (_note_mode != mode || midi_track()->note_mode() != mode) {
751 midi_track()->set_note_mode(mode);
752 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
753 _view->redisplay_track();
758 MidiTimeAxisView::set_color_mode(ColorMode mode)
760 if (_color_mode != mode) {
761 if (mode == ChannelColors) {
762 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
764 _channel_selector.set_default_channel_color();
768 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
769 _view->redisplay_track();
774 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
776 if (!_ignore_signals)
777 midi_view()->set_note_range(range);
782 MidiTimeAxisView::update_range()
784 MidiGhostRegion* mgr;
786 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
787 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
794 MidiTimeAxisView::show_all_automation ()
797 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
799 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
800 create_automation_child(*i, true);
804 RouteTimeAxisView::show_all_automation ();
808 MidiTimeAxisView::show_existing_automation ()
811 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
813 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
814 create_automation_child(*i, true);
818 RouteTimeAxisView::show_existing_automation ();
821 /** Create an automation track for the given parameter (pitch bend, channel pressure).
824 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
826 if (param.type() == NullAutomation) {
827 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
831 AutomationTracks::iterator existing = _automation_tracks.find (param);
832 if (existing != _automation_tracks.end()) {
836 if (param.type() == GainAutomation) {
837 create_gain_automation_child (param, show);
840 /* These controllers are region "automation", so we do not create
841 * an AutomationList/Line for the track */
843 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
846 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
847 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
852 _route->describe_parameter(param)));
854 add_automation_child (param, track, show);
860 MidiTimeAxisView::route_active_changed ()
862 RouteUI::route_active_changed ();
865 if (_route->active()) {
866 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
867 controls_base_selected_name = "MidiTrackControlsBaseSelected";
868 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
870 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
871 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
872 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
878 if (_route->active()) {
879 controls_ebox.set_name ("BusControlsBaseUnselected");
880 controls_base_selected_name = "BusControlsBaseSelected";
881 controls_base_unselected_name = "BusControlsBaseUnselected";
883 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
884 controls_base_selected_name = "BusControlsBaseInactiveSelected";
885 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
893 MidiTimeAxisView::add_note_selection (uint8_t note)
895 if (!_editor.internal_editing()) {
899 uint16_t chn_mask = _channel_selector.get_selected_channels();
901 if (_view->num_selected_regionviews() == 0) {
902 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
904 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
909 MidiTimeAxisView::extend_note_selection (uint8_t note)
911 if (!_editor.internal_editing()) {
915 uint16_t chn_mask = _channel_selector.get_selected_channels();
917 if (_view->num_selected_regionviews() == 0) {
918 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
920 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
925 MidiTimeAxisView::toggle_note_selection (uint8_t note)
927 if (!_editor.internal_editing()) {
931 uint16_t chn_mask = _channel_selector.get_selected_channels();
933 if (_view->num_selected_regionviews() == 0) {
934 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
936 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
941 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
943 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
947 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
949 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
953 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
955 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
959 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
961 /* hide all automation tracks that use the wrong channel(s) and show all those that use
965 uint16_t selected_channels = _channel_selector.get_selected_channels();
966 bool changed = false;
970 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
972 for (uint32_t chn = 0; chn < 16; ++chn) {
973 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
974 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
980 if ((selected_channels & (0x0001 << chn)) == 0) {
981 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
982 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
984 changed = track->set_visibility (false) || changed;
986 changed = track->set_visibility (true) || changed;
993 /* TODO: Bender, Pressure */
995 /* invalidate the controller menu, so that we rebuilt it next time */
996 _controller_menu_map.clear ();
997 delete controller_menu;
1001 _route->gui_changed ("track_height", this);
1006 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1008 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1013 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1014 if (i != _controller_menu_map.end()) {
1018 i = _channel_command_menu_map.find (param);
1019 if (i != _channel_command_menu_map.end()) {
1026 boost::shared_ptr<MidiRegion>
1027 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1029 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1031 real_editor->begin_reversible_command (_("create region"));
1032 playlist()->clear_changes ();
1034 real_editor->snap_to (pos, 0);
1036 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1037 view()->trackview().track()->name());
1040 plist.add (ARDOUR::Properties::start, 0);
1041 plist.add (ARDOUR::Properties::length, length);
1042 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1044 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1046 playlist()->add_region (region, pos);
1047 _session->add_command (new StatefulDiffCommand (playlist()));
1050 real_editor->commit_reversible_command ();
1053 return boost::dynamic_pointer_cast<MidiRegion>(region);
1057 MidiTimeAxisView::start_step_editing ()
1059 if (!_step_editor) {
1060 _step_editor = new StepEditor (_editor, midi_track(), *this);
1063 _step_editor->start_step_editing ();
1067 MidiTimeAxisView::stop_step_editing ()
1070 _step_editor->stop_step_editing ();