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"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/plugin_insert.h"
54 #include "ardour/profile.h"
55 #include "ardour/region.h"
56 #include "ardour/region_factory.h"
57 #include "ardour/route.h"
58 #include "ardour/session.h"
59 #include "ardour/session_object.h"
60 #include "ardour/source.h"
61 #include "ardour/track.h"
62 #include "ardour/types.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
89 #include "note_base.h"
91 #include "ardour/midi_track.h"
95 using namespace ARDOUR;
96 using namespace ARDOUR_UI_UTILS;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
103 // Minimum height at which a control is displayed
104 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
105 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
107 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
108 : SessionHandlePtr (sess)
109 , RouteTimeAxisView (ed, sess, canvas)
110 , _ignore_signals(false)
112 , _piano_roll_header(0)
113 , _note_mode(Sustained)
115 , _percussion_mode_item(0)
116 , _color_mode(MeterColors)
117 , _meter_color_mode_item(0)
118 , _channel_color_mode_item(0)
119 , _track_color_mode_item(0)
120 , _channel_selector (0)
121 , _step_edit_item (0)
122 , controller_menu (0)
123 , poly_pressure_menu (0)
126 _midnam_model_selector.disable_scrolling();
127 _midnam_custom_device_mode_selector.disable_scrolling();
131 MidiTimeAxisView::set_note_highlight (uint8_t note) {
132 _piano_roll_header->set_note_highlight (note);
136 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
140 _view = new MidiStreamView (*this);
143 _piano_roll_header = new PianoRollHeader(*midi_view());
144 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
145 _range_scroomer->DoubleClicked.connect (
146 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
147 MidiStreamView::ContentsRange, false));
150 /* This next call will result in our height being set up, so it must come after
151 the creation of the piano roll / range scroomer as their visibility is set up
154 RouteTimeAxisView::set_route (rt);
156 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
158 subplugin_menu.set_name ("ArdourContextMenu");
160 if (!gui_property ("note-range-min").empty ()) {
161 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
162 atoi (gui_property ("note-range-max").c_str()),
166 _view->ContentsHeightChanged.connect (
167 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
169 ignore_toggle = false;
171 if (is_midi_track()) {
172 _note_mode = midi_track()->note_mode();
175 /* if set_state above didn't create a gain automation child, we need to make one */
176 if (automation_child (GainAutomation) == 0) {
177 create_automation_child (GainAutomation, false);
180 /* if set_state above didn't create a mute automation child, we need to make one */
181 if (automation_child (MuteAutomation) == 0) {
182 create_automation_child (MuteAutomation, false);
185 if (_route->panner_shell()) {
186 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
189 /* map current state of the route */
190 ensure_pan_views (false);
191 update_control_names();
192 processors_changed (RouteProcessorChange ());
194 _route->processors_changed.connect (*this, invalidator (*this),
195 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
199 _piano_roll_header->SetNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
201 _piano_roll_header->AddNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
203 _piano_roll_header->ExtendNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
205 _piano_roll_header->ToggleNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
208 /* Update StreamView during scroomer drags.*/
210 _range_scroomer->DragStarting.connect (
211 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
212 _range_scroomer->DragFinishing.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
215 /* Put the scroomer and the keyboard in a VBox with a padding
216 label so that they can be reduced in height for stacked-view
220 HSeparator* separator = manage (new HSeparator());
221 separator->set_name("TrackSeparator");
222 separator->set_size_request(-1, 1);
225 VBox* v = manage (new VBox);
226 HBox* h = manage (new HBox);
227 h->pack_end (*_piano_roll_header);
228 h->pack_end (*_range_scroomer);
229 v->pack_start (*separator, false, false);
230 v->pack_start (*h, true, true);
233 top_hbox.remove(scroomer_placeholder);
234 time_axis_hbox.pack_end(*v, false, false, 0);
235 midi_scroomer_size_group->add_widget (*v);
237 midi_view()->NoteRangeChanged.connect (
238 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
240 /* ask for notifications of any new RegionViews */
241 _view->RegionViewAdded.connect (
242 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
244 midi_track()->playback_filter().ChannelModeChanged.connect (
245 *this, invalidator (*this),
246 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
248 midi_track()->playback_filter().ChannelMaskChanged.connect (
249 *this, invalidator (*this),
250 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
252 midi_track()->capture_filter().ChannelModeChanged.connect (
253 *this, invalidator (*this),
254 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
256 midi_track()->capture_filter().ChannelMaskChanged.connect (
257 *this, invalidator (*this),
258 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
261 playback_channel_mode_changed ();
262 capture_channel_mode_changed ();
264 if (!_editor.have_idled()) {
265 /* first idle will do what we need */
271 if (gui_property (X_("midnam-model-name")).empty()) {
272 set_gui_property (X_("midnam-model-name"), "Generic");
275 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
276 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
278 set_gui_property (X_("midnam-custom-device-mode"),
279 *device_names->custom_device_mode_names().begin());
283 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
284 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
286 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
287 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
289 _midi_controls_box.set_homogeneous(false);
290 _midi_controls_box.set_border_width (2);
292 _channel_status_box.set_homogeneous (false);
293 _channel_status_box.set_spacing (4);
295 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
296 channel_selector_button->set_name ("route button");
297 set_tooltip (channel_selector_button, _("Click to edit channel settings"));
299 // Insert expanding space labels to get full width justification
300 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
301 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
302 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
303 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
304 _channel_status_box.pack_end (*channel_selector_button, false, false);
305 _channel_status_box.show_all ();
307 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
309 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
311 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
312 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
315 setup_midnam_patches ();
316 update_patch_selector ();
318 model_changed (gui_property(X_("midnam-model-name")));
319 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
321 controls_vbox.pack_start(_midi_controls_box, false, false);
323 const string color_mode = gui_property ("color-mode");
324 if (!color_mode.empty()) {
325 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
326 if (_channel_selector && _color_mode == ChannelColors) {
327 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
331 set_color_mode (_color_mode, true, false);
333 const string note_mode = gui_property ("note-mode");
334 if (!note_mode.empty()) {
335 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
336 if (_percussion_mode_item) {
337 _percussion_mode_item->set_active (_note_mode == Percussive);
341 /* Look for any GUI object state nodes that represent automation children
342 * that should exist, and create the children.
345 const list<string> gui_ids = gui_object_state().all_ids ();
346 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
349 Evoral::Parameter parameter (0, 0, 0);
351 bool const p = AutomationTimeAxisView::parse_state_id (
352 *i, route_id, has_parameter, parameter);
353 if (p && route_id == _route->id () && has_parameter) {
354 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
355 create_automation_child (parameter, string_is_affirmative (visible));
361 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
363 RouteTimeAxisView::processors_changed (c);
364 update_patch_selector ();
368 MidiTimeAxisView::first_idle ()
375 MidiTimeAxisView::~MidiTimeAxisView ()
377 delete _channel_selector;
379 delete _piano_roll_header;
380 _piano_roll_header = 0;
382 delete _range_scroomer;
385 delete controller_menu;
390 MidiTimeAxisView::check_step_edit ()
392 ensure_step_editor ();
393 _step_editor->check_step_edit ();
397 MidiTimeAxisView::setup_midnam_patches ()
399 typedef MIDI::Name::MidiPatchManager PatchManager;
400 PatchManager& patch_manager = PatchManager::instance();
402 _midnam_model_selector.clear_items ();
403 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
404 m != patch_manager.devices_by_manufacturer().end(); ++m) {
405 Menu* menu = Gtk::manage(new Menu);
406 Menu_Helpers::MenuList& items = menu->items();
408 // Build manufacturer submenu
409 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
410 n != m->second.end(); ++n) {
411 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
413 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
416 items.push_back(elem);
419 // Add manufacturer submenu to selector
420 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
423 if (!get_device_names()) {
424 model_changed ("Generic");
429 MidiTimeAxisView::drop_instrument_ref ()
431 midnam_connection.drop_connections ();
434 MidiTimeAxisView::start_scroomer_update ()
436 _note_range_changed_connection.disconnect();
437 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
438 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
441 MidiTimeAxisView::stop_scroomer_update ()
443 _note_range_changed_connection.disconnect();
447 MidiTimeAxisView::update_patch_selector ()
449 typedef MIDI::Name::MidiPatchManager PatchManager;
450 PatchManager& patch_manager = PatchManager::instance();
452 bool pluginprovided = false;
454 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
455 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
456 if (pi && pi->plugin ()->has_midnam ()) {
457 midnam_connection.drop_connections ();
458 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
459 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
461 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
462 boost::bind (&Plugin::read_midnam, pi->plugin ()),
465 pluginprovided = true;
466 std::string model_name = pi->plugin ()->midnam_model ();
467 if (gui_property (X_("midnam-model-name")) != model_name) {
468 model_changed (model_name);
473 if (patch_manager.all_models().empty() || pluginprovided) {
474 _midnam_model_selector.hide ();
475 _midnam_custom_device_mode_selector.hide ();
477 _midnam_model_selector.show ();
478 _midnam_custom_device_mode_selector.show ();
483 MidiTimeAxisView::model_changed(const std::string& model)
485 set_gui_property (X_("midnam-model-name"), model);
487 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
488 .custom_device_mode_names_by_model(model);
490 _midnam_model_selector.set_text(model);
491 _midnam_custom_device_mode_selector.clear_items();
493 for (std::list<std::string>::const_iterator i = device_modes.begin();
494 i != device_modes.end(); ++i) {
495 _midnam_custom_device_mode_selector.AddMenuElem(
496 Gtk::Menu_Helpers::MenuElem(
497 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
501 if (!device_modes.empty()) {
502 custom_device_mode_changed(device_modes.front());
505 if (device_modes.size() > 1) {
506 _midnam_custom_device_mode_selector.show();
508 _midnam_custom_device_mode_selector.hide();
511 // now this is a real bad hack
512 if (device_modes.size() > 0) {
513 _route->instrument_info().set_external_instrument (model, device_modes.front());
515 _route->instrument_info().set_external_instrument (model, "");
518 // Rebuild controller menu
519 _controller_menu_map.clear ();
520 delete controller_menu;
522 build_automation_action_menu(false);
526 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
528 const std::string model = gui_property (X_("midnam-model-name"));
530 set_gui_property (X_("midnam-custom-device-mode"), mode);
531 _midnam_custom_device_mode_selector.set_text(mode);
532 _route->instrument_info().set_external_instrument (model, mode);
536 MidiTimeAxisView::midi_view()
538 return dynamic_cast<MidiStreamView*>(_view);
542 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
544 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
545 _midi_controls_box.show ();
547 _midi_controls_box.hide();
550 if (h >= KEYBOARD_MIN_HEIGHT) {
551 if (is_track() && _range_scroomer) {
552 _range_scroomer->show();
554 if (is_track() && _piano_roll_header) {
555 _piano_roll_header->show();
558 if (is_track() && _range_scroomer) {
559 _range_scroomer->hide();
561 if (is_track() && _piano_roll_header) {
562 _piano_roll_header->hide();
566 /* We need to do this after changing visibility of our stuff, as it will
567 eventually trigger a call to Editor::reset_controls_layout_width(),
568 which needs to know if we have just shown or hidden a scroomer /
571 RouteTimeAxisView::set_height (h, m);
575 MidiTimeAxisView::append_extra_display_menu_items ()
577 using namespace Menu_Helpers;
579 MenuList& items = display_menu->items();
582 Menu *range_menu = manage(new Menu);
583 MenuList& range_items = range_menu->items();
584 range_menu->set_name ("ArdourContextMenu");
586 range_items.push_back (
587 MenuElem (_("Show Full Range"),
588 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
589 MidiStreamView::FullRange, true)));
591 range_items.push_back (
592 MenuElem (_("Fit Contents"),
593 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
594 MidiStreamView::ContentsRange, true)));
596 items.push_back (MenuElem (_("Note Range"), *range_menu));
597 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
598 items.push_back (MenuElem (_("Channel Selector"),
599 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
601 color_mode_menu = build_color_mode_menu();
602 if (color_mode_menu) {
603 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
606 items.push_back (SeparatorElem ());
610 MidiTimeAxisView::toggle_channel_selector ()
612 if (!_channel_selector) {
613 _channel_selector = new MidiChannelSelectorWindow (midi_track());
615 if (_color_mode == ChannelColors) {
616 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
618 _channel_selector->set_default_channel_color ();
621 _channel_selector->show_all ();
623 _channel_selector->cycle_visibility ();
628 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
630 using namespace Menu_Helpers;
632 /* If we have a controller menu, we need to detach it before
633 RouteTimeAxis::build_automation_action_menu destroys the
634 menu it is attached to. Otherwise GTK destroys
635 controller_menu's gobj, meaning that it can't be reattached
636 below. See bug #3134.
639 if (controller_menu) {
640 detach_menu (*controller_menu);
643 _channel_command_menu_map.clear ();
644 RouteTimeAxisView::build_automation_action_menu (for_selection);
646 MenuList& automation_items = automation_action_menu->items();
648 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
650 if (selected_channels != 0) {
652 automation_items.push_back (SeparatorElem());
654 /* these 2 MIDI "command" types are semantically more like automation
655 than note data, but they are not MIDI controllers. We give them
656 special status in this menu, since they will not show up in the
657 controller list and anyone who actually knows something about MIDI
658 (!) would not expect to find them there.
661 add_channel_command_menu_item (
662 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
663 automation_items.back().set_sensitive (
664 !for_selection || _editor.get_selection().tracks.size() == 1);
665 add_channel_command_menu_item (
666 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
667 automation_items.back().set_sensitive (
668 !for_selection || _editor.get_selection().tracks.size() == 1);
670 /* now all MIDI controllers. Always offer the possibility that we will
671 rebuild the controllers menu since it might need to be updated after
672 a channel mode change or other change. Also detach it first in case
673 it has been used anywhere else.
676 build_controller_menu ();
678 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
680 if (!poly_pressure_menu) {
681 poly_pressure_menu = new Gtk::Menu;
684 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
686 automation_items.back().set_sensitive (
687 !for_selection || _editor.get_selection().tracks.size() == 1);
689 automation_items.push_back (
690 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
691 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
696 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
698 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
700 for (uint8_t chn = 0; chn < 16; chn++) {
701 if (selected_channels & (0x0001 << chn)) {
703 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
704 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
707 menu->set_active (yn);
714 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
716 AutomationType auto_type,
719 using namespace Menu_Helpers;
721 /* count the number of selected channels because we will build a different menu
722 structure if there is more than 1 selected.
725 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
728 for (uint8_t chn = 0; chn < 16; chn++) {
729 if (selected_channels & (0x0001 << chn)) {
738 /* multiple channels - create a submenu, with 1 item per channel */
740 Menu* chn_menu = manage (new Menu);
741 MenuList& chn_items (chn_menu->items());
742 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
744 /* add a couple of items to hide/show all of them */
746 chn_items.push_back (
747 MenuElem (_("Hide all channels"),
748 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
749 false, param_without_channel)));
750 chn_items.push_back (
751 MenuElem (_("Show all channels"),
752 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
753 true, param_without_channel)));
755 for (uint8_t chn = 0; chn < 16; chn++) {
756 if (selected_channels & (0x0001 << chn)) {
758 /* for each selected channel, add a menu item for this controller */
760 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
761 chn_items.push_back (
762 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
763 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
764 fully_qualified_param)));
766 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
767 bool visible = false;
770 if (track->marked_for_display()) {
775 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
776 _channel_command_menu_map[fully_qualified_param] = cmi;
777 cmi->set_active (visible);
781 /* now create an item in the parent menu that has the per-channel list as a submenu */
783 items.push_back (MenuElem (label, *chn_menu));
787 /* just one channel - create a single menu item for this command+channel combination*/
789 for (uint8_t chn = 0; chn < 16; chn++) {
790 if (selected_channels & (0x0001 << chn)) {
792 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
794 CheckMenuElem (label,
795 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
796 fully_qualified_param)));
798 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
799 bool visible = false;
802 if (track->marked_for_display()) {
807 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
808 _channel_command_menu_map[fully_qualified_param] = cmi;
809 cmi->set_active (visible);
811 /* one channel only */
818 /** Add a single menu item for a controller on one channel. */
820 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
822 const std::string& name)
824 using namespace Menu_Helpers;
826 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
827 for (uint8_t chn = 0; chn < 16; chn++) {
828 if (selected_channels & (0x0001 << chn)) {
830 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
831 ctl_items.push_back (
833 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
835 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
836 fully_qualified_param)));
837 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
839 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
840 fully_qualified_param);
842 bool visible = false;
844 if (track->marked_for_display()) {
849 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
850 _controller_menu_map[fully_qualified_param] = cmi;
851 cmi->set_active (visible);
853 /* one channel only */
859 /** Add a submenu with 1 item per channel for a controller on many channels. */
861 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
863 const std::string& name)
865 using namespace Menu_Helpers;
867 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
869 Menu* chn_menu = manage (new Menu);
870 MenuList& chn_items (chn_menu->items());
872 /* add a couple of items to hide/show this controller on all channels */
874 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
875 chn_items.push_back (
876 MenuElem (_("Hide all channels"),
877 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
878 false, param_without_channel)));
879 chn_items.push_back (
880 MenuElem (_("Show all channels"),
881 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
882 true, param_without_channel)));
884 for (uint8_t chn = 0; chn < 16; chn++) {
885 if (selected_channels & (0x0001 << chn)) {
887 /* for each selected channel, add a menu item for this controller */
889 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
890 chn_items.push_back (
891 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
892 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
893 fully_qualified_param)));
895 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
896 fully_qualified_param);
897 bool visible = false;
900 if (track->marked_for_display()) {
905 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
906 _controller_menu_map[fully_qualified_param] = cmi;
907 cmi->set_active (visible);
911 /* add the per-channel menu to the list of controllers, with the name of the controller */
912 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
914 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
917 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
918 MidiTimeAxisView::get_device_mode()
920 using namespace MIDI::Name;
922 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
924 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
927 return device_names->custom_device_mode_by_name(
928 gui_property (X_("midnam-custom-device-mode")));
931 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
932 MidiTimeAxisView::get_device_names()
934 using namespace MIDI::Name;
936 const std::string model = gui_property (X_("midnam-model-name"));
938 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
939 .document_by_model(model);
941 return midnam->master_device_names(model);
943 return boost::shared_ptr<MasterDeviceNames>();
948 MidiTimeAxisView::build_controller_menu ()
950 using namespace Menu_Helpers;
952 if (controller_menu) {
953 /* it exists and has not been invalidated by a channel mode change */
957 controller_menu = new Menu; // explicitly managed by us
958 MenuList& items (controller_menu->items());
960 /* create several "top level" menu items for sets of controllers (16 at a
961 time), and populate each one with a submenu for each controller+channel
962 combination covering the currently selected channels for this track
965 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
967 /* count the number of selected channels because we will build a different menu
968 structure if there is more than 1 selected.
972 for (uint8_t chn = 0; chn < 16; chn++) {
973 if (selected_channels & (0x0001 << chn)) {
980 using namespace MIDI::Name;
981 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
983 if (device_names && !device_names->controls().empty()) {
984 /* Controllers names available in midnam file, generate fancy menu */
985 unsigned n_items = 0;
986 unsigned n_groups = 0;
988 /* TODO: This is not correct, should look up the currently applicable ControlNameList
989 and only build a menu for that one. */
990 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
991 l != device_names->controls().end(); ++l) {
992 boost::shared_ptr<ControlNameList> name_list = l->second;
993 Menu* ctl_menu = NULL;
995 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
996 c != name_list->controls().end();) {
997 const uint16_t ctl = c->second->number();
998 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
999 /* Skip bank select controllers since they're handled specially */
1001 /* Create a new submenu */
1002 ctl_menu = manage (new Menu);
1005 MenuList& ctl_items (ctl_menu->items());
1007 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
1009 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
1014 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
1015 /* Submenu has 16 items or we're done, add it to controller menu and reset */
1017 MenuElem(string_compose(_("Controllers %1-%2"),
1018 (16 * n_groups), (16 * n_groups) + n_items - 1),
1027 /* No controllers names, generate generic numeric menu */
1028 for (int i = 0; i < 127; i += 16) {
1029 Menu* ctl_menu = manage (new Menu);
1030 MenuList& ctl_items (ctl_menu->items());
1032 for (int ctl = i; ctl < i+16; ++ctl) {
1033 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1034 /* Skip bank select controllers since they're handled specially */
1039 add_multi_channel_controller_item(
1040 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1042 add_single_channel_controller_item(
1043 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1047 /* Add submenu for this block of controllers to controller menu */
1049 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1056 MidiTimeAxisView::build_note_mode_menu()
1058 using namespace Menu_Helpers;
1060 Menu* mode_menu = manage (new Menu);
1061 MenuList& items = mode_menu->items();
1062 mode_menu->set_name ("ArdourContextMenu");
1064 RadioMenuItem::Group mode_group;
1066 RadioMenuElem (mode_group,_("Sustained"),
1067 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1069 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1070 _note_mode_item->set_active(_note_mode == Sustained);
1073 RadioMenuElem (mode_group, _("Percussive"),
1074 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1075 Percussive, true)));
1076 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1077 _percussion_mode_item->set_active(_note_mode == Percussive);
1083 MidiTimeAxisView::build_color_mode_menu()
1085 using namespace Menu_Helpers;
1087 Menu* mode_menu = manage (new Menu);
1088 MenuList& items = mode_menu->items();
1089 mode_menu->set_name ("ArdourContextMenu");
1091 RadioMenuItem::Group mode_group;
1093 RadioMenuElem (mode_group, _("Meter Colors"),
1094 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1095 MeterColors, false, true, true)));
1096 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1097 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1100 RadioMenuElem (mode_group, _("Channel Colors"),
1101 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1102 ChannelColors, false, true, true)));
1103 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1104 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1107 RadioMenuElem (mode_group, _("Track Color"),
1108 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1109 TrackColor, false, true, true)));
1110 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1111 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1117 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1119 if (apply_to_selection) {
1120 _editor.get_selection().tracks.foreach_midi_time_axis (
1121 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1123 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1125 midi_track()->set_note_mode(mode);
1126 set_gui_property ("note-mode", enum_2_string(_note_mode));
1127 _view->redisplay_track();
1133 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1135 if (apply_to_selection) {
1136 _editor.get_selection().tracks.foreach_midi_time_axis (
1137 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1139 if (_color_mode == mode && !force) {
1143 if (_channel_selector) {
1144 if (mode == ChannelColors) {
1145 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1147 _channel_selector->set_default_channel_color();
1152 set_gui_property ("color-mode", enum_2_string(_color_mode));
1154 _view->redisplay_track();
1160 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1162 if (apply_to_selection) {
1163 _editor.get_selection().tracks.foreach_midi_time_axis (
1164 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1166 if (!_ignore_signals) {
1167 midi_view()->set_note_range(range);
1173 MidiTimeAxisView::update_range()
1175 MidiGhostRegion* mgr;
1177 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1178 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1179 mgr->update_range();
1185 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1187 using namespace MIDI::Name;
1189 if (apply_to_selection) {
1190 _editor.get_selection().tracks.foreach_midi_time_axis (
1191 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1194 // Show existing automation
1195 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1197 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1198 create_automation_child(*i, true);
1201 // Show automation for all controllers named in midnam file
1202 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1203 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1204 device_names && !device_names->controls().empty()) {
1205 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1206 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1207 for (uint32_t chn = 0; chn < 16; ++chn) {
1208 if ((selected_channels & (0x0001 << chn)) == 0) {
1209 // Channel not in use
1213 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1219 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1220 chan_names->control_list_name());
1221 if (!control_names) {
1225 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1226 c != control_names->controls().end();
1228 const uint16_t ctl = c->second->number();
1229 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1230 /* Skip bank select controllers since they're handled specially */
1231 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1232 create_automation_child(param, true);
1239 RouteTimeAxisView::show_all_automation ();
1244 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1246 if (apply_to_selection) {
1247 _editor.get_selection().tracks.foreach_midi_time_axis (
1248 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1251 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1253 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1254 create_automation_child (*i, true);
1258 RouteTimeAxisView::show_existing_automation ();
1262 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1265 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1267 if (param.type() == NullAutomation) {
1271 AutomationTracks::iterator existing = _automation_tracks.find (param);
1273 if (existing != _automation_tracks.end()) {
1275 /* automation track created because we had existing data for
1276 * the processor, but visibility may need to be controlled
1277 * since it will have been set visible by default.
1280 existing->second->set_marked_for_display (show);
1289 boost::shared_ptr<AutomationTimeAxisView> track;
1290 boost::shared_ptr<AutomationControl> control;
1293 switch (param.type()) {
1295 case GainAutomation:
1296 create_gain_automation_child (param, show);
1299 case MuteAutomation:
1300 create_mute_automation_child (param, show);
1303 case PluginAutomation:
1304 /* handled elsewhere */
1307 case MidiCCAutomation:
1308 case MidiPgmChangeAutomation:
1309 case MidiPitchBenderAutomation:
1310 case MidiChannelPressureAutomation:
1311 case MidiSystemExclusiveAutomation:
1312 /* These controllers are region "automation" - they are owned
1313 * by regions (and their MidiModels), not by the track. As a
1314 * result there is no AutomationList/Line for the track, but we create
1315 * a controller for the user to write immediate events, so the editor
1316 * can act as a control surface for the present MIDI controllers.
1318 * TODO: Record manipulation of the controller to regions?
1321 control = _route->automation_control(param, true);
1322 track.reset (new AutomationTimeAxisView (
1325 control ? _route : boost::shared_ptr<Automatable> (),
1332 _route->describe_parameter(param)));
1335 _view->foreach_regionview (
1336 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1339 add_automation_child (param, track, show);
1342 case PanWidthAutomation:
1343 case PanElevationAutomation:
1344 case PanAzimuthAutomation:
1345 ensure_pan_views (show);
1349 error << "MidiTimeAxisView: unknown automation child "
1350 << EventTypeMap::instance().to_symbol(param) << endmsg;
1355 MidiTimeAxisView::route_active_changed ()
1357 RouteUI::route_active_changed ();
1358 update_control_names();
1362 MidiTimeAxisView::update_control_names ()
1365 if (_route->active()) {
1366 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1367 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1369 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1370 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1372 } else { // MIDI bus (which doesn't exist yet..)
1373 if (_route->active()) {
1374 controls_base_selected_name = "BusControlsBaseSelected";
1375 controls_base_unselected_name = "BusControlsBaseUnselected";
1377 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1378 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1383 controls_ebox.set_name (controls_base_selected_name);
1384 time_axis_frame.set_name (controls_base_selected_name);
1386 controls_ebox.set_name (controls_base_unselected_name);
1387 time_axis_frame.set_name (controls_base_unselected_name);
1392 MidiTimeAxisView::set_note_selection (uint8_t note)
1394 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1396 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1398 if (_view->num_selected_regionviews() == 0) {
1399 _view->foreach_regionview (
1400 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1403 _view->foreach_selected_regionview (
1404 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1408 _editor.commit_reversible_selection_op();
1412 MidiTimeAxisView::add_note_selection (uint8_t note)
1414 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1416 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1418 if (_view->num_selected_regionviews() == 0) {
1419 _view->foreach_regionview (
1420 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1423 _view->foreach_selected_regionview (
1424 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1428 _editor.commit_reversible_selection_op();
1432 MidiTimeAxisView::extend_note_selection (uint8_t note)
1434 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1436 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1438 if (_view->num_selected_regionviews() == 0) {
1439 _view->foreach_regionview (
1440 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1443 _view->foreach_selected_regionview (
1444 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1448 _editor.commit_reversible_selection_op();
1452 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1454 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1456 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1458 if (_view->num_selected_regionviews() == 0) {
1459 _view->foreach_regionview (
1460 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1463 _view->foreach_selected_regionview (
1464 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1468 _editor.commit_reversible_selection_op();
1472 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1474 _view->foreach_regionview (
1475 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1479 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1481 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1485 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1487 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1491 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1493 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1497 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1499 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1503 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1505 Evoral::Sequence<Evoral::Beats>::Notes selected;
1506 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1508 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1510 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1511 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1512 notes.insert (*sel_it);
1515 if (!notes.empty()) {
1516 selection.push_back (make_pair ((rv)->region()->id(), notes));
1521 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1523 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1527 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1528 bool changed = false;
1532 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1534 for (uint32_t chn = 0; chn < 16; ++chn) {
1535 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1536 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1542 if ((selected_channels & (0x0001 << chn)) == 0) {
1543 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1544 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1546 changed = track->set_marked_for_display (false) || changed;
1548 changed = track->set_marked_for_display (true) || changed;
1555 /* TODO: Bender, Pressure */
1557 /* invalidate the controller menu, so that we rebuild it next time */
1558 _controller_menu_map.clear ();
1559 delete controller_menu;
1560 controller_menu = 0;
1568 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1570 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1575 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1576 if (i != _controller_menu_map.end()) {
1580 i = _channel_command_menu_map.find (param);
1581 if (i != _channel_command_menu_map.end()) {
1588 boost::shared_ptr<MidiRegion>
1589 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, const int32_t sub_num)
1591 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1593 real_editor->begin_reversible_command (Operations::create_region);
1595 playlist()->clear_changes ();
1597 real_editor->snap_to (pos, RoundNearest);
1599 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1602 plist.add (ARDOUR::Properties::start, 0);
1603 plist.add (ARDOUR::Properties::length, length);
1604 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1606 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1607 /* sets beat position */
1608 region->set_position (pos, sub_num);
1609 playlist()->add_region (region, pos, 1.0, false, sub_num);
1610 _session->add_command (new StatefulDiffCommand (playlist()));
1613 real_editor->commit_reversible_command ();
1616 return boost::dynamic_pointer_cast<MidiRegion>(region);
1620 MidiTimeAxisView::ensure_step_editor ()
1622 if (!_step_editor) {
1623 _step_editor = new StepEditor (_editor, midi_track(), *this);
1628 MidiTimeAxisView::start_step_editing ()
1630 ensure_step_editor ();
1631 _step_editor->start_step_editing ();
1635 MidiTimeAxisView::stop_step_editing ()
1638 _step_editor->stop_step_editing ();
1642 /** @return channel (counted from 0) to add an event to, based on the current setting
1643 * of the channel selector.
1646 MidiTimeAxisView::get_channel_for_add () const
1648 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1650 uint8_t channel = 0;
1652 /* pick the highest selected channel, unless all channels are selected,
1653 which is interpreted to mean channel 1 (zero)
1656 for (uint16_t i = 0; i < 16; ++i) {
1657 if (chn_mask & (1<<i)) {
1663 if (chn_cnt == 16) {
1671 MidiTimeAxisView::note_range_changed ()
1673 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1674 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1678 MidiTimeAxisView::contents_height_changed ()
1680 _range_scroomer->queue_resize ();
1684 MidiTimeAxisView::playback_channel_mode_changed ()
1686 /* Invalidate the controller automation menu */
1687 delete controller_menu;
1688 controller_menu = 0;
1689 /* Update the button text */
1690 switch (midi_track()->get_playback_channel_mode()) {
1692 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1694 case FilterChannels:
1695 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1698 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1704 MidiTimeAxisView::capture_channel_mode_changed ()
1706 switch (midi_track()->get_capture_channel_mode()) {
1708 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1710 case FilterChannels:
1711 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1714 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1720 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1722 if (!_editor.internal_editing()) {
1723 // Non-internal paste, paste regions like any other route
1724 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1727 return midi_view()->paste(pos, selection, ctx, sub_num);