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 "patch_change_dialog.h"
78 #include "piano_roll_header.h"
79 #include "playlist_selector.h"
80 #include "plugin_selector.h"
81 #include "plugin_ui.h"
82 #include "point_selection.h"
84 #include "region_view.h"
85 #include "rgb_macros.h"
86 #include "selection.h"
87 #include "step_editor.h"
90 #include "note_base.h"
92 #include "ardour/midi_track.h"
96 using namespace ARDOUR;
97 using namespace ARDOUR_UI_UTILS;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
104 // Minimum height at which a control is displayed
105 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
106 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
108 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
109 : SessionHandlePtr (sess)
110 , RouteTimeAxisView (ed, sess, canvas)
111 , _ignore_signals(false)
113 , _piano_roll_header(0)
114 , _note_mode(Sustained)
116 , _percussion_mode_item(0)
117 , _color_mode(MeterColors)
118 , _meter_color_mode_item(0)
119 , _channel_color_mode_item(0)
120 , _track_color_mode_item(0)
121 , _channel_selector (0)
122 , _step_edit_item (0)
123 , controller_menu (0)
124 , poly_pressure_menu (0)
127 _midnam_model_selector.disable_scrolling();
128 _midnam_custom_device_mode_selector.disable_scrolling();
132 MidiTimeAxisView::set_note_highlight (uint8_t note) {
133 _piano_roll_header->set_note_highlight (note);
137 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
141 _view = new MidiStreamView (*this);
144 _piano_roll_header = new PianoRollHeader(*midi_view());
145 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
146 _range_scroomer->DoubleClicked.connect (
147 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
148 MidiStreamView::ContentsRange, false));
151 /* This next call will result in our height being set up, so it must come after
152 the creation of the piano roll / range scroomer as their visibility is set up
155 RouteTimeAxisView::set_route (rt);
157 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
159 subplugin_menu.set_name ("ArdourContextMenu");
161 if (!gui_property ("note-range-min").empty ()) {
162 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
163 atoi (gui_property ("note-range-max").c_str()),
167 _view->ContentsHeightChanged.connect (
168 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
170 ignore_toggle = false;
172 if (is_midi_track()) {
173 _note_mode = midi_track()->note_mode();
176 /* if set_state above didn't create a gain automation child, we need to make one */
177 if (automation_child (GainAutomation) == 0) {
178 create_automation_child (GainAutomation, false);
181 /* if set_state above didn't create a mute automation child, we need to make one */
182 if (automation_child (MuteAutomation) == 0) {
183 create_automation_child (MuteAutomation, false);
186 if (_route->panner_shell()) {
187 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
190 /* map current state of the route */
191 ensure_pan_views (false);
192 update_control_names();
193 processors_changed (RouteProcessorChange ());
195 _route->processors_changed.connect (*this, invalidator (*this),
196 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
200 _piano_roll_header->SetNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
202 _piano_roll_header->AddNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
204 _piano_roll_header->ExtendNoteSelection.connect (
205 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
206 _piano_roll_header->ToggleNoteSelection.connect (
207 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
209 /* Update StreamView during scroomer drags.*/
211 _range_scroomer->DragStarting.connect (
212 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
213 _range_scroomer->DragFinishing.connect (
214 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
216 /* Put the scroomer and the keyboard in a VBox with a padding
217 label so that they can be reduced in height for stacked-view
221 HSeparator* separator = manage (new HSeparator());
222 separator->set_name("TrackSeparator");
223 separator->set_size_request(-1, 1);
226 VBox* v = manage (new VBox);
227 HBox* h = manage (new HBox);
228 h->pack_end (*_piano_roll_header);
229 h->pack_end (*_range_scroomer);
230 v->pack_start (*separator, false, false);
231 v->pack_start (*h, true, true);
234 top_hbox.remove(scroomer_placeholder);
235 time_axis_hbox.pack_end(*v, false, false, 0);
236 midi_scroomer_size_group->add_widget (*v);
238 midi_view()->NoteRangeChanged.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 /* ask for notifications of any new RegionViews */
242 _view->RegionViewAdded.connect (
243 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 if (!_editor.have_idled()) {
246 /* first idle will do what we need */
252 if (gui_property (X_("midnam-model-name")).empty()) {
253 set_gui_property (X_("midnam-model-name"), "Generic");
256 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
257 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
259 set_gui_property (X_("midnam-custom-device-mode"),
260 *device_names->custom_device_mode_names().begin());
264 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
265 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
267 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
268 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
270 _midi_controls_box.set_homogeneous(false);
271 _midi_controls_box.set_border_width (2);
273 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
274 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
277 setup_midnam_patches ();
278 update_patch_selector ();
280 model_changed (gui_property(X_("midnam-model-name")));
281 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
283 controls_vbox.pack_start(_midi_controls_box, false, false);
285 const string color_mode = gui_property ("color-mode");
286 if (!color_mode.empty()) {
287 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
288 if (_channel_selector && _color_mode == ChannelColors) {
289 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
293 set_color_mode (_color_mode, true, false);
295 const string note_mode = gui_property ("note-mode");
296 if (!note_mode.empty()) {
297 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
298 if (_percussion_mode_item) {
299 _percussion_mode_item->set_active (_note_mode == Percussive);
303 /* Look for any GUI object state nodes that represent automation children
304 * that should exist, and create the children.
307 const list<string> gui_ids = gui_object_state().all_ids ();
308 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
311 Evoral::Parameter parameter (0, 0, 0);
313 bool const p = AutomationTimeAxisView::parse_state_id (
314 *i, route_id, has_parameter, parameter);
315 if (p && route_id == _route->id () && has_parameter) {
316 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
317 create_automation_child (parameter, string_to<bool> (visible));
323 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
325 RouteTimeAxisView::processors_changed (c);
326 update_patch_selector ();
330 MidiTimeAxisView::first_idle ()
337 MidiTimeAxisView::~MidiTimeAxisView ()
339 delete _channel_selector;
341 delete _piano_roll_header;
342 _piano_roll_header = 0;
344 delete _range_scroomer;
347 delete controller_menu;
352 MidiTimeAxisView::check_step_edit ()
354 ensure_step_editor ();
355 _step_editor->check_step_edit ();
359 MidiTimeAxisView::setup_midnam_patches ()
361 typedef MIDI::Name::MidiPatchManager PatchManager;
362 PatchManager& patch_manager = PatchManager::instance();
364 _midnam_model_selector.clear_items ();
365 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
366 m != patch_manager.devices_by_manufacturer().end(); ++m) {
367 Menu* menu = Gtk::manage(new Menu);
368 Menu_Helpers::MenuList& items = menu->items();
370 // Build manufacturer submenu
371 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
372 n != m->second.end(); ++n) {
373 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
375 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
378 items.push_back(elem);
381 // Add manufacturer submenu to selector
382 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
385 if (!get_device_names()) {
386 model_changed ("Generic");
391 MidiTimeAxisView::drop_instrument_ref ()
393 midnam_connection.drop_connections ();
396 MidiTimeAxisView::start_scroomer_update ()
398 _note_range_changed_connection.disconnect();
399 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
400 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
403 MidiTimeAxisView::stop_scroomer_update ()
405 _note_range_changed_connection.disconnect();
409 MidiTimeAxisView::update_patch_selector ()
411 typedef MIDI::Name::MidiPatchManager PatchManager;
412 PatchManager& patch_manager = PatchManager::instance();
414 bool pluginprovided = false;
416 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
417 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
418 if (pi && pi->plugin ()->has_midnam ()) {
419 midnam_connection.drop_connections ();
420 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
421 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
423 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
424 boost::bind (&Plugin::read_midnam, pi->plugin ()),
427 pluginprovided = true;
428 std::string model_name = pi->plugin ()->midnam_model ();
429 if (gui_property (X_("midnam-model-name")) != model_name) {
430 model_changed (model_name);
435 if (patch_manager.all_models().empty() || pluginprovided) {
436 _midnam_model_selector.hide ();
437 _midnam_custom_device_mode_selector.hide ();
439 _midnam_model_selector.show ();
440 _midnam_custom_device_mode_selector.show ();
445 MidiTimeAxisView::model_changed(const std::string& model)
447 set_gui_property (X_("midnam-model-name"), model);
449 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
450 .custom_device_mode_names_by_model(model);
452 _midnam_model_selector.set_text(model);
453 _midnam_custom_device_mode_selector.clear_items();
455 for (std::list<std::string>::const_iterator i = device_modes.begin();
456 i != device_modes.end(); ++i) {
457 _midnam_custom_device_mode_selector.AddMenuElem(
458 Gtk::Menu_Helpers::MenuElem(
459 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
463 if (!device_modes.empty()) {
464 custom_device_mode_changed(device_modes.front());
467 if (device_modes.size() > 1) {
468 _midnam_custom_device_mode_selector.show();
470 _midnam_custom_device_mode_selector.hide();
473 // now this is a real bad hack
474 if (device_modes.size() > 0) {
475 _route->instrument_info().set_external_instrument (model, device_modes.front());
477 _route->instrument_info().set_external_instrument (model, "");
480 // Rebuild controller menu
481 _controller_menu_map.clear ();
482 delete controller_menu;
484 build_automation_action_menu(false);
488 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
490 const std::string model = gui_property (X_("midnam-model-name"));
492 set_gui_property (X_("midnam-custom-device-mode"), mode);
493 _midnam_custom_device_mode_selector.set_text(mode);
494 _route->instrument_info().set_external_instrument (model, mode);
498 MidiTimeAxisView::midi_view()
500 return dynamic_cast<MidiStreamView*>(_view);
504 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
506 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
507 _midi_controls_box.show ();
509 _midi_controls_box.hide();
512 if (h >= KEYBOARD_MIN_HEIGHT) {
513 if (is_track() && _range_scroomer) {
514 _range_scroomer->show();
516 if (is_track() && _piano_roll_header) {
517 _piano_roll_header->show();
520 if (is_track() && _range_scroomer) {
521 _range_scroomer->hide();
523 if (is_track() && _piano_roll_header) {
524 _piano_roll_header->hide();
528 /* We need to do this after changing visibility of our stuff, as it will
529 eventually trigger a call to Editor::reset_controls_layout_width(),
530 which needs to know if we have just shown or hidden a scroomer /
533 RouteTimeAxisView::set_height (h, m);
537 MidiTimeAxisView::append_extra_display_menu_items ()
539 using namespace Menu_Helpers;
541 MenuList& items = display_menu->items();
544 Menu *range_menu = manage(new Menu);
545 MenuList& range_items = range_menu->items();
546 range_menu->set_name ("ArdourContextMenu");
548 range_items.push_back (
549 MenuElem (_("Show Full Range"),
550 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
551 MidiStreamView::FullRange, true)));
553 range_items.push_back (
554 MenuElem (_("Fit Contents"),
555 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
556 MidiStreamView::ContentsRange, true)));
558 items.push_back (MenuElem (_("Note Range"), *range_menu));
559 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
560 items.push_back (MenuElem (_("Channel Selector"),
561 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
563 items.push_back (MenuElem (_("Select Patch..."),
564 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
566 color_mode_menu = build_color_mode_menu();
567 if (color_mode_menu) {
568 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
571 items.push_back (SeparatorElem ());
575 MidiTimeAxisView::toggle_channel_selector ()
577 if (!_channel_selector) {
578 _channel_selector = new MidiChannelSelectorWindow (midi_track());
580 if (_color_mode == ChannelColors) {
581 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
583 _channel_selector->set_default_channel_color ();
586 _channel_selector->show_all ();
588 _channel_selector->cycle_visibility ();
593 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
595 using namespace Menu_Helpers;
597 /* If we have a controller menu, we need to detach it before
598 RouteTimeAxis::build_automation_action_menu destroys the
599 menu it is attached to. Otherwise GTK destroys
600 controller_menu's gobj, meaning that it can't be reattached
601 below. See bug #3134.
604 if (controller_menu) {
605 detach_menu (*controller_menu);
608 _channel_command_menu_map.clear ();
609 RouteTimeAxisView::build_automation_action_menu (for_selection);
611 MenuList& automation_items = automation_action_menu->items();
613 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
615 if (selected_channels != 0) {
617 automation_items.push_back (SeparatorElem());
619 /* these 2 MIDI "command" types are semantically more like automation
620 than note data, but they are not MIDI controllers. We give them
621 special status in this menu, since they will not show up in the
622 controller list and anyone who actually knows something about MIDI
623 (!) would not expect to find them there.
626 add_channel_command_menu_item (
627 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
628 automation_items.back().set_sensitive (
629 !for_selection || _editor.get_selection().tracks.size() == 1);
630 add_channel_command_menu_item (
631 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
632 automation_items.back().set_sensitive (
633 !for_selection || _editor.get_selection().tracks.size() == 1);
635 /* now all MIDI controllers. Always offer the possibility that we will
636 rebuild the controllers menu since it might need to be updated after
637 a channel mode change or other change. Also detach it first in case
638 it has been used anywhere else.
641 build_controller_menu ();
643 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
645 if (!poly_pressure_menu) {
646 poly_pressure_menu = new Gtk::Menu;
649 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
651 automation_items.back().set_sensitive (
652 !for_selection || _editor.get_selection().tracks.size() == 1);
654 automation_items.push_back (
655 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
656 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
661 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
663 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
665 for (uint8_t chn = 0; chn < 16; chn++) {
666 if (selected_channels & (0x0001 << chn)) {
668 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
669 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
672 menu->set_active (yn);
679 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
681 AutomationType auto_type,
684 using namespace Menu_Helpers;
686 /* count the number of selected channels because we will build a different menu
687 structure if there is more than 1 selected.
690 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
693 for (uint8_t chn = 0; chn < 16; chn++) {
694 if (selected_channels & (0x0001 << chn)) {
703 /* multiple channels - create a submenu, with 1 item per channel */
705 Menu* chn_menu = manage (new Menu);
706 MenuList& chn_items (chn_menu->items());
707 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
709 /* add a couple of items to hide/show all of them */
711 chn_items.push_back (
712 MenuElem (_("Hide all channels"),
713 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
714 false, param_without_channel)));
715 chn_items.push_back (
716 MenuElem (_("Show all channels"),
717 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
718 true, param_without_channel)));
720 for (uint8_t chn = 0; chn < 16; chn++) {
721 if (selected_channels & (0x0001 << chn)) {
723 /* for each selected channel, add a menu item for this controller */
725 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
726 chn_items.push_back (
727 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
728 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
729 fully_qualified_param)));
731 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
732 bool visible = false;
735 if (track->marked_for_display()) {
740 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
741 _channel_command_menu_map[fully_qualified_param] = cmi;
742 cmi->set_active (visible);
746 /* now create an item in the parent menu that has the per-channel list as a submenu */
748 items.push_back (MenuElem (label, *chn_menu));
752 /* just one channel - create a single menu item for this command+channel combination*/
754 for (uint8_t chn = 0; chn < 16; chn++) {
755 if (selected_channels & (0x0001 << chn)) {
757 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
759 CheckMenuElem (label,
760 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
761 fully_qualified_param)));
763 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
764 bool visible = false;
767 if (track->marked_for_display()) {
772 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
773 _channel_command_menu_map[fully_qualified_param] = cmi;
774 cmi->set_active (visible);
776 /* one channel only */
783 /** Add a single menu item for a controller on one channel. */
785 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
787 const std::string& name)
789 using namespace Menu_Helpers;
791 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
792 for (uint8_t chn = 0; chn < 16; chn++) {
793 if (selected_channels & (0x0001 << chn)) {
795 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
796 ctl_items.push_back (
798 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
800 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
801 fully_qualified_param)));
802 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
804 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
805 fully_qualified_param);
807 bool visible = false;
809 if (track->marked_for_display()) {
814 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
815 _controller_menu_map[fully_qualified_param] = cmi;
816 cmi->set_active (visible);
818 /* one channel only */
824 /** Add a submenu with 1 item per channel for a controller on many channels. */
826 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
828 const std::string& name)
830 using namespace Menu_Helpers;
832 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
834 Menu* chn_menu = manage (new Menu);
835 MenuList& chn_items (chn_menu->items());
837 /* add a couple of items to hide/show this controller on all channels */
839 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
840 chn_items.push_back (
841 MenuElem (_("Hide all channels"),
842 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
843 false, param_without_channel)));
844 chn_items.push_back (
845 MenuElem (_("Show all channels"),
846 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
847 true, param_without_channel)));
849 for (uint8_t chn = 0; chn < 16; chn++) {
850 if (selected_channels & (0x0001 << chn)) {
852 /* for each selected channel, add a menu item for this controller */
854 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
855 chn_items.push_back (
856 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
857 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
858 fully_qualified_param)));
860 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
861 fully_qualified_param);
862 bool visible = false;
865 if (track->marked_for_display()) {
870 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
871 _controller_menu_map[fully_qualified_param] = cmi;
872 cmi->set_active (visible);
876 /* add the per-channel menu to the list of controllers, with the name of the controller */
877 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
879 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
882 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
883 MidiTimeAxisView::get_device_mode()
885 using namespace MIDI::Name;
887 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
889 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
892 return device_names->custom_device_mode_by_name(
893 gui_property (X_("midnam-custom-device-mode")));
896 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
897 MidiTimeAxisView::get_device_names()
899 using namespace MIDI::Name;
901 const std::string model = gui_property (X_("midnam-model-name"));
903 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
904 .document_by_model(model);
906 return midnam->master_device_names(model);
908 return boost::shared_ptr<MasterDeviceNames>();
913 MidiTimeAxisView::build_controller_menu ()
915 using namespace Menu_Helpers;
917 if (controller_menu) {
918 /* it exists and has not been invalidated by a channel mode change */
922 controller_menu = new Menu; // explicitly managed by us
923 MenuList& items (controller_menu->items());
925 /* create several "top level" menu items for sets of controllers (16 at a
926 time), and populate each one with a submenu for each controller+channel
927 combination covering the currently selected channels for this track
930 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
932 /* count the number of selected channels because we will build a different menu
933 structure if there is more than 1 selected.
937 for (uint8_t chn = 0; chn < 16; chn++) {
938 if (selected_channels & (0x0001 << chn)) {
945 using namespace MIDI::Name;
946 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
948 if (device_names && !device_names->controls().empty()) {
949 /* Controllers names available in midnam file, generate fancy menu */
950 unsigned n_items = 0;
951 unsigned n_groups = 0;
953 /* TODO: This is not correct, should look up the currently applicable ControlNameList
954 and only build a menu for that one. */
955 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
956 l != device_names->controls().end(); ++l) {
957 boost::shared_ptr<ControlNameList> name_list = l->second;
958 Menu* ctl_menu = NULL;
960 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
961 c != name_list->controls().end();) {
962 const uint16_t ctl = c->second->number();
963 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
964 /* Skip bank select controllers since they're handled specially */
966 /* Create a new submenu */
967 ctl_menu = manage (new Menu);
970 MenuList& ctl_items (ctl_menu->items());
972 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
974 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
979 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
980 /* Submenu has 16 items or we're done, add it to controller menu and reset */
982 MenuElem(string_compose(_("Controllers %1-%2"),
983 (16 * n_groups), (16 * n_groups) + n_items - 1),
992 /* No controllers names, generate generic numeric menu */
993 for (int i = 0; i < 127; i += 16) {
994 Menu* ctl_menu = manage (new Menu);
995 MenuList& ctl_items (ctl_menu->items());
997 for (int ctl = i; ctl < i+16; ++ctl) {
998 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
999 /* Skip bank select controllers since they're handled specially */
1004 add_multi_channel_controller_item(
1005 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1007 add_single_channel_controller_item(
1008 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1012 /* Add submenu for this block of controllers to controller menu */
1014 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1021 MidiTimeAxisView::build_note_mode_menu()
1023 using namespace Menu_Helpers;
1025 Menu* mode_menu = manage (new Menu);
1026 MenuList& items = mode_menu->items();
1027 mode_menu->set_name ("ArdourContextMenu");
1029 RadioMenuItem::Group mode_group;
1031 RadioMenuElem (mode_group,_("Sustained"),
1032 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1034 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1035 _note_mode_item->set_active(_note_mode == Sustained);
1038 RadioMenuElem (mode_group, _("Percussive"),
1039 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1040 Percussive, true)));
1041 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1042 _percussion_mode_item->set_active(_note_mode == Percussive);
1048 MidiTimeAxisView::build_color_mode_menu()
1050 using namespace Menu_Helpers;
1052 Menu* mode_menu = manage (new Menu);
1053 MenuList& items = mode_menu->items();
1054 mode_menu->set_name ("ArdourContextMenu");
1056 RadioMenuItem::Group mode_group;
1058 RadioMenuElem (mode_group, _("Meter Colors"),
1059 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1060 MeterColors, false, true, true)));
1061 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1062 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1065 RadioMenuElem (mode_group, _("Channel Colors"),
1066 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1067 ChannelColors, false, true, true)));
1068 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1069 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1072 RadioMenuElem (mode_group, _("Track Color"),
1073 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1074 TrackColor, false, true, true)));
1075 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1076 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1082 MidiTimeAxisView::send_patch_change ()
1088 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
1089 PatchChangeDialog d (0, 0, empty, _route->instrument_info(), Gtk::Stock::OK);
1091 if (d.run() == RESPONSE_CANCEL) {
1094 Evoral::PatchChange<Evoral::Beats> p (d.patch ());
1096 uint8_t chn = p.channel();
1098 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1099 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1100 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1102 if (!bank_msb || ! bank_lsb || !program) {
1106 bank_msb->set_value (p.bank_msb (), Controllable::NoGroup);
1107 bank_lsb->set_value (p.bank_lsb (), Controllable::NoGroup);
1108 program->set_value (p.program () , Controllable::NoGroup);
1112 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1114 if (apply_to_selection) {
1115 _editor.get_selection().tracks.foreach_midi_time_axis (
1116 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1118 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1120 midi_track()->set_note_mode(mode);
1121 set_gui_property ("note-mode", enum_2_string(_note_mode));
1122 _view->redisplay_track();
1128 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1130 if (apply_to_selection) {
1131 _editor.get_selection().tracks.foreach_midi_time_axis (
1132 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1134 if (_color_mode == mode && !force) {
1138 if (_channel_selector) {
1139 if (mode == ChannelColors) {
1140 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1142 _channel_selector->set_default_channel_color();
1147 set_gui_property ("color-mode", enum_2_string(_color_mode));
1149 _view->redisplay_track();
1155 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1157 if (apply_to_selection) {
1158 _editor.get_selection().tracks.foreach_midi_time_axis (
1159 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1161 if (!_ignore_signals) {
1162 midi_view()->set_note_range(range);
1168 MidiTimeAxisView::update_range()
1173 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1175 using namespace MIDI::Name;
1177 if (apply_to_selection) {
1178 _editor.get_selection().tracks.foreach_midi_time_axis (
1179 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1182 // Show existing automation
1183 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1185 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1186 create_automation_child(*i, true);
1189 // Show automation for all controllers named in midnam file
1190 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1191 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1192 device_names && !device_names->controls().empty()) {
1193 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1194 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1195 for (uint32_t chn = 0; chn < 16; ++chn) {
1196 if ((selected_channels & (0x0001 << chn)) == 0) {
1197 // Channel not in use
1201 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1207 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1208 chan_names->control_list_name());
1209 if (!control_names) {
1213 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1214 c != control_names->controls().end();
1216 const uint16_t ctl = c->second->number();
1217 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1218 /* Skip bank select controllers since they're handled specially */
1219 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1220 create_automation_child(param, true);
1227 RouteTimeAxisView::show_all_automation ();
1232 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1234 if (apply_to_selection) {
1235 _editor.get_selection().tracks.foreach_midi_time_axis (
1236 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1239 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1241 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1242 create_automation_child (*i, true);
1246 RouteTimeAxisView::show_existing_automation ();
1250 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1253 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1255 if (param.type() == NullAutomation) {
1259 AutomationTracks::iterator existing = _automation_tracks.find (param);
1261 if (existing != _automation_tracks.end()) {
1263 /* automation track created because we had existing data for
1264 * the processor, but visibility may need to be controlled
1265 * since it will have been set visible by default.
1268 existing->second->set_marked_for_display (show);
1277 boost::shared_ptr<AutomationTimeAxisView> track;
1278 boost::shared_ptr<AutomationControl> control;
1281 switch (param.type()) {
1283 case GainAutomation:
1284 create_gain_automation_child (param, show);
1287 case MuteAutomation:
1288 create_mute_automation_child (param, show);
1291 case PluginAutomation:
1292 /* handled elsewhere */
1295 case MidiCCAutomation:
1296 case MidiPgmChangeAutomation:
1297 case MidiPitchBenderAutomation:
1298 case MidiChannelPressureAutomation:
1299 case MidiSystemExclusiveAutomation:
1300 /* These controllers are region "automation" - they are owned
1301 * by regions (and their MidiModels), not by the track. As a
1302 * result there is no AutomationList/Line for the track, but we create
1303 * a controller for the user to write immediate events, so the editor
1304 * can act as a control surface for the present MIDI controllers.
1306 * TODO: Record manipulation of the controller to regions?
1309 control = _route->automation_control(param, true);
1310 track.reset (new AutomationTimeAxisView (
1313 control ? _route : boost::shared_ptr<Automatable> (),
1320 _route->describe_parameter(param)));
1323 _view->foreach_regionview (
1324 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1327 add_automation_child (param, track, show);
1330 case PanWidthAutomation:
1331 case PanElevationAutomation:
1332 case PanAzimuthAutomation:
1333 ensure_pan_views (show);
1337 error << "MidiTimeAxisView: unknown automation child "
1338 << EventTypeMap::instance().to_symbol(param) << endmsg;
1343 MidiTimeAxisView::route_active_changed ()
1345 RouteUI::route_active_changed ();
1346 update_control_names();
1350 MidiTimeAxisView::update_control_names ()
1353 if (_route->active()) {
1354 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1355 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1357 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1358 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1360 } else { // MIDI bus (which doesn't exist yet..)
1361 if (_route->active()) {
1362 controls_base_selected_name = "BusControlsBaseSelected";
1363 controls_base_unselected_name = "BusControlsBaseUnselected";
1365 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1366 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1371 controls_ebox.set_name (controls_base_selected_name);
1372 time_axis_frame.set_name (controls_base_selected_name);
1374 controls_ebox.set_name (controls_base_unselected_name);
1375 time_axis_frame.set_name (controls_base_unselected_name);
1380 MidiTimeAxisView::set_note_selection (uint8_t note)
1382 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1384 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1386 if (_view->num_selected_regionviews() == 0) {
1387 _view->foreach_regionview (
1388 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1391 _view->foreach_selected_regionview (
1392 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1396 _editor.commit_reversible_selection_op();
1400 MidiTimeAxisView::add_note_selection (uint8_t note)
1402 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1404 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1406 if (_view->num_selected_regionviews() == 0) {
1407 _view->foreach_regionview (
1408 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1411 _view->foreach_selected_regionview (
1412 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1416 _editor.commit_reversible_selection_op();
1420 MidiTimeAxisView::extend_note_selection (uint8_t note)
1422 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1424 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1426 if (_view->num_selected_regionviews() == 0) {
1427 _view->foreach_regionview (
1428 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1431 _view->foreach_selected_regionview (
1432 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1436 _editor.commit_reversible_selection_op();
1440 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1442 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1444 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1446 if (_view->num_selected_regionviews() == 0) {
1447 _view->foreach_regionview (
1448 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1451 _view->foreach_selected_regionview (
1452 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1456 _editor.commit_reversible_selection_op();
1460 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1462 _view->foreach_regionview (
1463 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1467 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1469 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1473 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1475 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1479 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1481 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1485 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1487 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1491 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1493 Evoral::Sequence<Evoral::Beats>::Notes selected;
1494 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1496 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1498 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1499 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1500 notes.insert (*sel_it);
1503 if (!notes.empty()) {
1504 selection.push_back (make_pair ((rv)->region()->id(), notes));
1509 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1511 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1515 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1516 bool changed = false;
1520 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1522 for (uint32_t chn = 0; chn < 16; ++chn) {
1523 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1524 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1530 if ((selected_channels & (0x0001 << chn)) == 0) {
1531 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1532 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1534 changed = track->set_marked_for_display (false) || changed;
1536 changed = track->set_marked_for_display (true) || changed;
1543 /* TODO: Bender, Pressure */
1545 /* invalidate the controller menu, so that we rebuild it next time */
1546 _controller_menu_map.clear ();
1547 delete controller_menu;
1548 controller_menu = 0;
1556 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1558 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1563 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1564 if (i != _controller_menu_map.end()) {
1568 i = _channel_command_menu_map.find (param);
1569 if (i != _channel_command_menu_map.end()) {
1576 boost::shared_ptr<MidiRegion>
1577 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1579 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1580 MusicFrame pos (f, 0);
1583 real_editor->begin_reversible_command (Operations::create_region);
1585 playlist()->clear_changes ();
1587 real_editor->snap_to (pos, RoundNearest);
1589 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1592 plist.add (ARDOUR::Properties::start, 0);
1593 plist.add (ARDOUR::Properties::length, length);
1594 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1596 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1597 /* sets beat position */
1598 region->set_position (pos.frame, pos.division);
1599 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1600 _session->add_command (new StatefulDiffCommand (playlist()));
1603 real_editor->commit_reversible_command ();
1606 return boost::dynamic_pointer_cast<MidiRegion>(region);
1610 MidiTimeAxisView::ensure_step_editor ()
1612 if (!_step_editor) {
1613 _step_editor = new StepEditor (_editor, midi_track(), *this);
1618 MidiTimeAxisView::start_step_editing ()
1620 ensure_step_editor ();
1621 _step_editor->start_step_editing ();
1625 MidiTimeAxisView::stop_step_editing ()
1628 _step_editor->stop_step_editing ();
1632 /** @return channel (counted from 0) to add an event to, based on the current setting
1633 * of the channel selector.
1636 MidiTimeAxisView::get_channel_for_add () const
1638 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1640 uint8_t channel = 0;
1642 /* pick the highest selected channel, unless all channels are selected,
1643 which is interpreted to mean channel 1 (zero)
1646 for (uint16_t i = 0; i < 16; ++i) {
1647 if (chn_mask & (1<<i)) {
1653 if (chn_cnt == 16) {
1661 MidiTimeAxisView::note_range_changed ()
1663 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1664 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1668 MidiTimeAxisView::contents_height_changed ()
1670 _range_scroomer->queue_resize ();
1674 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1676 if (!_editor.internal_editing()) {
1677 // Non-internal paste, paste regions like any other route
1678 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1681 return midi_view()->paste(pos, selection, ctx, sub_num);