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 items.push_back (MenuElem (_("Select Patch"), *build_patch_menu()));
603 color_mode_menu = build_color_mode_menu();
604 if (color_mode_menu) {
605 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
608 items.push_back (SeparatorElem ());
612 MidiTimeAxisView::toggle_channel_selector ()
614 if (!_channel_selector) {
615 _channel_selector = new MidiChannelSelectorWindow (midi_track());
617 if (_color_mode == ChannelColors) {
618 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
620 _channel_selector->set_default_channel_color ();
623 _channel_selector->show_all ();
625 _channel_selector->cycle_visibility ();
630 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
632 using namespace Menu_Helpers;
634 /* If we have a controller menu, we need to detach it before
635 RouteTimeAxis::build_automation_action_menu destroys the
636 menu it is attached to. Otherwise GTK destroys
637 controller_menu's gobj, meaning that it can't be reattached
638 below. See bug #3134.
641 if (controller_menu) {
642 detach_menu (*controller_menu);
645 _channel_command_menu_map.clear ();
646 RouteTimeAxisView::build_automation_action_menu (for_selection);
648 MenuList& automation_items = automation_action_menu->items();
650 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
652 if (selected_channels != 0) {
654 automation_items.push_back (SeparatorElem());
656 /* these 2 MIDI "command" types are semantically more like automation
657 than note data, but they are not MIDI controllers. We give them
658 special status in this menu, since they will not show up in the
659 controller list and anyone who actually knows something about MIDI
660 (!) would not expect to find them there.
663 add_channel_command_menu_item (
664 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
665 automation_items.back().set_sensitive (
666 !for_selection || _editor.get_selection().tracks.size() == 1);
667 add_channel_command_menu_item (
668 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
669 automation_items.back().set_sensitive (
670 !for_selection || _editor.get_selection().tracks.size() == 1);
672 /* now all MIDI controllers. Always offer the possibility that we will
673 rebuild the controllers menu since it might need to be updated after
674 a channel mode change or other change. Also detach it first in case
675 it has been used anywhere else.
678 build_controller_menu ();
680 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
682 if (!poly_pressure_menu) {
683 poly_pressure_menu = new Gtk::Menu;
686 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
688 automation_items.back().set_sensitive (
689 !for_selection || _editor.get_selection().tracks.size() == 1);
691 automation_items.push_back (
692 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
693 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
698 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
700 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
702 for (uint8_t chn = 0; chn < 16; chn++) {
703 if (selected_channels & (0x0001 << chn)) {
705 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
706 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
709 menu->set_active (yn);
716 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
718 AutomationType auto_type,
721 using namespace Menu_Helpers;
723 /* count the number of selected channels because we will build a different menu
724 structure if there is more than 1 selected.
727 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
730 for (uint8_t chn = 0; chn < 16; chn++) {
731 if (selected_channels & (0x0001 << chn)) {
740 /* multiple channels - create a submenu, with 1 item per channel */
742 Menu* chn_menu = manage (new Menu);
743 MenuList& chn_items (chn_menu->items());
744 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
746 /* add a couple of items to hide/show all of them */
748 chn_items.push_back (
749 MenuElem (_("Hide all channels"),
750 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
751 false, param_without_channel)));
752 chn_items.push_back (
753 MenuElem (_("Show all channels"),
754 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
755 true, param_without_channel)));
757 for (uint8_t chn = 0; chn < 16; chn++) {
758 if (selected_channels & (0x0001 << chn)) {
760 /* for each selected channel, add a menu item for this controller */
762 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
763 chn_items.push_back (
764 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
765 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
766 fully_qualified_param)));
768 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
769 bool visible = false;
772 if (track->marked_for_display()) {
777 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
778 _channel_command_menu_map[fully_qualified_param] = cmi;
779 cmi->set_active (visible);
783 /* now create an item in the parent menu that has the per-channel list as a submenu */
785 items.push_back (MenuElem (label, *chn_menu));
789 /* just one channel - create a single menu item for this command+channel combination*/
791 for (uint8_t chn = 0; chn < 16; chn++) {
792 if (selected_channels & (0x0001 << chn)) {
794 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
796 CheckMenuElem (label,
797 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
798 fully_qualified_param)));
800 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
801 bool visible = false;
804 if (track->marked_for_display()) {
809 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
810 _channel_command_menu_map[fully_qualified_param] = cmi;
811 cmi->set_active (visible);
813 /* one channel only */
820 /** Add a single menu item for a controller on one channel. */
822 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
824 const std::string& name)
826 using namespace Menu_Helpers;
828 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
829 for (uint8_t chn = 0; chn < 16; chn++) {
830 if (selected_channels & (0x0001 << chn)) {
832 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
833 ctl_items.push_back (
835 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
837 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
838 fully_qualified_param)));
839 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
841 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
842 fully_qualified_param);
844 bool visible = false;
846 if (track->marked_for_display()) {
851 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
852 _controller_menu_map[fully_qualified_param] = cmi;
853 cmi->set_active (visible);
855 /* one channel only */
861 /** Add a submenu with 1 item per channel for a controller on many channels. */
863 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
865 const std::string& name)
867 using namespace Menu_Helpers;
869 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
871 Menu* chn_menu = manage (new Menu);
872 MenuList& chn_items (chn_menu->items());
874 /* add a couple of items to hide/show this controller on all channels */
876 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
877 chn_items.push_back (
878 MenuElem (_("Hide all channels"),
879 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
880 false, param_without_channel)));
881 chn_items.push_back (
882 MenuElem (_("Show all channels"),
883 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
884 true, param_without_channel)));
886 for (uint8_t chn = 0; chn < 16; chn++) {
887 if (selected_channels & (0x0001 << chn)) {
889 /* for each selected channel, add a menu item for this controller */
891 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
892 chn_items.push_back (
893 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
894 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
895 fully_qualified_param)));
897 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
898 fully_qualified_param);
899 bool visible = false;
902 if (track->marked_for_display()) {
907 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
908 _controller_menu_map[fully_qualified_param] = cmi;
909 cmi->set_active (visible);
913 /* add the per-channel menu to the list of controllers, with the name of the controller */
914 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
916 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
919 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
920 MidiTimeAxisView::get_device_mode()
922 using namespace MIDI::Name;
924 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
926 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
929 return device_names->custom_device_mode_by_name(
930 gui_property (X_("midnam-custom-device-mode")));
933 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
934 MidiTimeAxisView::get_device_names()
936 using namespace MIDI::Name;
938 const std::string model = gui_property (X_("midnam-model-name"));
940 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
941 .document_by_model(model);
943 return midnam->master_device_names(model);
945 return boost::shared_ptr<MasterDeviceNames>();
950 MidiTimeAxisView::build_controller_menu ()
952 using namespace Menu_Helpers;
954 if (controller_menu) {
955 /* it exists and has not been invalidated by a channel mode change */
959 controller_menu = new Menu; // explicitly managed by us
960 MenuList& items (controller_menu->items());
962 /* create several "top level" menu items for sets of controllers (16 at a
963 time), and populate each one with a submenu for each controller+channel
964 combination covering the currently selected channels for this track
967 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
969 /* count the number of selected channels because we will build a different menu
970 structure if there is more than 1 selected.
974 for (uint8_t chn = 0; chn < 16; chn++) {
975 if (selected_channels & (0x0001 << chn)) {
982 using namespace MIDI::Name;
983 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
985 if (device_names && !device_names->controls().empty()) {
986 /* Controllers names available in midnam file, generate fancy menu */
987 unsigned n_items = 0;
988 unsigned n_groups = 0;
990 /* TODO: This is not correct, should look up the currently applicable ControlNameList
991 and only build a menu for that one. */
992 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
993 l != device_names->controls().end(); ++l) {
994 boost::shared_ptr<ControlNameList> name_list = l->second;
995 Menu* ctl_menu = NULL;
997 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
998 c != name_list->controls().end();) {
999 const uint16_t ctl = c->second->number();
1000 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1001 /* Skip bank select controllers since they're handled specially */
1003 /* Create a new submenu */
1004 ctl_menu = manage (new Menu);
1007 MenuList& ctl_items (ctl_menu->items());
1009 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
1011 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
1016 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
1017 /* Submenu has 16 items or we're done, add it to controller menu and reset */
1019 MenuElem(string_compose(_("Controllers %1-%2"),
1020 (16 * n_groups), (16 * n_groups) + n_items - 1),
1029 /* No controllers names, generate generic numeric menu */
1030 for (int i = 0; i < 127; i += 16) {
1031 Menu* ctl_menu = manage (new Menu);
1032 MenuList& ctl_items (ctl_menu->items());
1034 for (int ctl = i; ctl < i+16; ++ctl) {
1035 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1036 /* Skip bank select controllers since they're handled specially */
1041 add_multi_channel_controller_item(
1042 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1044 add_single_channel_controller_item(
1045 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1049 /* Add submenu for this block of controllers to controller menu */
1051 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1058 MidiTimeAxisView::build_note_mode_menu()
1060 using namespace Menu_Helpers;
1062 Menu* mode_menu = manage (new Menu);
1063 MenuList& items = mode_menu->items();
1064 mode_menu->set_name ("ArdourContextMenu");
1066 RadioMenuItem::Group mode_group;
1068 RadioMenuElem (mode_group,_("Sustained"),
1069 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1071 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1072 _note_mode_item->set_active(_note_mode == Sustained);
1075 RadioMenuElem (mode_group, _("Percussive"),
1076 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1077 Percussive, true)));
1078 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1079 _percussion_mode_item->set_active(_note_mode == Percussive);
1085 MidiTimeAxisView::build_color_mode_menu()
1087 using namespace Menu_Helpers;
1089 Menu* mode_menu = manage (new Menu);
1090 MenuList& items = mode_menu->items();
1091 mode_menu->set_name ("ArdourContextMenu");
1093 RadioMenuItem::Group mode_group;
1095 RadioMenuElem (mode_group, _("Meter Colors"),
1096 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1097 MeterColors, false, true, true)));
1098 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1099 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1102 RadioMenuElem (mode_group, _("Channel Colors"),
1103 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1104 ChannelColors, false, true, true)));
1105 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1106 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1109 RadioMenuElem (mode_group, _("Track Color"),
1110 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1111 TrackColor, false, true, true)));
1112 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1113 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1119 MidiTimeAxisView::build_patch_menu()
1121 using namespace MIDI::Name;
1122 using namespace Menu_Helpers;
1124 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1125 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1127 Menu* pc_menu = manage (new Menu);
1128 MenuList& pc_items = pc_menu->items();
1130 for (uint32_t chn = 0; chn < 16; ++chn) {
1131 boost::shared_ptr<ChannelNameSet> channel_name_set = device_names->channel_name_set_by_channel (device_mode, chn);
1132 // see also PatchChange::initialize_popup_menus
1133 if (!channel_name_set) {
1136 Gtk::Menu& chan_menu = *manage(new Gtk::Menu());
1138 const ChannelNameSet::PatchBanks& patch_banks = channel_name_set->patch_banks();
1139 if (patch_banks.size() > 1) {
1141 for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin();
1142 bank != patch_banks.end();
1144 Glib::RefPtr<Glib::Regex> underscores = Glib::Regex::create("_");
1145 std::string replacement(" ");
1147 Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu());
1149 const PatchNameList& patches = (*bank)->patch_name_list();
1150 Gtk::Menu::MenuList& patch_menus = patch_bank_menu.items();
1152 for (PatchNameList::const_iterator patch = patches.begin();
1153 patch != patches.end();
1155 std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement);
1157 patch_menus.push_back(
1158 Gtk::Menu_Helpers::MenuElem(
1161 sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1162 chn, (*patch)->patch_primary_key())) );
1166 std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement);
1168 chan_menu.items().push_back(
1169 Gtk::Menu_Helpers::MenuElem(
1174 /* only one patch bank, so make it the initial menu */
1176 const PatchNameList& patches = patch_banks.front()->patch_name_list();
1178 for (PatchNameList::const_iterator patch = patches.begin();
1179 patch != patches.end();
1181 std::string name = (*patch)->name();
1182 boost::replace_all (name, "_", " ");
1184 chan_menu.items().push_back (
1185 Gtk::Menu_Helpers::MenuElem (
1187 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1188 chn, (*patch)->patch_primary_key())));
1193 Gtk::Menu_Helpers::MenuElem(
1194 string_compose (_("Channel %1"), chn + 1),
1201 MidiTimeAxisView::on_patch_menu_selected (int chn, const MIDI::Name::PatchPrimaryKey& key)
1206 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1207 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1208 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1210 if (!bank_msb || ! bank_lsb || !program) {
1213 bank_msb->set_value ((key.bank() >> 7) & 0x7f, Controllable::NoGroup);
1214 bank_lsb->set_value (key.bank() & 0x7f, Controllable::NoGroup);
1215 program->set_value (key.program(), Controllable::NoGroup);
1219 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1221 if (apply_to_selection) {
1222 _editor.get_selection().tracks.foreach_midi_time_axis (
1223 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1225 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1227 midi_track()->set_note_mode(mode);
1228 set_gui_property ("note-mode", enum_2_string(_note_mode));
1229 _view->redisplay_track();
1235 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1237 if (apply_to_selection) {
1238 _editor.get_selection().tracks.foreach_midi_time_axis (
1239 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1241 if (_color_mode == mode && !force) {
1245 if (_channel_selector) {
1246 if (mode == ChannelColors) {
1247 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1249 _channel_selector->set_default_channel_color();
1254 set_gui_property ("color-mode", enum_2_string(_color_mode));
1256 _view->redisplay_track();
1262 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1264 if (apply_to_selection) {
1265 _editor.get_selection().tracks.foreach_midi_time_axis (
1266 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1268 if (!_ignore_signals) {
1269 midi_view()->set_note_range(range);
1275 MidiTimeAxisView::update_range()
1277 MidiGhostRegion* mgr;
1279 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1280 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1281 mgr->update_range();
1287 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1289 using namespace MIDI::Name;
1291 if (apply_to_selection) {
1292 _editor.get_selection().tracks.foreach_midi_time_axis (
1293 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1296 // Show existing automation
1297 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1299 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1300 create_automation_child(*i, true);
1303 // Show automation for all controllers named in midnam file
1304 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1305 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1306 device_names && !device_names->controls().empty()) {
1307 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1308 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1309 for (uint32_t chn = 0; chn < 16; ++chn) {
1310 if ((selected_channels & (0x0001 << chn)) == 0) {
1311 // Channel not in use
1315 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1321 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1322 chan_names->control_list_name());
1323 if (!control_names) {
1327 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1328 c != control_names->controls().end();
1330 const uint16_t ctl = c->second->number();
1331 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1332 /* Skip bank select controllers since they're handled specially */
1333 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1334 create_automation_child(param, true);
1341 RouteTimeAxisView::show_all_automation ();
1346 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1348 if (apply_to_selection) {
1349 _editor.get_selection().tracks.foreach_midi_time_axis (
1350 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1353 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1355 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1356 create_automation_child (*i, true);
1360 RouteTimeAxisView::show_existing_automation ();
1364 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1367 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1369 if (param.type() == NullAutomation) {
1373 AutomationTracks::iterator existing = _automation_tracks.find (param);
1375 if (existing != _automation_tracks.end()) {
1377 /* automation track created because we had existing data for
1378 * the processor, but visibility may need to be controlled
1379 * since it will have been set visible by default.
1382 existing->second->set_marked_for_display (show);
1391 boost::shared_ptr<AutomationTimeAxisView> track;
1392 boost::shared_ptr<AutomationControl> control;
1395 switch (param.type()) {
1397 case GainAutomation:
1398 create_gain_automation_child (param, show);
1401 case MuteAutomation:
1402 create_mute_automation_child (param, show);
1405 case PluginAutomation:
1406 /* handled elsewhere */
1409 case MidiCCAutomation:
1410 case MidiPgmChangeAutomation:
1411 case MidiPitchBenderAutomation:
1412 case MidiChannelPressureAutomation:
1413 case MidiSystemExclusiveAutomation:
1414 /* These controllers are region "automation" - they are owned
1415 * by regions (and their MidiModels), not by the track. As a
1416 * result there is no AutomationList/Line for the track, but we create
1417 * a controller for the user to write immediate events, so the editor
1418 * can act as a control surface for the present MIDI controllers.
1420 * TODO: Record manipulation of the controller to regions?
1423 control = _route->automation_control(param, true);
1424 track.reset (new AutomationTimeAxisView (
1427 control ? _route : boost::shared_ptr<Automatable> (),
1434 _route->describe_parameter(param)));
1437 _view->foreach_regionview (
1438 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1441 add_automation_child (param, track, show);
1444 case PanWidthAutomation:
1445 case PanElevationAutomation:
1446 case PanAzimuthAutomation:
1447 ensure_pan_views (show);
1451 error << "MidiTimeAxisView: unknown automation child "
1452 << EventTypeMap::instance().to_symbol(param) << endmsg;
1457 MidiTimeAxisView::route_active_changed ()
1459 RouteUI::route_active_changed ();
1460 update_control_names();
1464 MidiTimeAxisView::update_control_names ()
1467 if (_route->active()) {
1468 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1469 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1471 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1472 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1474 } else { // MIDI bus (which doesn't exist yet..)
1475 if (_route->active()) {
1476 controls_base_selected_name = "BusControlsBaseSelected";
1477 controls_base_unselected_name = "BusControlsBaseUnselected";
1479 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1480 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1485 controls_ebox.set_name (controls_base_selected_name);
1486 time_axis_frame.set_name (controls_base_selected_name);
1488 controls_ebox.set_name (controls_base_unselected_name);
1489 time_axis_frame.set_name (controls_base_unselected_name);
1494 MidiTimeAxisView::set_note_selection (uint8_t note)
1496 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1498 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1500 if (_view->num_selected_regionviews() == 0) {
1501 _view->foreach_regionview (
1502 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1505 _view->foreach_selected_regionview (
1506 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1510 _editor.commit_reversible_selection_op();
1514 MidiTimeAxisView::add_note_selection (uint8_t note)
1516 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1518 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1520 if (_view->num_selected_regionviews() == 0) {
1521 _view->foreach_regionview (
1522 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1525 _view->foreach_selected_regionview (
1526 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1530 _editor.commit_reversible_selection_op();
1534 MidiTimeAxisView::extend_note_selection (uint8_t note)
1536 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1538 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1540 if (_view->num_selected_regionviews() == 0) {
1541 _view->foreach_regionview (
1542 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1545 _view->foreach_selected_regionview (
1546 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1550 _editor.commit_reversible_selection_op();
1554 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1556 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1558 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1560 if (_view->num_selected_regionviews() == 0) {
1561 _view->foreach_regionview (
1562 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1565 _view->foreach_selected_regionview (
1566 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1570 _editor.commit_reversible_selection_op();
1574 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1576 _view->foreach_regionview (
1577 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1581 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1583 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1587 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1589 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1593 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1595 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1599 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1601 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1605 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1607 Evoral::Sequence<Evoral::Beats>::Notes selected;
1608 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1610 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1612 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1613 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1614 notes.insert (*sel_it);
1617 if (!notes.empty()) {
1618 selection.push_back (make_pair ((rv)->region()->id(), notes));
1623 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1625 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1629 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1630 bool changed = false;
1634 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1636 for (uint32_t chn = 0; chn < 16; ++chn) {
1637 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1638 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1644 if ((selected_channels & (0x0001 << chn)) == 0) {
1645 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1646 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1648 changed = track->set_marked_for_display (false) || changed;
1650 changed = track->set_marked_for_display (true) || changed;
1657 /* TODO: Bender, Pressure */
1659 /* invalidate the controller menu, so that we rebuild it next time */
1660 _controller_menu_map.clear ();
1661 delete controller_menu;
1662 controller_menu = 0;
1670 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1672 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1677 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1678 if (i != _controller_menu_map.end()) {
1682 i = _channel_command_menu_map.find (param);
1683 if (i != _channel_command_menu_map.end()) {
1690 boost::shared_ptr<MidiRegion>
1691 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, const int32_t sub_num)
1693 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1695 real_editor->begin_reversible_command (Operations::create_region);
1697 playlist()->clear_changes ();
1699 real_editor->snap_to (pos, RoundNearest);
1701 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1704 plist.add (ARDOUR::Properties::start, 0);
1705 plist.add (ARDOUR::Properties::length, length);
1706 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1708 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1709 /* sets beat position */
1710 region->set_position (pos, sub_num);
1711 playlist()->add_region (region, pos, 1.0, false, sub_num);
1712 _session->add_command (new StatefulDiffCommand (playlist()));
1715 real_editor->commit_reversible_command ();
1718 return boost::dynamic_pointer_cast<MidiRegion>(region);
1722 MidiTimeAxisView::ensure_step_editor ()
1724 if (!_step_editor) {
1725 _step_editor = new StepEditor (_editor, midi_track(), *this);
1730 MidiTimeAxisView::start_step_editing ()
1732 ensure_step_editor ();
1733 _step_editor->start_step_editing ();
1737 MidiTimeAxisView::stop_step_editing ()
1740 _step_editor->stop_step_editing ();
1744 /** @return channel (counted from 0) to add an event to, based on the current setting
1745 * of the channel selector.
1748 MidiTimeAxisView::get_channel_for_add () const
1750 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1752 uint8_t channel = 0;
1754 /* pick the highest selected channel, unless all channels are selected,
1755 which is interpreted to mean channel 1 (zero)
1758 for (uint16_t i = 0; i < 16; ++i) {
1759 if (chn_mask & (1<<i)) {
1765 if (chn_cnt == 16) {
1773 MidiTimeAxisView::note_range_changed ()
1775 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1776 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1780 MidiTimeAxisView::contents_height_changed ()
1782 _range_scroomer->queue_resize ();
1786 MidiTimeAxisView::playback_channel_mode_changed ()
1788 /* Invalidate the controller automation menu */
1789 delete controller_menu;
1790 controller_menu = 0;
1791 /* Update the button text */
1792 switch (midi_track()->get_playback_channel_mode()) {
1794 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1796 case FilterChannels:
1797 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1800 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1806 MidiTimeAxisView::capture_channel_mode_changed ()
1808 switch (midi_track()->get_capture_channel_mode()) {
1810 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1812 case FilterChannels:
1813 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1816 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1822 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1824 if (!_editor.internal_editing()) {
1825 // Non-internal paste, paste regions like any other route
1826 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1829 return midi_view()->paste(pos, selection, ctx, sub_num);