2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <gtkmm/separator.h>
29 #include <gtkmm/stock.h>
31 #include "pbd/error.h"
33 #include "pbd/stl_delete.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/basename.h"
36 #include "pbd/enumwriter.h"
37 #include "pbd/memento_command.h"
38 #include "pbd/stateful_diff_command.h"
40 #include "gtkmm2ext/gtk_ui.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/tooltips.h"
45 #include "ardour/event_type_map.h"
46 #include "ardour/midi_patch_manager.h"
47 #include "ardour/midi_playlist.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_source.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/operations.h"
52 #include "ardour/pannable.h"
53 #include "ardour/panner.h"
54 #include "ardour/panner_shell.h"
55 #include "ardour/playlist.h"
56 #include "ardour/plugin_insert.h"
57 #include "ardour/profile.h"
58 #include "ardour/region.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/route.h"
61 #include "ardour/session.h"
62 #include "ardour/session_object.h"
63 #include "ardour/source.h"
64 #include "ardour/track.h"
65 #include "ardour/types.h"
67 #include "automation_line.h"
68 #include "automation_time_axis.h"
71 #include "ghostregion.h"
72 #include "gui_thread.h"
74 #include "midi_channel_selector.h"
75 #include "midi_scroomer.h"
76 #include "midi_streamview.h"
77 #include "midi_region_view.h"
78 #include "midi_time_axis.h"
79 #include "patch_change_dialog.h"
80 #include "patch_change_widget.h"
81 #include "piano_roll_header.h"
82 #include "playlist_selector.h"
83 #include "plugin_selector.h"
84 #include "plugin_ui.h"
85 #include "point_selection.h"
86 #include "region_view.h"
87 #include "rgb_macros.h"
88 #include "selection.h"
89 #include "step_editor.h"
91 #include "note_base.h"
93 #include "ardour/midi_track.h"
97 using namespace ARDOUR;
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)
126 , _patch_change_dialog (0)
128 _midnam_model_selector.disable_scrolling();
129 _midnam_custom_device_mode_selector.disable_scrolling();
133 MidiTimeAxisView::set_note_highlight (uint8_t note) {
134 _piano_roll_header->set_note_highlight (note);
138 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
142 _view = new MidiStreamView (*this);
145 _piano_roll_header = new PianoRollHeader(*midi_view());
146 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
147 _range_scroomer->DoubleClicked.connect (
148 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
149 MidiStreamView::ContentsRange, false));
152 /* This next call will result in our height being set up, so it must come after
153 the creation of the piano roll / range scroomer as their visibility is set up
156 RouteTimeAxisView::set_route (rt);
158 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
160 subplugin_menu.set_name ("ArdourContextMenu");
162 if (!gui_property ("note-range-min").empty ()) {
163 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
164 atoi (gui_property ("note-range-max").c_str()),
168 _view->ContentsHeightChanged.connect (
169 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
171 ignore_toggle = false;
173 if (is_midi_track()) {
174 _note_mode = midi_track()->note_mode();
177 /* if set_state above didn't create a gain automation child, we need to make one */
178 if (automation_child (GainAutomation) == 0) {
179 create_automation_child (GainAutomation, false);
182 /* if set_state above didn't create a mute automation child, we need to make one */
183 if (automation_child (MuteAutomation) == 0) {
184 create_automation_child (MuteAutomation, false);
187 if (_route->panner_shell()) {
188 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
191 /* map current state of the route */
192 ensure_pan_views (false);
193 update_control_names();
194 processors_changed (RouteProcessorChange ());
196 _route->processors_changed.connect (*this, invalidator (*this),
197 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
201 _piano_roll_header->SetNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
203 _piano_roll_header->AddNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
205 _piano_roll_header->ExtendNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
207 _piano_roll_header->ToggleNoteSelection.connect (
208 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
210 /* Update StreamView during scroomer drags.*/
212 _range_scroomer->DragStarting.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
214 _range_scroomer->DragFinishing.connect (
215 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
217 /* Put the scroomer and the keyboard in a VBox with a padding
218 label so that they can be reduced in height for stacked-view
222 HSeparator* separator = manage (new HSeparator());
223 separator->set_name("TrackSeparator");
224 separator->set_size_request(-1, 1);
227 VBox* v = manage (new VBox);
228 HBox* h = manage (new HBox);
229 h->pack_end (*_piano_roll_header);
230 h->pack_end (*_range_scroomer);
231 v->pack_start (*separator, false, false);
232 v->pack_start (*h, true, true);
235 top_hbox.remove(scroomer_placeholder);
236 time_axis_hbox.pack_end(*v, false, false, 0);
237 midi_scroomer_size_group->add_widget (*v);
239 midi_view()->NoteRangeChanged.connect (
240 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
242 /* ask for notifications of any new RegionViews */
243 _view->RegionViewAdded.connect (
244 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
246 if (!_editor.have_idled()) {
247 /* first idle will do what we need */
253 if (gui_property (X_("midnam-model-name")).empty()) {
254 set_gui_property (X_("midnam-model-name"), "Generic");
257 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
258 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
260 set_gui_property (X_("midnam-custom-device-mode"),
261 *device_names->custom_device_mode_names().begin());
265 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
266 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
268 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
269 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
271 _midi_controls_box.set_homogeneous(false);
272 _midi_controls_box.set_border_width (2);
274 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
275 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
278 setup_midnam_patches ();
279 update_patch_selector ();
281 model_changed (gui_property(X_("midnam-model-name")));
282 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
284 controls_vbox.pack_start(_midi_controls_box, false, false);
286 const string color_mode = gui_property ("color-mode");
287 if (!color_mode.empty()) {
288 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
289 if (_channel_selector && _color_mode == ChannelColors) {
290 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
294 set_color_mode (_color_mode, true, false);
296 const string note_mode = gui_property ("note-mode");
297 if (!note_mode.empty()) {
298 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
299 if (_percussion_mode_item) {
300 _percussion_mode_item->set_active (_note_mode == Percussive);
304 /* Look for any GUI object state nodes that represent automation children
305 * that should exist, and create the children.
308 const list<string> gui_ids = gui_object_state().all_ids ();
309 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
312 Evoral::Parameter parameter (0, 0, 0);
314 bool const p = AutomationTimeAxisView::parse_state_id (
315 *i, route_id, has_parameter, parameter);
316 if (p && route_id == _route->id () && has_parameter) {
317 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
318 create_automation_child (parameter, string_to<bool> (visible));
324 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
326 RouteTimeAxisView::processors_changed (c);
327 update_patch_selector ();
331 MidiTimeAxisView::first_idle ()
338 MidiTimeAxisView::~MidiTimeAxisView ()
340 delete _channel_selector;
342 delete _piano_roll_header;
343 _piano_roll_header = 0;
345 delete _range_scroomer;
348 delete controller_menu;
351 delete _patch_change_dialog;
352 _patch_change_dialog = 0;
356 MidiTimeAxisView::check_step_edit ()
358 ensure_step_editor ();
359 _step_editor->check_step_edit ();
363 MidiTimeAxisView::setup_midnam_patches ()
365 typedef MIDI::Name::MidiPatchManager PatchManager;
366 PatchManager& patch_manager = PatchManager::instance();
368 _midnam_model_selector.clear_items ();
369 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
370 m != patch_manager.devices_by_manufacturer().end(); ++m) {
371 Menu* menu = Gtk::manage(new Menu);
372 Menu_Helpers::MenuList& items = menu->items();
374 // Build manufacturer submenu
375 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
376 n != m->second.end(); ++n) {
377 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
379 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
382 items.push_back(elem);
385 // Add manufacturer submenu to selector
386 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
389 if (!get_device_names()) {
390 model_changed ("Generic");
395 MidiTimeAxisView::drop_instrument_ref ()
397 midnam_connection.drop_connections ();
400 MidiTimeAxisView::start_scroomer_update ()
402 _note_range_changed_connection.disconnect();
403 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
404 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
407 MidiTimeAxisView::stop_scroomer_update ()
409 _note_range_changed_connection.disconnect();
413 MidiTimeAxisView::update_patch_selector ()
415 typedef MIDI::Name::MidiPatchManager PatchManager;
416 PatchManager& patch_manager = PatchManager::instance();
418 bool pluginprovided = false;
420 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
421 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
422 if (pi && pi->plugin ()->has_midnam ()) {
423 midnam_connection.drop_connections ();
424 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
425 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
427 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
428 boost::bind (&MidiTimeAxisView::reread_midnam, this),
431 pluginprovided = true;
432 std::string model_name = pi->plugin ()->midnam_model ();
433 if (gui_property (X_("midnam-model-name")) != model_name) {
434 model_changed (model_name);
439 if (patch_manager.all_models().empty() || pluginprovided) {
440 _midnam_model_selector.hide ();
441 _midnam_custom_device_mode_selector.hide ();
443 _midnam_model_selector.show ();
444 _midnam_custom_device_mode_selector.show ();
449 MidiTimeAxisView::reread_midnam ()
451 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
452 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
453 pi->plugin ()->read_midnam();
455 if (_patch_change_dialog) {
456 _patch_change_dialog->refresh ();
460 MidiTimeAxisView::model_changed(const std::string& model)
462 set_gui_property (X_("midnam-model-name"), model);
464 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
465 .custom_device_mode_names_by_model(model);
467 _midnam_model_selector.set_text(model);
468 _midnam_custom_device_mode_selector.clear_items();
470 for (std::list<std::string>::const_iterator i = device_modes.begin();
471 i != device_modes.end(); ++i) {
472 _midnam_custom_device_mode_selector.AddMenuElem(
473 Gtk::Menu_Helpers::MenuElem(
474 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
478 if (!device_modes.empty()) {
479 custom_device_mode_changed(device_modes.front());
482 if (device_modes.size() > 1) {
483 _midnam_custom_device_mode_selector.show();
485 _midnam_custom_device_mode_selector.hide();
488 // now this is a real bad hack
489 if (device_modes.size() > 0) {
490 _route->instrument_info().set_external_instrument (model, device_modes.front());
492 _route->instrument_info().set_external_instrument (model, "");
495 // Rebuild controller menu
496 _controller_menu_map.clear ();
497 delete controller_menu;
499 build_automation_action_menu(false);
501 if (_patch_change_dialog) {
502 _patch_change_dialog->refresh ();
507 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
509 const std::string model = gui_property (X_("midnam-model-name"));
511 set_gui_property (X_("midnam-custom-device-mode"), mode);
512 _midnam_custom_device_mode_selector.set_text(mode);
513 _route->instrument_info().set_external_instrument (model, mode);
517 MidiTimeAxisView::midi_view()
519 return dynamic_cast<MidiStreamView*>(_view);
523 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
525 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
526 _midi_controls_box.show ();
528 _midi_controls_box.hide();
531 if (h >= KEYBOARD_MIN_HEIGHT) {
532 if (is_track() && _range_scroomer) {
533 _range_scroomer->show();
535 if (is_track() && _piano_roll_header) {
536 _piano_roll_header->show();
539 if (is_track() && _range_scroomer) {
540 _range_scroomer->hide();
542 if (is_track() && _piano_roll_header) {
543 _piano_roll_header->hide();
547 /* We need to do this after changing visibility of our stuff, as it will
548 eventually trigger a call to Editor::reset_controls_layout_width(),
549 which needs to know if we have just shown or hidden a scroomer /
552 RouteTimeAxisView::set_height (h, m);
556 MidiTimeAxisView::append_extra_display_menu_items ()
558 using namespace Menu_Helpers;
560 MenuList& items = display_menu->items();
563 Menu *range_menu = manage(new Menu);
564 MenuList& range_items = range_menu->items();
565 range_menu->set_name ("ArdourContextMenu");
567 range_items.push_back (
568 MenuElem (_("Show Full Range"),
569 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
570 MidiStreamView::FullRange, true)));
572 range_items.push_back (
573 MenuElem (_("Fit Contents"),
574 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
575 MidiStreamView::ContentsRange, true)));
577 items.push_back (MenuElem (_("Note Range"), *range_menu));
578 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
579 items.push_back (MenuElem (_("Channel Selector..."),
580 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
582 items.push_back (MenuElem (_("Patch Selector..."),
583 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
585 color_mode_menu = build_color_mode_menu();
586 if (color_mode_menu) {
587 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
590 items.push_back (SeparatorElem ());
594 MidiTimeAxisView::toggle_channel_selector ()
596 if (!_channel_selector) {
597 _channel_selector = new MidiChannelSelectorWindow (midi_track());
599 if (_color_mode == ChannelColors) {
600 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
602 _channel_selector->set_default_channel_color ();
605 _channel_selector->show_all ();
607 _channel_selector->cycle_visibility ();
612 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
614 using namespace Menu_Helpers;
616 /* If we have a controller menu, we need to detach it before
617 RouteTimeAxis::build_automation_action_menu destroys the
618 menu it is attached to. Otherwise GTK destroys
619 controller_menu's gobj, meaning that it can't be reattached
620 below. See bug #3134.
623 if (controller_menu) {
624 detach_menu (*controller_menu);
627 _channel_command_menu_map.clear ();
628 RouteTimeAxisView::build_automation_action_menu (for_selection);
630 MenuList& automation_items = automation_action_menu->items();
632 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
634 if (selected_channels != 0) {
636 automation_items.push_back (SeparatorElem());
638 /* these 2 MIDI "command" types are semantically more like automation
639 than note data, but they are not MIDI controllers. We give them
640 special status in this menu, since they will not show up in the
641 controller list and anyone who actually knows something about MIDI
642 (!) would not expect to find them there.
645 add_channel_command_menu_item (
646 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
647 automation_items.back().set_sensitive (
648 !for_selection || _editor.get_selection().tracks.size() == 1);
649 add_channel_command_menu_item (
650 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
651 automation_items.back().set_sensitive (
652 !for_selection || _editor.get_selection().tracks.size() == 1);
654 /* now all MIDI controllers. Always offer the possibility that we will
655 rebuild the controllers menu since it might need to be updated after
656 a channel mode change or other change. Also detach it first in case
657 it has been used anywhere else.
660 build_controller_menu ();
662 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
664 if (!poly_pressure_menu) {
665 poly_pressure_menu = new Gtk::Menu;
668 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
670 automation_items.back().set_sensitive (
671 !for_selection || _editor.get_selection().tracks.size() == 1);
673 automation_items.push_back (
674 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
675 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
680 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
682 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
684 for (uint8_t chn = 0; chn < 16; chn++) {
685 if (selected_channels & (0x0001 << chn)) {
687 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
688 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
691 menu->set_active (yn);
698 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
700 AutomationType auto_type,
703 using namespace Menu_Helpers;
705 /* count the number of selected channels because we will build a different menu
706 structure if there is more than 1 selected.
709 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
712 for (uint8_t chn = 0; chn < 16; chn++) {
713 if (selected_channels & (0x0001 << chn)) {
722 /* multiple channels - create a submenu, with 1 item per channel */
724 Menu* chn_menu = manage (new Menu);
725 MenuList& chn_items (chn_menu->items());
726 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
728 /* add a couple of items to hide/show all of them */
730 chn_items.push_back (
731 MenuElem (_("Hide all channels"),
732 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
733 false, param_without_channel)));
734 chn_items.push_back (
735 MenuElem (_("Show all channels"),
736 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
737 true, param_without_channel)));
739 for (uint8_t chn = 0; chn < 16; chn++) {
740 if (selected_channels & (0x0001 << chn)) {
742 /* for each selected channel, add a menu item for this controller */
744 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
745 chn_items.push_back (
746 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
747 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
748 fully_qualified_param)));
750 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
751 bool visible = false;
754 if (track->marked_for_display()) {
759 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
760 _channel_command_menu_map[fully_qualified_param] = cmi;
761 cmi->set_active (visible);
765 /* now create an item in the parent menu that has the per-channel list as a submenu */
767 items.push_back (MenuElem (label, *chn_menu));
771 /* just one channel - create a single menu item for this command+channel combination*/
773 for (uint8_t chn = 0; chn < 16; chn++) {
774 if (selected_channels & (0x0001 << chn)) {
776 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
778 CheckMenuElem (label,
779 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
780 fully_qualified_param)));
782 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
783 bool visible = false;
786 if (track->marked_for_display()) {
791 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
792 _channel_command_menu_map[fully_qualified_param] = cmi;
793 cmi->set_active (visible);
795 /* one channel only */
802 /** Add a single menu item for a controller on one channel. */
804 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
806 const std::string& name)
808 using namespace Menu_Helpers;
810 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
811 for (uint8_t chn = 0; chn < 16; chn++) {
812 if (selected_channels & (0x0001 << chn)) {
814 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
815 ctl_items.push_back (
817 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
819 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
820 fully_qualified_param)));
821 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
823 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
824 fully_qualified_param);
826 bool visible = false;
828 if (track->marked_for_display()) {
833 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
834 _controller_menu_map[fully_qualified_param] = cmi;
835 cmi->set_active (visible);
837 /* one channel only */
843 /** Add a submenu with 1 item per channel for a controller on many channels. */
845 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
847 const std::string& name)
849 using namespace Menu_Helpers;
851 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
853 Menu* chn_menu = manage (new Menu);
854 MenuList& chn_items (chn_menu->items());
856 /* add a couple of items to hide/show this controller on all channels */
858 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
859 chn_items.push_back (
860 MenuElem (_("Hide all channels"),
861 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
862 false, param_without_channel)));
863 chn_items.push_back (
864 MenuElem (_("Show all channels"),
865 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
866 true, param_without_channel)));
868 for (uint8_t chn = 0; chn < 16; chn++) {
869 if (selected_channels & (0x0001 << chn)) {
871 /* for each selected channel, add a menu item for this controller */
873 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
874 chn_items.push_back (
875 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
876 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
877 fully_qualified_param)));
879 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
880 fully_qualified_param);
881 bool visible = false;
884 if (track->marked_for_display()) {
889 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
890 _controller_menu_map[fully_qualified_param] = cmi;
891 cmi->set_active (visible);
895 /* add the per-channel menu to the list of controllers, with the name of the controller */
896 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
898 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
901 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
902 MidiTimeAxisView::get_device_mode()
904 using namespace MIDI::Name;
906 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
908 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
911 return device_names->custom_device_mode_by_name(
912 gui_property (X_("midnam-custom-device-mode")));
915 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
916 MidiTimeAxisView::get_device_names()
918 using namespace MIDI::Name;
920 const std::string model = gui_property (X_("midnam-model-name"));
922 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
923 .document_by_model(model);
925 return midnam->master_device_names(model);
927 return boost::shared_ptr<MasterDeviceNames>();
932 MidiTimeAxisView::build_controller_menu ()
934 using namespace Menu_Helpers;
936 if (controller_menu) {
937 /* it exists and has not been invalidated by a channel mode change */
941 controller_menu = new Menu; // explicitly managed by us
942 MenuList& items (controller_menu->items());
944 /* create several "top level" menu items for sets of controllers (16 at a
945 time), and populate each one with a submenu for each controller+channel
946 combination covering the currently selected channels for this track
949 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
951 /* count the number of selected channels because we will build a different menu
952 structure if there is more than 1 selected.
956 for (uint8_t chn = 0; chn < 16; chn++) {
957 if (selected_channels & (0x0001 << chn)) {
964 using namespace MIDI::Name;
965 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
967 if (device_names && !device_names->controls().empty()) {
968 /* Controllers names available in midnam file, generate fancy menu */
969 unsigned n_items = 0;
970 unsigned n_groups = 0;
972 /* TODO: This is not correct, should look up the currently applicable ControlNameList
973 and only build a menu for that one. */
974 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
975 l != device_names->controls().end(); ++l) {
976 boost::shared_ptr<ControlNameList> name_list = l->second;
977 Menu* ctl_menu = NULL;
979 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
980 c != name_list->controls().end();) {
981 const uint16_t ctl = c->second->number();
982 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
983 /* Skip bank select controllers since they're handled specially */
985 /* Create a new submenu */
986 ctl_menu = manage (new Menu);
989 MenuList& ctl_items (ctl_menu->items());
991 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
993 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
998 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
999 /* Submenu has 16 items or we're done, add it to controller menu and reset */
1001 MenuElem(string_compose(_("Controllers %1-%2"),
1002 (16 * n_groups), (16 * n_groups) + n_items - 1),
1011 /* No controllers names, generate generic numeric menu */
1012 for (int i = 0; i < 127; i += 16) {
1013 Menu* ctl_menu = manage (new Menu);
1014 MenuList& ctl_items (ctl_menu->items());
1016 for (int ctl = i; ctl < i+16; ++ctl) {
1017 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1018 /* Skip bank select controllers since they're handled specially */
1023 add_multi_channel_controller_item(
1024 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1026 add_single_channel_controller_item(
1027 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1031 /* Add submenu for this block of controllers to controller menu */
1033 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1040 MidiTimeAxisView::build_note_mode_menu()
1042 using namespace Menu_Helpers;
1044 Menu* mode_menu = manage (new Menu);
1045 MenuList& items = mode_menu->items();
1046 mode_menu->set_name ("ArdourContextMenu");
1048 RadioMenuItem::Group mode_group;
1050 RadioMenuElem (mode_group,_("Sustained"),
1051 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1053 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1054 _note_mode_item->set_active(_note_mode == Sustained);
1057 RadioMenuElem (mode_group, _("Percussive"),
1058 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1059 Percussive, true)));
1060 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1061 _percussion_mode_item->set_active(_note_mode == Percussive);
1067 MidiTimeAxisView::build_color_mode_menu()
1069 using namespace Menu_Helpers;
1071 Menu* mode_menu = manage (new Menu);
1072 MenuList& items = mode_menu->items();
1073 mode_menu->set_name ("ArdourContextMenu");
1075 RadioMenuItem::Group mode_group;
1077 RadioMenuElem (mode_group, _("Meter Colors"),
1078 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1079 MeterColors, false, true, true)));
1080 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1081 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1084 RadioMenuElem (mode_group, _("Channel Colors"),
1085 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1086 ChannelColors, false, true, true)));
1087 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1088 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1091 RadioMenuElem (mode_group, _("Track Color"),
1092 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1093 TrackColor, false, true, true)));
1094 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1095 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1101 MidiTimeAxisView::send_patch_change ()
1106 if (_patch_change_dialog) {
1107 _patch_change_dialog->present ();
1111 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1112 _patch_change_dialog = d;
1117 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1119 if (apply_to_selection) {
1120 _editor.get_selection().tracks.foreach_midi_time_axis (
1121 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1123 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1125 midi_track()->set_note_mode(mode);
1126 set_gui_property ("note-mode", enum_2_string(_note_mode));
1127 _view->redisplay_track();
1133 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1135 if (apply_to_selection) {
1136 _editor.get_selection().tracks.foreach_midi_time_axis (
1137 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1139 if (_color_mode == mode && !force) {
1143 if (_channel_selector) {
1144 if (mode == ChannelColors) {
1145 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1147 _channel_selector->set_default_channel_color();
1152 set_gui_property ("color-mode", enum_2_string(_color_mode));
1154 _view->redisplay_track();
1160 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1162 if (apply_to_selection) {
1163 _editor.get_selection().tracks.foreach_midi_time_axis (
1164 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1166 if (!_ignore_signals) {
1167 midi_view()->set_note_range(range);
1173 MidiTimeAxisView::update_range()
1178 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1180 using namespace MIDI::Name;
1182 if (apply_to_selection) {
1183 _editor.get_selection().tracks.foreach_midi_time_axis (
1184 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1187 // Show existing automation
1188 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1190 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1191 create_automation_child(*i, true);
1194 // Show automation for all controllers named in midnam file
1195 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1196 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1197 device_names && !device_names->controls().empty()) {
1198 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1199 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1200 for (uint32_t chn = 0; chn < 16; ++chn) {
1201 if ((selected_channels & (0x0001 << chn)) == 0) {
1202 // Channel not in use
1206 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1212 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1213 chan_names->control_list_name());
1214 if (!control_names) {
1218 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1219 c != control_names->controls().end();
1221 const uint16_t ctl = c->second->number();
1222 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1223 /* Skip bank select controllers since they're handled specially */
1224 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1225 create_automation_child(param, true);
1232 RouteTimeAxisView::show_all_automation ();
1237 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1239 if (apply_to_selection) {
1240 _editor.get_selection().tracks.foreach_midi_time_axis (
1241 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1244 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1246 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1247 create_automation_child (*i, true);
1251 RouteTimeAxisView::show_existing_automation ();
1255 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1258 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1260 if (param.type() == NullAutomation) {
1264 AutomationTracks::iterator existing = _automation_tracks.find (param);
1266 if (existing != _automation_tracks.end()) {
1268 /* automation track created because we had existing data for
1269 * the processor, but visibility may need to be controlled
1270 * since it will have been set visible by default.
1273 existing->second->set_marked_for_display (show);
1282 boost::shared_ptr<AutomationTimeAxisView> track;
1283 boost::shared_ptr<AutomationControl> control;
1286 switch (param.type()) {
1288 case GainAutomation:
1289 create_gain_automation_child (param, show);
1292 case MuteAutomation:
1293 create_mute_automation_child (param, show);
1296 case PluginAutomation:
1297 /* handled elsewhere */
1300 case MidiCCAutomation:
1301 case MidiPgmChangeAutomation:
1302 case MidiPitchBenderAutomation:
1303 case MidiChannelPressureAutomation:
1304 case MidiSystemExclusiveAutomation:
1305 /* These controllers are region "automation" - they are owned
1306 * by regions (and their MidiModels), not by the track. As a
1307 * result there is no AutomationList/Line for the track, but we create
1308 * a controller for the user to write immediate events, so the editor
1309 * can act as a control surface for the present MIDI controllers.
1311 * TODO: Record manipulation of the controller to regions?
1314 control = _route->automation_control(param, true);
1315 track.reset (new AutomationTimeAxisView (
1318 control ? _route : boost::shared_ptr<Automatable> (),
1325 _route->describe_parameter(param)));
1328 _view->foreach_regionview (
1329 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1332 add_automation_child (param, track, show);
1334 reshow_selection (_editor.get_selection().time);
1339 case PanWidthAutomation:
1340 case PanElevationAutomation:
1341 case PanAzimuthAutomation:
1342 ensure_pan_views (show);
1346 error << "MidiTimeAxisView: unknown automation child "
1347 << EventTypeMap::instance().to_symbol(param) << endmsg;
1352 MidiTimeAxisView::route_active_changed ()
1354 RouteUI::route_active_changed ();
1355 update_control_names();
1359 MidiTimeAxisView::update_control_names ()
1362 if (_route->active()) {
1363 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1364 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1366 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1367 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1369 } else { // MIDI bus (which doesn't exist yet..)
1370 if (_route->active()) {
1371 controls_base_selected_name = "BusControlsBaseSelected";
1372 controls_base_unselected_name = "BusControlsBaseUnselected";
1374 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1375 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1380 controls_ebox.set_name (controls_base_selected_name);
1381 time_axis_frame.set_name (controls_base_selected_name);
1383 controls_ebox.set_name (controls_base_unselected_name);
1384 time_axis_frame.set_name (controls_base_unselected_name);
1389 MidiTimeAxisView::set_note_selection (uint8_t note)
1391 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1393 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1395 if (_view->num_selected_regionviews() == 0) {
1396 _view->foreach_regionview (
1397 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1400 _view->foreach_selected_regionview (
1401 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1405 _editor.commit_reversible_selection_op();
1409 MidiTimeAxisView::add_note_selection (uint8_t note)
1411 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1413 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1415 if (_view->num_selected_regionviews() == 0) {
1416 _view->foreach_regionview (
1417 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1420 _view->foreach_selected_regionview (
1421 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1425 _editor.commit_reversible_selection_op();
1429 MidiTimeAxisView::extend_note_selection (uint8_t note)
1431 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1433 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1435 if (_view->num_selected_regionviews() == 0) {
1436 _view->foreach_regionview (
1437 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1440 _view->foreach_selected_regionview (
1441 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1445 _editor.commit_reversible_selection_op();
1449 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1451 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1453 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1455 if (_view->num_selected_regionviews() == 0) {
1456 _view->foreach_regionview (
1457 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1460 _view->foreach_selected_regionview (
1461 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1465 _editor.commit_reversible_selection_op();
1469 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1471 _view->foreach_regionview (
1472 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1476 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1478 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1482 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1484 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1488 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1490 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1494 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1496 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1500 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1502 Evoral::Sequence<Evoral::Beats>::Notes selected;
1503 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1505 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1507 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1508 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1509 notes.insert (*sel_it);
1512 if (!notes.empty()) {
1513 selection.push_back (make_pair ((rv)->region()->id(), notes));
1518 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1520 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1524 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1525 bool changed = false;
1529 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1531 for (uint32_t chn = 0; chn < 16; ++chn) {
1532 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1533 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1539 if ((selected_channels & (0x0001 << chn)) == 0) {
1540 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1541 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1543 changed = track->set_marked_for_display (false) || changed;
1545 changed = track->set_marked_for_display (true) || changed;
1552 /* TODO: Bender, Pressure */
1554 /* invalidate the controller menu, so that we rebuild it next time */
1555 _controller_menu_map.clear ();
1556 delete controller_menu;
1557 controller_menu = 0;
1565 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1567 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1572 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1573 if (i != _controller_menu_map.end()) {
1577 i = _channel_command_menu_map.find (param);
1578 if (i != _channel_command_menu_map.end()) {
1585 boost::shared_ptr<MidiRegion>
1586 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1588 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1589 MusicFrame pos (f, 0);
1592 real_editor->begin_reversible_command (Operations::create_region);
1594 playlist()->clear_changes ();
1596 real_editor->snap_to (pos, RoundNearest);
1598 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1601 plist.add (ARDOUR::Properties::start, 0);
1602 plist.add (ARDOUR::Properties::length, length);
1603 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1605 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1606 /* sets beat position */
1607 region->set_position (pos.frame, pos.division);
1608 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1609 _session->add_command (new StatefulDiffCommand (playlist()));
1612 real_editor->commit_reversible_command ();
1615 return boost::dynamic_pointer_cast<MidiRegion>(region);
1619 MidiTimeAxisView::ensure_step_editor ()
1621 if (!_step_editor) {
1622 _step_editor = new StepEditor (_editor, midi_track(), *this);
1627 MidiTimeAxisView::start_step_editing ()
1629 ensure_step_editor ();
1630 _step_editor->start_step_editing ();
1634 MidiTimeAxisView::stop_step_editing ()
1637 _step_editor->stop_step_editing ();
1641 /** @return channel (counted from 0) to add an event to, based on the current setting
1642 * of the channel selector.
1645 MidiTimeAxisView::get_channel_for_add () const
1647 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1649 uint8_t channel = 0;
1651 /* pick the highest selected channel, unless all channels are selected,
1652 which is interpreted to mean channel 1 (zero)
1655 for (uint16_t i = 0; i < 16; ++i) {
1656 if (chn_mask & (1<<i)) {
1662 if (chn_cnt == 16) {
1670 MidiTimeAxisView::note_range_changed ()
1672 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1673 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1677 MidiTimeAxisView::contents_height_changed ()
1679 _range_scroomer->queue_resize ();
1683 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1685 if (!_editor.internal_editing()) {
1686 // Non-internal paste, paste regions like any other route
1687 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1690 return midi_view()->paste(pos, selection, ctx, sub_num);