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 <gtkmm/separator.h>
29 #include <gtkmm/stock.h>
31 #include "pbd/error.h"
33 #include "pbd/stl_delete.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/basename.h"
36 #include "pbd/enumwriter.h"
37 #include "pbd/memento_command.h"
38 #include "pbd/stateful_diff_command.h"
40 #include "gtkmm2ext/gtk_ui.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/tooltips.h"
45 #include "ardour/event_type_map.h"
46 #include "ardour/midi_patch_manager.h"
47 #include "ardour/midi_playlist.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_source.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/operations.h"
52 #include "ardour/pannable.h"
53 #include "ardour/panner.h"
54 #include "ardour/panner_shell.h"
55 #include "ardour/playlist.h"
56 #include "ardour/plugin_insert.h"
57 #include "ardour/profile.h"
58 #include "ardour/region.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/route.h"
61 #include "ardour/session.h"
62 #include "ardour/session_object.h"
63 #include "ardour/source.h"
64 #include "ardour/track.h"
65 #include "ardour/types.h"
67 #include "automation_line.h"
68 #include "automation_time_axis.h"
71 #include "ghostregion.h"
72 #include "gui_thread.h"
74 #include "midi_channel_selector.h"
75 #include "midi_scroomer.h"
76 #include "midi_streamview.h"
77 #include "midi_region_view.h"
78 #include "midi_time_axis.h"
79 #include "patch_change_dialog.h"
80 #include "piano_roll_header.h"
81 #include "playlist_selector.h"
82 #include "plugin_selector.h"
83 #include "plugin_ui.h"
84 #include "point_selection.h"
85 #include "region_view.h"
86 #include "rgb_macros.h"
87 #include "selection.h"
88 #include "step_editor.h"
90 #include "note_base.h"
92 #include "ardour/midi_track.h"
96 using namespace ARDOUR;
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)
125 , _patch_change_dialog (0)
127 _midnam_model_selector.disable_scrolling();
128 _midnam_custom_device_mode_selector.disable_scrolling();
132 MidiTimeAxisView::set_note_highlight (uint8_t note) {
133 _piano_roll_header->set_note_highlight (note);
137 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
141 _view = new MidiStreamView (*this);
144 _piano_roll_header = new PianoRollHeader(*midi_view());
145 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
146 _range_scroomer->DoubleClicked.connect (
147 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
148 MidiStreamView::ContentsRange, false));
151 /* This next call will result in our height being set up, so it must come after
152 the creation of the piano roll / range scroomer as their visibility is set up
155 RouteTimeAxisView::set_route (rt);
157 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
159 subplugin_menu.set_name ("ArdourContextMenu");
161 if (!gui_property ("note-range-min").empty ()) {
162 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
163 atoi (gui_property ("note-range-max").c_str()),
167 _view->ContentsHeightChanged.connect (
168 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
170 ignore_toggle = false;
172 if (is_midi_track()) {
173 _note_mode = midi_track()->note_mode();
176 /* if set_state above didn't create a gain automation child, we need to make one */
177 if (automation_child (GainAutomation) == 0) {
178 create_automation_child (GainAutomation, false);
181 /* if set_state above didn't create a mute automation child, we need to make one */
182 if (automation_child (MuteAutomation) == 0) {
183 create_automation_child (MuteAutomation, false);
186 if (_route->panner_shell()) {
187 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
190 /* map current state of the route */
191 ensure_pan_views (false);
192 update_control_names();
193 processors_changed (RouteProcessorChange ());
195 _route->processors_changed.connect (*this, invalidator (*this),
196 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
200 _piano_roll_header->SetNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
202 _piano_roll_header->AddNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
204 _piano_roll_header->ExtendNoteSelection.connect (
205 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
206 _piano_roll_header->ToggleNoteSelection.connect (
207 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
209 /* Update StreamView during scroomer drags.*/
211 _range_scroomer->DragStarting.connect (
212 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
213 _range_scroomer->DragFinishing.connect (
214 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
216 /* Put the scroomer and the keyboard in a VBox with a padding
217 label so that they can be reduced in height for stacked-view
221 HSeparator* separator = manage (new HSeparator());
222 separator->set_name("TrackSeparator");
223 separator->set_size_request(-1, 1);
226 VBox* v = manage (new VBox);
227 HBox* h = manage (new HBox);
228 h->pack_end (*_piano_roll_header);
229 h->pack_end (*_range_scroomer);
230 v->pack_start (*separator, false, false);
231 v->pack_start (*h, true, true);
234 top_hbox.remove(scroomer_placeholder);
235 time_axis_hbox.pack_end(*v, false, false, 0);
236 midi_scroomer_size_group->add_widget (*v);
238 midi_view()->NoteRangeChanged.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 /* ask for notifications of any new RegionViews */
242 _view->RegionViewAdded.connect (
243 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 if (!_editor.have_idled()) {
246 /* first idle will do what we need */
252 if (gui_property (X_("midnam-model-name")).empty()) {
253 set_gui_property (X_("midnam-model-name"), "Generic");
256 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
257 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
259 set_gui_property (X_("midnam-custom-device-mode"),
260 *device_names->custom_device_mode_names().begin());
264 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
265 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
267 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
268 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
270 _midi_controls_box.set_homogeneous(false);
271 _midi_controls_box.set_border_width (2);
273 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
274 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
277 setup_midnam_patches ();
278 update_patch_selector ();
280 model_changed (gui_property(X_("midnam-model-name")));
281 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
283 controls_vbox.pack_start(_midi_controls_box, false, false);
285 const string color_mode = gui_property ("color-mode");
286 if (!color_mode.empty()) {
287 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
288 if (_channel_selector && _color_mode == ChannelColors) {
289 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
293 set_color_mode (_color_mode, true, false);
295 const string note_mode = gui_property ("note-mode");
296 if (!note_mode.empty()) {
297 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
298 if (_percussion_mode_item) {
299 _percussion_mode_item->set_active (_note_mode == Percussive);
303 /* Look for any GUI object state nodes that represent automation children
304 * that should exist, and create the children.
307 const list<string> gui_ids = gui_object_state().all_ids ();
308 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
311 Evoral::Parameter parameter (0, 0, 0);
313 bool const p = AutomationTimeAxisView::parse_state_id (
314 *i, route_id, has_parameter, parameter);
315 if (p && route_id == _route->id () && has_parameter) {
316 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
317 create_automation_child (parameter, string_to<bool> (visible));
323 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
325 RouteTimeAxisView::processors_changed (c);
326 update_patch_selector ();
330 MidiTimeAxisView::first_idle ()
337 MidiTimeAxisView::~MidiTimeAxisView ()
339 delete _channel_selector;
341 delete _piano_roll_header;
342 _piano_roll_header = 0;
344 delete _range_scroomer;
347 delete controller_menu;
350 delete _patch_change_dialog;
351 _patch_change_dialog = 0;
355 MidiTimeAxisView::check_step_edit ()
357 ensure_step_editor ();
358 _step_editor->check_step_edit ();
362 MidiTimeAxisView::setup_midnam_patches ()
364 typedef MIDI::Name::MidiPatchManager PatchManager;
365 PatchManager& patch_manager = PatchManager::instance();
367 _midnam_model_selector.clear_items ();
368 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
369 m != patch_manager.devices_by_manufacturer().end(); ++m) {
370 Menu* menu = Gtk::manage(new Menu);
371 Menu_Helpers::MenuList& items = menu->items();
373 // Build manufacturer submenu
374 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
375 n != m->second.end(); ++n) {
376 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
378 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
381 items.push_back(elem);
384 // Add manufacturer submenu to selector
385 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
388 if (!get_device_names()) {
389 model_changed ("Generic");
394 MidiTimeAxisView::drop_instrument_ref ()
396 midnam_connection.drop_connections ();
399 MidiTimeAxisView::start_scroomer_update ()
401 _note_range_changed_connection.disconnect();
402 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
403 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
406 MidiTimeAxisView::stop_scroomer_update ()
408 _note_range_changed_connection.disconnect();
412 MidiTimeAxisView::update_patch_selector ()
414 typedef MIDI::Name::MidiPatchManager PatchManager;
415 PatchManager& patch_manager = PatchManager::instance();
417 bool pluginprovided = false;
419 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
420 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
421 if (pi && pi->plugin ()->has_midnam ()) {
422 midnam_connection.drop_connections ();
423 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
424 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
426 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
427 boost::bind (&Plugin::read_midnam, pi->plugin ()),
430 pluginprovided = true;
431 std::string model_name = pi->plugin ()->midnam_model ();
432 if (gui_property (X_("midnam-model-name")) != model_name) {
433 model_changed (model_name);
438 if (patch_manager.all_models().empty() || pluginprovided) {
439 _midnam_model_selector.hide ();
440 _midnam_custom_device_mode_selector.hide ();
442 _midnam_model_selector.show ();
443 _midnam_custom_device_mode_selector.show ();
448 MidiTimeAxisView::model_changed(const std::string& model)
450 set_gui_property (X_("midnam-model-name"), model);
452 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
453 .custom_device_mode_names_by_model(model);
455 _midnam_model_selector.set_text(model);
456 _midnam_custom_device_mode_selector.clear_items();
458 for (std::list<std::string>::const_iterator i = device_modes.begin();
459 i != device_modes.end(); ++i) {
460 _midnam_custom_device_mode_selector.AddMenuElem(
461 Gtk::Menu_Helpers::MenuElem(
462 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
466 if (!device_modes.empty()) {
467 custom_device_mode_changed(device_modes.front());
470 if (device_modes.size() > 1) {
471 _midnam_custom_device_mode_selector.show();
473 _midnam_custom_device_mode_selector.hide();
476 // now this is a real bad hack
477 if (device_modes.size() > 0) {
478 _route->instrument_info().set_external_instrument (model, device_modes.front());
480 _route->instrument_info().set_external_instrument (model, "");
483 // Rebuild controller menu
484 _controller_menu_map.clear ();
485 delete controller_menu;
487 build_automation_action_menu(false);
491 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
493 const std::string model = gui_property (X_("midnam-model-name"));
495 set_gui_property (X_("midnam-custom-device-mode"), mode);
496 _midnam_custom_device_mode_selector.set_text(mode);
497 _route->instrument_info().set_external_instrument (model, mode);
501 MidiTimeAxisView::midi_view()
503 return dynamic_cast<MidiStreamView*>(_view);
507 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
509 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
510 _midi_controls_box.show ();
512 _midi_controls_box.hide();
515 if (h >= KEYBOARD_MIN_HEIGHT) {
516 if (is_track() && _range_scroomer) {
517 _range_scroomer->show();
519 if (is_track() && _piano_roll_header) {
520 _piano_roll_header->show();
523 if (is_track() && _range_scroomer) {
524 _range_scroomer->hide();
526 if (is_track() && _piano_roll_header) {
527 _piano_roll_header->hide();
531 /* We need to do this after changing visibility of our stuff, as it will
532 eventually trigger a call to Editor::reset_controls_layout_width(),
533 which needs to know if we have just shown or hidden a scroomer /
536 RouteTimeAxisView::set_height (h, m);
540 MidiTimeAxisView::append_extra_display_menu_items ()
542 using namespace Menu_Helpers;
544 MenuList& items = display_menu->items();
547 Menu *range_menu = manage(new Menu);
548 MenuList& range_items = range_menu->items();
549 range_menu->set_name ("ArdourContextMenu");
551 range_items.push_back (
552 MenuElem (_("Show Full Range"),
553 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
554 MidiStreamView::FullRange, true)));
556 range_items.push_back (
557 MenuElem (_("Fit Contents"),
558 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
559 MidiStreamView::ContentsRange, true)));
561 items.push_back (MenuElem (_("Note Range"), *range_menu));
562 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
563 items.push_back (MenuElem (_("Channel Selector"),
564 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
566 items.push_back (MenuElem (_("Select Patch..."),
567 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
569 color_mode_menu = build_color_mode_menu();
570 if (color_mode_menu) {
571 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
574 items.push_back (SeparatorElem ());
578 MidiTimeAxisView::toggle_channel_selector ()
580 if (!_channel_selector) {
581 _channel_selector = new MidiChannelSelectorWindow (midi_track());
583 if (_color_mode == ChannelColors) {
584 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
586 _channel_selector->set_default_channel_color ();
589 _channel_selector->show_all ();
591 _channel_selector->cycle_visibility ();
596 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
598 using namespace Menu_Helpers;
600 /* If we have a controller menu, we need to detach it before
601 RouteTimeAxis::build_automation_action_menu destroys the
602 menu it is attached to. Otherwise GTK destroys
603 controller_menu's gobj, meaning that it can't be reattached
604 below. See bug #3134.
607 if (controller_menu) {
608 detach_menu (*controller_menu);
611 _channel_command_menu_map.clear ();
612 RouteTimeAxisView::build_automation_action_menu (for_selection);
614 MenuList& automation_items = automation_action_menu->items();
616 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
618 if (selected_channels != 0) {
620 automation_items.push_back (SeparatorElem());
622 /* these 2 MIDI "command" types are semantically more like automation
623 than note data, but they are not MIDI controllers. We give them
624 special status in this menu, since they will not show up in the
625 controller list and anyone who actually knows something about MIDI
626 (!) would not expect to find them there.
629 add_channel_command_menu_item (
630 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
631 automation_items.back().set_sensitive (
632 !for_selection || _editor.get_selection().tracks.size() == 1);
633 add_channel_command_menu_item (
634 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
635 automation_items.back().set_sensitive (
636 !for_selection || _editor.get_selection().tracks.size() == 1);
638 /* now all MIDI controllers. Always offer the possibility that we will
639 rebuild the controllers menu since it might need to be updated after
640 a channel mode change or other change. Also detach it first in case
641 it has been used anywhere else.
644 build_controller_menu ();
646 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
648 if (!poly_pressure_menu) {
649 poly_pressure_menu = new Gtk::Menu;
652 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
654 automation_items.back().set_sensitive (
655 !for_selection || _editor.get_selection().tracks.size() == 1);
657 automation_items.push_back (
658 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
659 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
664 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
666 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
668 for (uint8_t chn = 0; chn < 16; chn++) {
669 if (selected_channels & (0x0001 << chn)) {
671 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
672 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
675 menu->set_active (yn);
682 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
684 AutomationType auto_type,
687 using namespace Menu_Helpers;
689 /* count the number of selected channels because we will build a different menu
690 structure if there is more than 1 selected.
693 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
696 for (uint8_t chn = 0; chn < 16; chn++) {
697 if (selected_channels & (0x0001 << chn)) {
706 /* multiple channels - create a submenu, with 1 item per channel */
708 Menu* chn_menu = manage (new Menu);
709 MenuList& chn_items (chn_menu->items());
710 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
712 /* add a couple of items to hide/show all of them */
714 chn_items.push_back (
715 MenuElem (_("Hide all channels"),
716 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
717 false, param_without_channel)));
718 chn_items.push_back (
719 MenuElem (_("Show all channels"),
720 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
721 true, param_without_channel)));
723 for (uint8_t chn = 0; chn < 16; chn++) {
724 if (selected_channels & (0x0001 << chn)) {
726 /* for each selected channel, add a menu item for this controller */
728 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
729 chn_items.push_back (
730 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
731 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
732 fully_qualified_param)));
734 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
735 bool visible = false;
738 if (track->marked_for_display()) {
743 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
744 _channel_command_menu_map[fully_qualified_param] = cmi;
745 cmi->set_active (visible);
749 /* now create an item in the parent menu that has the per-channel list as a submenu */
751 items.push_back (MenuElem (label, *chn_menu));
755 /* just one channel - create a single menu item for this command+channel combination*/
757 for (uint8_t chn = 0; chn < 16; chn++) {
758 if (selected_channels & (0x0001 << chn)) {
760 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
762 CheckMenuElem (label,
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*>(&items.back());
776 _channel_command_menu_map[fully_qualified_param] = cmi;
777 cmi->set_active (visible);
779 /* one channel only */
786 /** Add a single menu item for a controller on one channel. */
788 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
790 const std::string& name)
792 using namespace Menu_Helpers;
794 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
795 for (uint8_t chn = 0; chn < 16; chn++) {
796 if (selected_channels & (0x0001 << chn)) {
798 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
799 ctl_items.push_back (
801 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
803 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
804 fully_qualified_param)));
805 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
807 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
808 fully_qualified_param);
810 bool visible = false;
812 if (track->marked_for_display()) {
817 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
818 _controller_menu_map[fully_qualified_param] = cmi;
819 cmi->set_active (visible);
821 /* one channel only */
827 /** Add a submenu with 1 item per channel for a controller on many channels. */
829 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
831 const std::string& name)
833 using namespace Menu_Helpers;
835 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
837 Menu* chn_menu = manage (new Menu);
838 MenuList& chn_items (chn_menu->items());
840 /* add a couple of items to hide/show this controller on all channels */
842 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
843 chn_items.push_back (
844 MenuElem (_("Hide all channels"),
845 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
846 false, param_without_channel)));
847 chn_items.push_back (
848 MenuElem (_("Show all channels"),
849 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
850 true, param_without_channel)));
852 for (uint8_t chn = 0; chn < 16; chn++) {
853 if (selected_channels & (0x0001 << chn)) {
855 /* for each selected channel, add a menu item for this controller */
857 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
858 chn_items.push_back (
859 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
860 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
861 fully_qualified_param)));
863 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
864 fully_qualified_param);
865 bool visible = false;
868 if (track->marked_for_display()) {
873 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
874 _controller_menu_map[fully_qualified_param] = cmi;
875 cmi->set_active (visible);
879 /* add the per-channel menu to the list of controllers, with the name of the controller */
880 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
882 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
885 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
886 MidiTimeAxisView::get_device_mode()
888 using namespace MIDI::Name;
890 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
892 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
895 return device_names->custom_device_mode_by_name(
896 gui_property (X_("midnam-custom-device-mode")));
899 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
900 MidiTimeAxisView::get_device_names()
902 using namespace MIDI::Name;
904 const std::string model = gui_property (X_("midnam-model-name"));
906 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
907 .document_by_model(model);
909 return midnam->master_device_names(model);
911 return boost::shared_ptr<MasterDeviceNames>();
916 MidiTimeAxisView::build_controller_menu ()
918 using namespace Menu_Helpers;
920 if (controller_menu) {
921 /* it exists and has not been invalidated by a channel mode change */
925 controller_menu = new Menu; // explicitly managed by us
926 MenuList& items (controller_menu->items());
928 /* create several "top level" menu items for sets of controllers (16 at a
929 time), and populate each one with a submenu for each controller+channel
930 combination covering the currently selected channels for this track
933 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
935 /* count the number of selected channels because we will build a different menu
936 structure if there is more than 1 selected.
940 for (uint8_t chn = 0; chn < 16; chn++) {
941 if (selected_channels & (0x0001 << chn)) {
948 using namespace MIDI::Name;
949 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
951 if (device_names && !device_names->controls().empty()) {
952 /* Controllers names available in midnam file, generate fancy menu */
953 unsigned n_items = 0;
954 unsigned n_groups = 0;
956 /* TODO: This is not correct, should look up the currently applicable ControlNameList
957 and only build a menu for that one. */
958 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
959 l != device_names->controls().end(); ++l) {
960 boost::shared_ptr<ControlNameList> name_list = l->second;
961 Menu* ctl_menu = NULL;
963 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
964 c != name_list->controls().end();) {
965 const uint16_t ctl = c->second->number();
966 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
967 /* Skip bank select controllers since they're handled specially */
969 /* Create a new submenu */
970 ctl_menu = manage (new Menu);
973 MenuList& ctl_items (ctl_menu->items());
975 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
977 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
982 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
983 /* Submenu has 16 items or we're done, add it to controller menu and reset */
985 MenuElem(string_compose(_("Controllers %1-%2"),
986 (16 * n_groups), (16 * n_groups) + n_items - 1),
995 /* No controllers names, generate generic numeric menu */
996 for (int i = 0; i < 127; i += 16) {
997 Menu* ctl_menu = manage (new Menu);
998 MenuList& ctl_items (ctl_menu->items());
1000 for (int ctl = i; ctl < i+16; ++ctl) {
1001 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1002 /* Skip bank select controllers since they're handled specially */
1007 add_multi_channel_controller_item(
1008 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1010 add_single_channel_controller_item(
1011 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1015 /* Add submenu for this block of controllers to controller menu */
1017 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1024 MidiTimeAxisView::build_note_mode_menu()
1026 using namespace Menu_Helpers;
1028 Menu* mode_menu = manage (new Menu);
1029 MenuList& items = mode_menu->items();
1030 mode_menu->set_name ("ArdourContextMenu");
1032 RadioMenuItem::Group mode_group;
1034 RadioMenuElem (mode_group,_("Sustained"),
1035 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1037 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1038 _note_mode_item->set_active(_note_mode == Sustained);
1041 RadioMenuElem (mode_group, _("Percussive"),
1042 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1043 Percussive, true)));
1044 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1045 _percussion_mode_item->set_active(_note_mode == Percussive);
1051 MidiTimeAxisView::build_color_mode_menu()
1053 using namespace Menu_Helpers;
1055 Menu* mode_menu = manage (new Menu);
1056 MenuList& items = mode_menu->items();
1057 mode_menu->set_name ("ArdourContextMenu");
1059 RadioMenuItem::Group mode_group;
1061 RadioMenuElem (mode_group, _("Meter Colors"),
1062 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1063 MeterColors, false, true, true)));
1064 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1065 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1068 RadioMenuElem (mode_group, _("Channel Colors"),
1069 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1070 ChannelColors, false, true, true)));
1071 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1072 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1075 RadioMenuElem (mode_group, _("Track Color"),
1076 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1077 TrackColor, false, true, true)));
1078 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1079 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1085 MidiTimeAxisView::immediate_patch_chnage_response (int response)
1087 if (response != RESPONSE_ACCEPT || !_route) {
1088 delete _patch_change_dialog;
1089 _patch_change_dialog = 0;
1092 Evoral::PatchChange<Evoral::Beats> p (_patch_change_dialog->patch ());
1094 uint8_t chn = p.channel();
1096 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1097 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1098 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1100 if (!bank_msb || ! bank_lsb || !program) {
1101 _patch_change_dialog->show ();
1105 bank_msb->set_value (p.bank_msb (), Controllable::NoGroup);
1106 bank_lsb->set_value (p.bank_lsb (), Controllable::NoGroup);
1107 program->set_value (p.program () , Controllable::NoGroup);
1108 _patch_change_dialog->show ();
1112 MidiTimeAxisView::send_patch_change ()
1117 if (_patch_change_dialog) {
1118 _patch_change_dialog->present ();
1122 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
1123 PatchChangeDialog* d = new PatchChangeDialog (0, 0, empty, _route->instrument_info(), Gtk::Stock::APPLY, false, false);
1124 d->signal_response().connect (sigc::mem_fun (*this, &MidiTimeAxisView::immediate_patch_chnage_response));
1125 _patch_change_dialog = d;
1126 _patch_change_dialog->present ();
1130 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1132 if (apply_to_selection) {
1133 _editor.get_selection().tracks.foreach_midi_time_axis (
1134 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1136 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1138 midi_track()->set_note_mode(mode);
1139 set_gui_property ("note-mode", enum_2_string(_note_mode));
1140 _view->redisplay_track();
1146 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1148 if (apply_to_selection) {
1149 _editor.get_selection().tracks.foreach_midi_time_axis (
1150 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1152 if (_color_mode == mode && !force) {
1156 if (_channel_selector) {
1157 if (mode == ChannelColors) {
1158 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1160 _channel_selector->set_default_channel_color();
1165 set_gui_property ("color-mode", enum_2_string(_color_mode));
1167 _view->redisplay_track();
1173 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1175 if (apply_to_selection) {
1176 _editor.get_selection().tracks.foreach_midi_time_axis (
1177 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1179 if (!_ignore_signals) {
1180 midi_view()->set_note_range(range);
1186 MidiTimeAxisView::update_range()
1191 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1193 using namespace MIDI::Name;
1195 if (apply_to_selection) {
1196 _editor.get_selection().tracks.foreach_midi_time_axis (
1197 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1200 // Show existing automation
1201 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1203 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1204 create_automation_child(*i, true);
1207 // Show automation for all controllers named in midnam file
1208 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1209 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1210 device_names && !device_names->controls().empty()) {
1211 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1212 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1213 for (uint32_t chn = 0; chn < 16; ++chn) {
1214 if ((selected_channels & (0x0001 << chn)) == 0) {
1215 // Channel not in use
1219 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1225 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1226 chan_names->control_list_name());
1227 if (!control_names) {
1231 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1232 c != control_names->controls().end();
1234 const uint16_t ctl = c->second->number();
1235 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1236 /* Skip bank select controllers since they're handled specially */
1237 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1238 create_automation_child(param, true);
1245 RouteTimeAxisView::show_all_automation ();
1250 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1252 if (apply_to_selection) {
1253 _editor.get_selection().tracks.foreach_midi_time_axis (
1254 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1257 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1259 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1260 create_automation_child (*i, true);
1264 RouteTimeAxisView::show_existing_automation ();
1268 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1271 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1273 if (param.type() == NullAutomation) {
1277 AutomationTracks::iterator existing = _automation_tracks.find (param);
1279 if (existing != _automation_tracks.end()) {
1281 /* automation track created because we had existing data for
1282 * the processor, but visibility may need to be controlled
1283 * since it will have been set visible by default.
1286 existing->second->set_marked_for_display (show);
1295 boost::shared_ptr<AutomationTimeAxisView> track;
1296 boost::shared_ptr<AutomationControl> control;
1299 switch (param.type()) {
1301 case GainAutomation:
1302 create_gain_automation_child (param, show);
1305 case MuteAutomation:
1306 create_mute_automation_child (param, show);
1309 case PluginAutomation:
1310 /* handled elsewhere */
1313 case MidiCCAutomation:
1314 case MidiPgmChangeAutomation:
1315 case MidiPitchBenderAutomation:
1316 case MidiChannelPressureAutomation:
1317 case MidiSystemExclusiveAutomation:
1318 /* These controllers are region "automation" - they are owned
1319 * by regions (and their MidiModels), not by the track. As a
1320 * result there is no AutomationList/Line for the track, but we create
1321 * a controller for the user to write immediate events, so the editor
1322 * can act as a control surface for the present MIDI controllers.
1324 * TODO: Record manipulation of the controller to regions?
1327 control = _route->automation_control(param, true);
1328 track.reset (new AutomationTimeAxisView (
1331 control ? _route : boost::shared_ptr<Automatable> (),
1338 _route->describe_parameter(param)));
1341 _view->foreach_regionview (
1342 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1345 add_automation_child (param, track, show);
1347 reshow_selection (_editor.get_selection().time);
1352 case PanWidthAutomation:
1353 case PanElevationAutomation:
1354 case PanAzimuthAutomation:
1355 ensure_pan_views (show);
1359 error << "MidiTimeAxisView: unknown automation child "
1360 << EventTypeMap::instance().to_symbol(param) << endmsg;
1365 MidiTimeAxisView::route_active_changed ()
1367 RouteUI::route_active_changed ();
1368 update_control_names();
1372 MidiTimeAxisView::update_control_names ()
1375 if (_route->active()) {
1376 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1377 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1379 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1380 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1382 } else { // MIDI bus (which doesn't exist yet..)
1383 if (_route->active()) {
1384 controls_base_selected_name = "BusControlsBaseSelected";
1385 controls_base_unselected_name = "BusControlsBaseUnselected";
1387 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1388 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1393 controls_ebox.set_name (controls_base_selected_name);
1394 time_axis_frame.set_name (controls_base_selected_name);
1396 controls_ebox.set_name (controls_base_unselected_name);
1397 time_axis_frame.set_name (controls_base_unselected_name);
1402 MidiTimeAxisView::set_note_selection (uint8_t note)
1404 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1406 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1408 if (_view->num_selected_regionviews() == 0) {
1409 _view->foreach_regionview (
1410 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1413 _view->foreach_selected_regionview (
1414 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1418 _editor.commit_reversible_selection_op();
1422 MidiTimeAxisView::add_note_selection (uint8_t note)
1424 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1426 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1428 if (_view->num_selected_regionviews() == 0) {
1429 _view->foreach_regionview (
1430 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1433 _view->foreach_selected_regionview (
1434 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1438 _editor.commit_reversible_selection_op();
1442 MidiTimeAxisView::extend_note_selection (uint8_t note)
1444 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1446 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1448 if (_view->num_selected_regionviews() == 0) {
1449 _view->foreach_regionview (
1450 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1453 _view->foreach_selected_regionview (
1454 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1458 _editor.commit_reversible_selection_op();
1462 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1464 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1466 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1468 if (_view->num_selected_regionviews() == 0) {
1469 _view->foreach_regionview (
1470 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1473 _view->foreach_selected_regionview (
1474 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1478 _editor.commit_reversible_selection_op();
1482 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1484 _view->foreach_regionview (
1485 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1489 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1491 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1495 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1497 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1501 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1503 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1507 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1509 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1513 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1515 Evoral::Sequence<Evoral::Beats>::Notes selected;
1516 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1518 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1520 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1521 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1522 notes.insert (*sel_it);
1525 if (!notes.empty()) {
1526 selection.push_back (make_pair ((rv)->region()->id(), notes));
1531 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1533 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1537 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1538 bool changed = false;
1542 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1544 for (uint32_t chn = 0; chn < 16; ++chn) {
1545 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1546 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1552 if ((selected_channels & (0x0001 << chn)) == 0) {
1553 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1554 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1556 changed = track->set_marked_for_display (false) || changed;
1558 changed = track->set_marked_for_display (true) || changed;
1565 /* TODO: Bender, Pressure */
1567 /* invalidate the controller menu, so that we rebuild it next time */
1568 _controller_menu_map.clear ();
1569 delete controller_menu;
1570 controller_menu = 0;
1578 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1580 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1585 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1586 if (i != _controller_menu_map.end()) {
1590 i = _channel_command_menu_map.find (param);
1591 if (i != _channel_command_menu_map.end()) {
1598 boost::shared_ptr<MidiRegion>
1599 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1601 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1602 MusicFrame pos (f, 0);
1605 real_editor->begin_reversible_command (Operations::create_region);
1607 playlist()->clear_changes ();
1609 real_editor->snap_to (pos, RoundNearest);
1611 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1614 plist.add (ARDOUR::Properties::start, 0);
1615 plist.add (ARDOUR::Properties::length, length);
1616 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1618 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1619 /* sets beat position */
1620 region->set_position (pos.frame, pos.division);
1621 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1622 _session->add_command (new StatefulDiffCommand (playlist()));
1625 real_editor->commit_reversible_command ();
1628 return boost::dynamic_pointer_cast<MidiRegion>(region);
1632 MidiTimeAxisView::ensure_step_editor ()
1634 if (!_step_editor) {
1635 _step_editor = new StepEditor (_editor, midi_track(), *this);
1640 MidiTimeAxisView::start_step_editing ()
1642 ensure_step_editor ();
1643 _step_editor->start_step_editing ();
1647 MidiTimeAxisView::stop_step_editing ()
1650 _step_editor->stop_step_editing ();
1654 /** @return channel (counted from 0) to add an event to, based on the current setting
1655 * of the channel selector.
1658 MidiTimeAxisView::get_channel_for_add () const
1660 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1662 uint8_t channel = 0;
1664 /* pick the highest selected channel, unless all channels are selected,
1665 which is interpreted to mean channel 1 (zero)
1668 for (uint16_t i = 0; i < 16; ++i) {
1669 if (chn_mask & (1<<i)) {
1675 if (chn_cnt == 16) {
1683 MidiTimeAxisView::note_range_changed ()
1685 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1686 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1690 MidiTimeAxisView::contents_height_changed ()
1692 _range_scroomer->queue_resize ();
1696 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1698 if (!_editor.internal_editing()) {
1699 // Non-internal paste, paste regions like any other route
1700 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1703 return midi_view()->paste(pos, selection, ctx, sub_num);