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 const ChannelNameSet::PatchBanks& patch_banks = channel_name_set->patch_banks();
1137 if (patch_banks.size () == 0) {
1141 Gtk::Menu& chan_menu = *manage(new Gtk::Menu());
1143 if (patch_banks.size() > 1) {
1145 for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin();
1146 bank != patch_banks.end();
1148 Glib::RefPtr<Glib::Regex> underscores = Glib::Regex::create("_");
1149 std::string replacement(" ");
1151 Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu());
1153 const PatchNameList& patches = (*bank)->patch_name_list();
1154 Gtk::Menu::MenuList& patch_menus = patch_bank_menu.items();
1156 for (PatchNameList::const_iterator patch = patches.begin();
1157 patch != patches.end();
1159 std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement);
1161 patch_menus.push_back(
1162 Gtk::Menu_Helpers::MenuElem(
1165 sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1166 chn, (*patch)->patch_primary_key())) );
1170 std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement);
1172 chan_menu.items().push_back(
1173 Gtk::Menu_Helpers::MenuElem(
1178 /* only one patch bank, so make it the initial menu */
1180 const PatchNameList& patches = patch_banks.front()->patch_name_list();
1182 for (PatchNameList::const_iterator patch = patches.begin();
1183 patch != patches.end();
1185 std::string name = (*patch)->name();
1186 boost::replace_all (name, "_", " ");
1188 chan_menu.items().push_back (
1189 Gtk::Menu_Helpers::MenuElem (
1191 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1192 chn, (*patch)->patch_primary_key())));
1197 Gtk::Menu_Helpers::MenuElem(
1198 string_compose (_("Channel %1"), chn + 1),
1205 MidiTimeAxisView::on_patch_menu_selected (int chn, const MIDI::Name::PatchPrimaryKey& key)
1210 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1211 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1212 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1214 if (!bank_msb || ! bank_lsb || !program) {
1217 bank_msb->set_value ((key.bank() >> 7) & 0x7f, Controllable::NoGroup);
1218 bank_lsb->set_value (key.bank() & 0x7f, Controllable::NoGroup);
1219 program->set_value (key.program(), Controllable::NoGroup);
1223 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1225 if (apply_to_selection) {
1226 _editor.get_selection().tracks.foreach_midi_time_axis (
1227 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1229 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1231 midi_track()->set_note_mode(mode);
1232 set_gui_property ("note-mode", enum_2_string(_note_mode));
1233 _view->redisplay_track();
1239 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1241 if (apply_to_selection) {
1242 _editor.get_selection().tracks.foreach_midi_time_axis (
1243 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1245 if (_color_mode == mode && !force) {
1249 if (_channel_selector) {
1250 if (mode == ChannelColors) {
1251 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1253 _channel_selector->set_default_channel_color();
1258 set_gui_property ("color-mode", enum_2_string(_color_mode));
1260 _view->redisplay_track();
1266 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1268 if (apply_to_selection) {
1269 _editor.get_selection().tracks.foreach_midi_time_axis (
1270 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1272 if (!_ignore_signals) {
1273 midi_view()->set_note_range(range);
1279 MidiTimeAxisView::update_range()
1281 MidiGhostRegion* mgr;
1283 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1284 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1285 mgr->update_range();
1291 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1293 using namespace MIDI::Name;
1295 if (apply_to_selection) {
1296 _editor.get_selection().tracks.foreach_midi_time_axis (
1297 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1300 // Show existing automation
1301 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1303 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1304 create_automation_child(*i, true);
1307 // Show automation for all controllers named in midnam file
1308 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1309 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1310 device_names && !device_names->controls().empty()) {
1311 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1312 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1313 for (uint32_t chn = 0; chn < 16; ++chn) {
1314 if ((selected_channels & (0x0001 << chn)) == 0) {
1315 // Channel not in use
1319 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1325 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1326 chan_names->control_list_name());
1327 if (!control_names) {
1331 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1332 c != control_names->controls().end();
1334 const uint16_t ctl = c->second->number();
1335 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1336 /* Skip bank select controllers since they're handled specially */
1337 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1338 create_automation_child(param, true);
1345 RouteTimeAxisView::show_all_automation ();
1350 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1352 if (apply_to_selection) {
1353 _editor.get_selection().tracks.foreach_midi_time_axis (
1354 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1357 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1359 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1360 create_automation_child (*i, true);
1364 RouteTimeAxisView::show_existing_automation ();
1368 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1371 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1373 if (param.type() == NullAutomation) {
1377 AutomationTracks::iterator existing = _automation_tracks.find (param);
1379 if (existing != _automation_tracks.end()) {
1381 /* automation track created because we had existing data for
1382 * the processor, but visibility may need to be controlled
1383 * since it will have been set visible by default.
1386 existing->second->set_marked_for_display (show);
1395 boost::shared_ptr<AutomationTimeAxisView> track;
1396 boost::shared_ptr<AutomationControl> control;
1399 switch (param.type()) {
1401 case GainAutomation:
1402 create_gain_automation_child (param, show);
1405 case MuteAutomation:
1406 create_mute_automation_child (param, show);
1409 case PluginAutomation:
1410 /* handled elsewhere */
1413 case MidiCCAutomation:
1414 case MidiPgmChangeAutomation:
1415 case MidiPitchBenderAutomation:
1416 case MidiChannelPressureAutomation:
1417 case MidiSystemExclusiveAutomation:
1418 /* These controllers are region "automation" - they are owned
1419 * by regions (and their MidiModels), not by the track. As a
1420 * result there is no AutomationList/Line for the track, but we create
1421 * a controller for the user to write immediate events, so the editor
1422 * can act as a control surface for the present MIDI controllers.
1424 * TODO: Record manipulation of the controller to regions?
1427 control = _route->automation_control(param, true);
1428 track.reset (new AutomationTimeAxisView (
1431 control ? _route : boost::shared_ptr<Automatable> (),
1438 _route->describe_parameter(param)));
1441 _view->foreach_regionview (
1442 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1445 add_automation_child (param, track, show);
1448 case PanWidthAutomation:
1449 case PanElevationAutomation:
1450 case PanAzimuthAutomation:
1451 ensure_pan_views (show);
1455 error << "MidiTimeAxisView: unknown automation child "
1456 << EventTypeMap::instance().to_symbol(param) << endmsg;
1461 MidiTimeAxisView::route_active_changed ()
1463 RouteUI::route_active_changed ();
1464 update_control_names();
1468 MidiTimeAxisView::update_control_names ()
1471 if (_route->active()) {
1472 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1473 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1475 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1476 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1478 } else { // MIDI bus (which doesn't exist yet..)
1479 if (_route->active()) {
1480 controls_base_selected_name = "BusControlsBaseSelected";
1481 controls_base_unselected_name = "BusControlsBaseUnselected";
1483 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1484 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1489 controls_ebox.set_name (controls_base_selected_name);
1490 time_axis_frame.set_name (controls_base_selected_name);
1492 controls_ebox.set_name (controls_base_unselected_name);
1493 time_axis_frame.set_name (controls_base_unselected_name);
1498 MidiTimeAxisView::set_note_selection (uint8_t note)
1500 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1502 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1504 if (_view->num_selected_regionviews() == 0) {
1505 _view->foreach_regionview (
1506 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1509 _view->foreach_selected_regionview (
1510 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1514 _editor.commit_reversible_selection_op();
1518 MidiTimeAxisView::add_note_selection (uint8_t note)
1520 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1522 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1524 if (_view->num_selected_regionviews() == 0) {
1525 _view->foreach_regionview (
1526 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1529 _view->foreach_selected_regionview (
1530 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1534 _editor.commit_reversible_selection_op();
1538 MidiTimeAxisView::extend_note_selection (uint8_t note)
1540 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1542 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1544 if (_view->num_selected_regionviews() == 0) {
1545 _view->foreach_regionview (
1546 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1549 _view->foreach_selected_regionview (
1550 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1554 _editor.commit_reversible_selection_op();
1558 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1560 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1562 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1564 if (_view->num_selected_regionviews() == 0) {
1565 _view->foreach_regionview (
1566 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1569 _view->foreach_selected_regionview (
1570 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1574 _editor.commit_reversible_selection_op();
1578 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1580 _view->foreach_regionview (
1581 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1585 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1587 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1591 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1593 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1597 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1599 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1603 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1605 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1609 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1611 Evoral::Sequence<Evoral::Beats>::Notes selected;
1612 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1614 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1616 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1617 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1618 notes.insert (*sel_it);
1621 if (!notes.empty()) {
1622 selection.push_back (make_pair ((rv)->region()->id(), notes));
1627 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1629 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1633 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1634 bool changed = false;
1638 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1640 for (uint32_t chn = 0; chn < 16; ++chn) {
1641 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1642 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1648 if ((selected_channels & (0x0001 << chn)) == 0) {
1649 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1650 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1652 changed = track->set_marked_for_display (false) || changed;
1654 changed = track->set_marked_for_display (true) || changed;
1661 /* TODO: Bender, Pressure */
1663 /* invalidate the controller menu, so that we rebuild it next time */
1664 _controller_menu_map.clear ();
1665 delete controller_menu;
1666 controller_menu = 0;
1674 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1676 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1681 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1682 if (i != _controller_menu_map.end()) {
1686 i = _channel_command_menu_map.find (param);
1687 if (i != _channel_command_menu_map.end()) {
1694 boost::shared_ptr<MidiRegion>
1695 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, const int32_t sub_num)
1697 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1699 real_editor->begin_reversible_command (Operations::create_region);
1701 playlist()->clear_changes ();
1703 real_editor->snap_to (pos, RoundNearest);
1705 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1708 plist.add (ARDOUR::Properties::start, 0);
1709 plist.add (ARDOUR::Properties::length, length);
1710 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1712 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1713 /* sets beat position */
1714 region->set_position (pos, sub_num);
1715 playlist()->add_region (region, pos, 1.0, false, sub_num);
1716 _session->add_command (new StatefulDiffCommand (playlist()));
1719 real_editor->commit_reversible_command ();
1722 return boost::dynamic_pointer_cast<MidiRegion>(region);
1726 MidiTimeAxisView::ensure_step_editor ()
1728 if (!_step_editor) {
1729 _step_editor = new StepEditor (_editor, midi_track(), *this);
1734 MidiTimeAxisView::start_step_editing ()
1736 ensure_step_editor ();
1737 _step_editor->start_step_editing ();
1741 MidiTimeAxisView::stop_step_editing ()
1744 _step_editor->stop_step_editing ();
1748 /** @return channel (counted from 0) to add an event to, based on the current setting
1749 * of the channel selector.
1752 MidiTimeAxisView::get_channel_for_add () const
1754 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1756 uint8_t channel = 0;
1758 /* pick the highest selected channel, unless all channels are selected,
1759 which is interpreted to mean channel 1 (zero)
1762 for (uint16_t i = 0; i < 16; ++i) {
1763 if (chn_mask & (1<<i)) {
1769 if (chn_cnt == 16) {
1777 MidiTimeAxisView::note_range_changed ()
1779 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1780 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1784 MidiTimeAxisView::contents_height_changed ()
1786 _range_scroomer->queue_resize ();
1790 MidiTimeAxisView::playback_channel_mode_changed ()
1792 /* Invalidate the controller automation menu */
1793 delete controller_menu;
1794 controller_menu = 0;
1795 /* Update the button text */
1796 switch (midi_track()->get_playback_channel_mode()) {
1798 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1800 case FilterChannels:
1801 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1804 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1810 MidiTimeAxisView::capture_channel_mode_changed ()
1812 switch (midi_track()->get_capture_channel_mode()) {
1814 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1816 case FilterChannels:
1817 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1820 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1826 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1828 if (!_editor.internal_editing()) {
1829 // Non-internal paste, paste regions like any other route
1830 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1833 return midi_view()->paste(pos, selection, ctx, sub_num);