2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <gtkmm/separator.h>
29 #include <gtkmm/stock.h>
31 #include "pbd/error.h"
33 #include "pbd/stl_delete.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/basename.h"
36 #include "pbd/enumwriter.h"
37 #include "pbd/memento_command.h"
38 #include "pbd/stateful_diff_command.h"
40 #include "gtkmm2ext/gtk_ui.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/tooltips.h"
45 #include "ardour/event_type_map.h"
46 #include "ardour/midi_patch_manager.h"
47 #include "ardour/midi_playlist.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_source.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/operations.h"
52 #include "ardour/pannable.h"
53 #include "ardour/panner.h"
54 #include "ardour/panner_shell.h"
55 #include "ardour/playlist.h"
56 #include "ardour/plugin_insert.h"
57 #include "ardour/profile.h"
58 #include "ardour/region.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/route.h"
61 #include "ardour/session.h"
62 #include "ardour/session_object.h"
63 #include "ardour/source.h"
64 #include "ardour/track.h"
65 #include "ardour/types.h"
67 #include "automation_line.h"
68 #include "automation_time_axis.h"
71 #include "ghostregion.h"
72 #include "gui_thread.h"
74 #include "midi_channel_selector.h"
75 #include "midi_scroomer.h"
76 #include "midi_streamview.h"
77 #include "midi_region_view.h"
78 #include "midi_time_axis.h"
79 #include "patch_change_dialog.h"
80 #include "piano_roll_header.h"
81 #include "playlist_selector.h"
82 #include "plugin_selector.h"
83 #include "plugin_ui.h"
84 #include "point_selection.h"
85 #include "region_view.h"
86 #include "rgb_macros.h"
87 #include "selection.h"
88 #include "step_editor.h"
90 #include "note_base.h"
92 #include "ardour/midi_track.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
103 // Minimum height at which a control is displayed
104 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
105 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
107 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
108 : SessionHandlePtr (sess)
109 , RouteTimeAxisView (ed, sess, canvas)
110 , _ignore_signals(false)
112 , _piano_roll_header(0)
113 , _note_mode(Sustained)
115 , _percussion_mode_item(0)
116 , _color_mode(MeterColors)
117 , _meter_color_mode_item(0)
118 , _channel_color_mode_item(0)
119 , _track_color_mode_item(0)
120 , _channel_selector (0)
121 , _step_edit_item (0)
122 , controller_menu (0)
123 , poly_pressure_menu (0)
126 _midnam_model_selector.disable_scrolling();
127 _midnam_custom_device_mode_selector.disable_scrolling();
131 MidiTimeAxisView::set_note_highlight (uint8_t note) {
132 _piano_roll_header->set_note_highlight (note);
136 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
140 _view = new MidiStreamView (*this);
143 _piano_roll_header = new PianoRollHeader(*midi_view());
144 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
145 _range_scroomer->DoubleClicked.connect (
146 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
147 MidiStreamView::ContentsRange, false));
150 /* This next call will result in our height being set up, so it must come after
151 the creation of the piano roll / range scroomer as their visibility is set up
154 RouteTimeAxisView::set_route (rt);
156 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
158 subplugin_menu.set_name ("ArdourContextMenu");
160 if (!gui_property ("note-range-min").empty ()) {
161 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
162 atoi (gui_property ("note-range-max").c_str()),
166 _view->ContentsHeightChanged.connect (
167 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
169 ignore_toggle = false;
171 if (is_midi_track()) {
172 _note_mode = midi_track()->note_mode();
175 /* if set_state above didn't create a gain automation child, we need to make one */
176 if (automation_child (GainAutomation) == 0) {
177 create_automation_child (GainAutomation, false);
180 /* if set_state above didn't create a mute automation child, we need to make one */
181 if (automation_child (MuteAutomation) == 0) {
182 create_automation_child (MuteAutomation, false);
185 if (_route->panner_shell()) {
186 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
189 /* map current state of the route */
190 ensure_pan_views (false);
191 update_control_names();
192 processors_changed (RouteProcessorChange ());
194 _route->processors_changed.connect (*this, invalidator (*this),
195 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
199 _piano_roll_header->SetNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
201 _piano_roll_header->AddNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
203 _piano_roll_header->ExtendNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
205 _piano_roll_header->ToggleNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
208 /* Update StreamView during scroomer drags.*/
210 _range_scroomer->DragStarting.connect (
211 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
212 _range_scroomer->DragFinishing.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
215 /* Put the scroomer and the keyboard in a VBox with a padding
216 label so that they can be reduced in height for stacked-view
220 HSeparator* separator = manage (new HSeparator());
221 separator->set_name("TrackSeparator");
222 separator->set_size_request(-1, 1);
225 VBox* v = manage (new VBox);
226 HBox* h = manage (new HBox);
227 h->pack_end (*_piano_roll_header);
228 h->pack_end (*_range_scroomer);
229 v->pack_start (*separator, false, false);
230 v->pack_start (*h, true, true);
233 top_hbox.remove(scroomer_placeholder);
234 time_axis_hbox.pack_end(*v, false, false, 0);
235 midi_scroomer_size_group->add_widget (*v);
237 midi_view()->NoteRangeChanged.connect (
238 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
240 /* ask for notifications of any new RegionViews */
241 _view->RegionViewAdded.connect (
242 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
244 if (!_editor.have_idled()) {
245 /* first idle will do what we need */
251 if (gui_property (X_("midnam-model-name")).empty()) {
252 set_gui_property (X_("midnam-model-name"), "Generic");
255 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
256 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
258 set_gui_property (X_("midnam-custom-device-mode"),
259 *device_names->custom_device_mode_names().begin());
263 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
264 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
266 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
267 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
269 _midi_controls_box.set_homogeneous(false);
270 _midi_controls_box.set_border_width (2);
272 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
273 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
276 setup_midnam_patches ();
277 update_patch_selector ();
279 model_changed (gui_property(X_("midnam-model-name")));
280 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
282 controls_vbox.pack_start(_midi_controls_box, false, false);
284 const string color_mode = gui_property ("color-mode");
285 if (!color_mode.empty()) {
286 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
287 if (_channel_selector && _color_mode == ChannelColors) {
288 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
292 set_color_mode (_color_mode, true, false);
294 const string note_mode = gui_property ("note-mode");
295 if (!note_mode.empty()) {
296 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
297 if (_percussion_mode_item) {
298 _percussion_mode_item->set_active (_note_mode == Percussive);
302 /* Look for any GUI object state nodes that represent automation children
303 * that should exist, and create the children.
306 const list<string> gui_ids = gui_object_state().all_ids ();
307 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
310 Evoral::Parameter parameter (0, 0, 0);
312 bool const p = AutomationTimeAxisView::parse_state_id (
313 *i, route_id, has_parameter, parameter);
314 if (p && route_id == _route->id () && has_parameter) {
315 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
316 create_automation_child (parameter, string_to<bool> (visible));
322 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
324 RouteTimeAxisView::processors_changed (c);
325 update_patch_selector ();
329 MidiTimeAxisView::first_idle ()
336 MidiTimeAxisView::~MidiTimeAxisView ()
338 delete _channel_selector;
340 delete _piano_roll_header;
341 _piano_roll_header = 0;
343 delete _range_scroomer;
346 delete controller_menu;
351 MidiTimeAxisView::check_step_edit ()
353 ensure_step_editor ();
354 _step_editor->check_step_edit ();
358 MidiTimeAxisView::setup_midnam_patches ()
360 typedef MIDI::Name::MidiPatchManager PatchManager;
361 PatchManager& patch_manager = PatchManager::instance();
363 _midnam_model_selector.clear_items ();
364 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
365 m != patch_manager.devices_by_manufacturer().end(); ++m) {
366 Menu* menu = Gtk::manage(new Menu);
367 Menu_Helpers::MenuList& items = menu->items();
369 // Build manufacturer submenu
370 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
371 n != m->second.end(); ++n) {
372 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
374 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
377 items.push_back(elem);
380 // Add manufacturer submenu to selector
381 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
384 if (!get_device_names()) {
385 model_changed ("Generic");
390 MidiTimeAxisView::drop_instrument_ref ()
392 midnam_connection.drop_connections ();
395 MidiTimeAxisView::start_scroomer_update ()
397 _note_range_changed_connection.disconnect();
398 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
399 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
402 MidiTimeAxisView::stop_scroomer_update ()
404 _note_range_changed_connection.disconnect();
408 MidiTimeAxisView::update_patch_selector ()
410 typedef MIDI::Name::MidiPatchManager PatchManager;
411 PatchManager& patch_manager = PatchManager::instance();
413 bool pluginprovided = false;
415 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
416 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
417 if (pi && pi->plugin ()->has_midnam ()) {
418 midnam_connection.drop_connections ();
419 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
420 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
422 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
423 boost::bind (&Plugin::read_midnam, pi->plugin ()),
426 pluginprovided = true;
427 std::string model_name = pi->plugin ()->midnam_model ();
428 if (gui_property (X_("midnam-model-name")) != model_name) {
429 model_changed (model_name);
434 if (patch_manager.all_models().empty() || pluginprovided) {
435 _midnam_model_selector.hide ();
436 _midnam_custom_device_mode_selector.hide ();
438 _midnam_model_selector.show ();
439 _midnam_custom_device_mode_selector.show ();
444 MidiTimeAxisView::model_changed(const std::string& model)
446 set_gui_property (X_("midnam-model-name"), model);
448 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
449 .custom_device_mode_names_by_model(model);
451 _midnam_model_selector.set_text(model);
452 _midnam_custom_device_mode_selector.clear_items();
454 for (std::list<std::string>::const_iterator i = device_modes.begin();
455 i != device_modes.end(); ++i) {
456 _midnam_custom_device_mode_selector.AddMenuElem(
457 Gtk::Menu_Helpers::MenuElem(
458 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
462 if (!device_modes.empty()) {
463 custom_device_mode_changed(device_modes.front());
466 if (device_modes.size() > 1) {
467 _midnam_custom_device_mode_selector.show();
469 _midnam_custom_device_mode_selector.hide();
472 // now this is a real bad hack
473 if (device_modes.size() > 0) {
474 _route->instrument_info().set_external_instrument (model, device_modes.front());
476 _route->instrument_info().set_external_instrument (model, "");
479 // Rebuild controller menu
480 _controller_menu_map.clear ();
481 delete controller_menu;
483 build_automation_action_menu(false);
487 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
489 const std::string model = gui_property (X_("midnam-model-name"));
491 set_gui_property (X_("midnam-custom-device-mode"), mode);
492 _midnam_custom_device_mode_selector.set_text(mode);
493 _route->instrument_info().set_external_instrument (model, mode);
497 MidiTimeAxisView::midi_view()
499 return dynamic_cast<MidiStreamView*>(_view);
503 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
505 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
506 _midi_controls_box.show ();
508 _midi_controls_box.hide();
511 if (h >= KEYBOARD_MIN_HEIGHT) {
512 if (is_track() && _range_scroomer) {
513 _range_scroomer->show();
515 if (is_track() && _piano_roll_header) {
516 _piano_roll_header->show();
519 if (is_track() && _range_scroomer) {
520 _range_scroomer->hide();
522 if (is_track() && _piano_roll_header) {
523 _piano_roll_header->hide();
527 /* We need to do this after changing visibility of our stuff, as it will
528 eventually trigger a call to Editor::reset_controls_layout_width(),
529 which needs to know if we have just shown or hidden a scroomer /
532 RouteTimeAxisView::set_height (h, m);
536 MidiTimeAxisView::append_extra_display_menu_items ()
538 using namespace Menu_Helpers;
540 MenuList& items = display_menu->items();
543 Menu *range_menu = manage(new Menu);
544 MenuList& range_items = range_menu->items();
545 range_menu->set_name ("ArdourContextMenu");
547 range_items.push_back (
548 MenuElem (_("Show Full Range"),
549 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
550 MidiStreamView::FullRange, true)));
552 range_items.push_back (
553 MenuElem (_("Fit Contents"),
554 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
555 MidiStreamView::ContentsRange, true)));
557 items.push_back (MenuElem (_("Note Range"), *range_menu));
558 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
559 items.push_back (MenuElem (_("Channel Selector"),
560 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
562 items.push_back (MenuElem (_("Select Patch..."),
563 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
565 color_mode_menu = build_color_mode_menu();
566 if (color_mode_menu) {
567 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
570 items.push_back (SeparatorElem ());
574 MidiTimeAxisView::toggle_channel_selector ()
576 if (!_channel_selector) {
577 _channel_selector = new MidiChannelSelectorWindow (midi_track());
579 if (_color_mode == ChannelColors) {
580 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
582 _channel_selector->set_default_channel_color ();
585 _channel_selector->show_all ();
587 _channel_selector->cycle_visibility ();
592 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
594 using namespace Menu_Helpers;
596 /* If we have a controller menu, we need to detach it before
597 RouteTimeAxis::build_automation_action_menu destroys the
598 menu it is attached to. Otherwise GTK destroys
599 controller_menu's gobj, meaning that it can't be reattached
600 below. See bug #3134.
603 if (controller_menu) {
604 detach_menu (*controller_menu);
607 _channel_command_menu_map.clear ();
608 RouteTimeAxisView::build_automation_action_menu (for_selection);
610 MenuList& automation_items = automation_action_menu->items();
612 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
614 if (selected_channels != 0) {
616 automation_items.push_back (SeparatorElem());
618 /* these 2 MIDI "command" types are semantically more like automation
619 than note data, but they are not MIDI controllers. We give them
620 special status in this menu, since they will not show up in the
621 controller list and anyone who actually knows something about MIDI
622 (!) would not expect to find them there.
625 add_channel_command_menu_item (
626 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
627 automation_items.back().set_sensitive (
628 !for_selection || _editor.get_selection().tracks.size() == 1);
629 add_channel_command_menu_item (
630 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
631 automation_items.back().set_sensitive (
632 !for_selection || _editor.get_selection().tracks.size() == 1);
634 /* now all MIDI controllers. Always offer the possibility that we will
635 rebuild the controllers menu since it might need to be updated after
636 a channel mode change or other change. Also detach it first in case
637 it has been used anywhere else.
640 build_controller_menu ();
642 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
644 if (!poly_pressure_menu) {
645 poly_pressure_menu = new Gtk::Menu;
648 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
650 automation_items.back().set_sensitive (
651 !for_selection || _editor.get_selection().tracks.size() == 1);
653 automation_items.push_back (
654 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
655 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
660 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
662 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
664 for (uint8_t chn = 0; chn < 16; chn++) {
665 if (selected_channels & (0x0001 << chn)) {
667 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
668 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
671 menu->set_active (yn);
678 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
680 AutomationType auto_type,
683 using namespace Menu_Helpers;
685 /* count the number of selected channels because we will build a different menu
686 structure if there is more than 1 selected.
689 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
692 for (uint8_t chn = 0; chn < 16; chn++) {
693 if (selected_channels & (0x0001 << chn)) {
702 /* multiple channels - create a submenu, with 1 item per channel */
704 Menu* chn_menu = manage (new Menu);
705 MenuList& chn_items (chn_menu->items());
706 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
708 /* add a couple of items to hide/show all of them */
710 chn_items.push_back (
711 MenuElem (_("Hide all channels"),
712 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
713 false, param_without_channel)));
714 chn_items.push_back (
715 MenuElem (_("Show all channels"),
716 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
717 true, param_without_channel)));
719 for (uint8_t chn = 0; chn < 16; chn++) {
720 if (selected_channels & (0x0001 << chn)) {
722 /* for each selected channel, add a menu item for this controller */
724 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
725 chn_items.push_back (
726 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
727 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
728 fully_qualified_param)));
730 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
731 bool visible = false;
734 if (track->marked_for_display()) {
739 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
740 _channel_command_menu_map[fully_qualified_param] = cmi;
741 cmi->set_active (visible);
745 /* now create an item in the parent menu that has the per-channel list as a submenu */
747 items.push_back (MenuElem (label, *chn_menu));
751 /* just one channel - create a single menu item for this command+channel combination*/
753 for (uint8_t chn = 0; chn < 16; chn++) {
754 if (selected_channels & (0x0001 << chn)) {
756 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
758 CheckMenuElem (label,
759 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
760 fully_qualified_param)));
762 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
763 bool visible = false;
766 if (track->marked_for_display()) {
771 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
772 _channel_command_menu_map[fully_qualified_param] = cmi;
773 cmi->set_active (visible);
775 /* one channel only */
782 /** Add a single menu item for a controller on one channel. */
784 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
786 const std::string& name)
788 using namespace Menu_Helpers;
790 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
791 for (uint8_t chn = 0; chn < 16; chn++) {
792 if (selected_channels & (0x0001 << chn)) {
794 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
795 ctl_items.push_back (
797 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
799 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
800 fully_qualified_param)));
801 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
803 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
804 fully_qualified_param);
806 bool visible = false;
808 if (track->marked_for_display()) {
813 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
814 _controller_menu_map[fully_qualified_param] = cmi;
815 cmi->set_active (visible);
817 /* one channel only */
823 /** Add a submenu with 1 item per channel for a controller on many channels. */
825 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
827 const std::string& name)
829 using namespace Menu_Helpers;
831 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
833 Menu* chn_menu = manage (new Menu);
834 MenuList& chn_items (chn_menu->items());
836 /* add a couple of items to hide/show this controller on all channels */
838 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
839 chn_items.push_back (
840 MenuElem (_("Hide all channels"),
841 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
842 false, param_without_channel)));
843 chn_items.push_back (
844 MenuElem (_("Show all channels"),
845 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
846 true, param_without_channel)));
848 for (uint8_t chn = 0; chn < 16; chn++) {
849 if (selected_channels & (0x0001 << chn)) {
851 /* for each selected channel, add a menu item for this controller */
853 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
854 chn_items.push_back (
855 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
856 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
857 fully_qualified_param)));
859 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
860 fully_qualified_param);
861 bool visible = false;
864 if (track->marked_for_display()) {
869 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
870 _controller_menu_map[fully_qualified_param] = cmi;
871 cmi->set_active (visible);
875 /* add the per-channel menu to the list of controllers, with the name of the controller */
876 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
878 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
881 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
882 MidiTimeAxisView::get_device_mode()
884 using namespace MIDI::Name;
886 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
888 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
891 return device_names->custom_device_mode_by_name(
892 gui_property (X_("midnam-custom-device-mode")));
895 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
896 MidiTimeAxisView::get_device_names()
898 using namespace MIDI::Name;
900 const std::string model = gui_property (X_("midnam-model-name"));
902 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
903 .document_by_model(model);
905 return midnam->master_device_names(model);
907 return boost::shared_ptr<MasterDeviceNames>();
912 MidiTimeAxisView::build_controller_menu ()
914 using namespace Menu_Helpers;
916 if (controller_menu) {
917 /* it exists and has not been invalidated by a channel mode change */
921 controller_menu = new Menu; // explicitly managed by us
922 MenuList& items (controller_menu->items());
924 /* create several "top level" menu items for sets of controllers (16 at a
925 time), and populate each one with a submenu for each controller+channel
926 combination covering the currently selected channels for this track
929 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
931 /* count the number of selected channels because we will build a different menu
932 structure if there is more than 1 selected.
936 for (uint8_t chn = 0; chn < 16; chn++) {
937 if (selected_channels & (0x0001 << chn)) {
944 using namespace MIDI::Name;
945 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
947 if (device_names && !device_names->controls().empty()) {
948 /* Controllers names available in midnam file, generate fancy menu */
949 unsigned n_items = 0;
950 unsigned n_groups = 0;
952 /* TODO: This is not correct, should look up the currently applicable ControlNameList
953 and only build a menu for that one. */
954 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
955 l != device_names->controls().end(); ++l) {
956 boost::shared_ptr<ControlNameList> name_list = l->second;
957 Menu* ctl_menu = NULL;
959 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
960 c != name_list->controls().end();) {
961 const uint16_t ctl = c->second->number();
962 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
963 /* Skip bank select controllers since they're handled specially */
965 /* Create a new submenu */
966 ctl_menu = manage (new Menu);
969 MenuList& ctl_items (ctl_menu->items());
971 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
973 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
978 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
979 /* Submenu has 16 items or we're done, add it to controller menu and reset */
981 MenuElem(string_compose(_("Controllers %1-%2"),
982 (16 * n_groups), (16 * n_groups) + n_items - 1),
991 /* No controllers names, generate generic numeric menu */
992 for (int i = 0; i < 127; i += 16) {
993 Menu* ctl_menu = manage (new Menu);
994 MenuList& ctl_items (ctl_menu->items());
996 for (int ctl = i; ctl < i+16; ++ctl) {
997 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
998 /* Skip bank select controllers since they're handled specially */
1003 add_multi_channel_controller_item(
1004 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1006 add_single_channel_controller_item(
1007 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1011 /* Add submenu for this block of controllers to controller menu */
1013 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1020 MidiTimeAxisView::build_note_mode_menu()
1022 using namespace Menu_Helpers;
1024 Menu* mode_menu = manage (new Menu);
1025 MenuList& items = mode_menu->items();
1026 mode_menu->set_name ("ArdourContextMenu");
1028 RadioMenuItem::Group mode_group;
1030 RadioMenuElem (mode_group,_("Sustained"),
1031 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1033 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1034 _note_mode_item->set_active(_note_mode == Sustained);
1037 RadioMenuElem (mode_group, _("Percussive"),
1038 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1039 Percussive, true)));
1040 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1041 _percussion_mode_item->set_active(_note_mode == Percussive);
1047 MidiTimeAxisView::build_color_mode_menu()
1049 using namespace Menu_Helpers;
1051 Menu* mode_menu = manage (new Menu);
1052 MenuList& items = mode_menu->items();
1053 mode_menu->set_name ("ArdourContextMenu");
1055 RadioMenuItem::Group mode_group;
1057 RadioMenuElem (mode_group, _("Meter Colors"),
1058 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1059 MeterColors, false, true, true)));
1060 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1061 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1064 RadioMenuElem (mode_group, _("Channel Colors"),
1065 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1066 ChannelColors, false, true, true)));
1067 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1068 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1071 RadioMenuElem (mode_group, _("Track Color"),
1072 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1073 TrackColor, false, true, true)));
1074 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1075 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1081 MidiTimeAxisView::send_patch_change ()
1087 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
1088 PatchChangeDialog d (0, 0, empty, _route->instrument_info(), Gtk::Stock::OK);
1090 if (d.run() == RESPONSE_CANCEL) {
1093 Evoral::PatchChange<Evoral::Beats> p (d.patch ());
1095 uint8_t chn = p.channel();
1097 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1098 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1099 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1101 if (!bank_msb || ! bank_lsb || !program) {
1105 bank_msb->set_value (p.bank_msb (), Controllable::NoGroup);
1106 bank_lsb->set_value (p.bank_lsb (), Controllable::NoGroup);
1107 program->set_value (p.program () , Controllable::NoGroup);
1111 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1113 if (apply_to_selection) {
1114 _editor.get_selection().tracks.foreach_midi_time_axis (
1115 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1117 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1119 midi_track()->set_note_mode(mode);
1120 set_gui_property ("note-mode", enum_2_string(_note_mode));
1121 _view->redisplay_track();
1127 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1129 if (apply_to_selection) {
1130 _editor.get_selection().tracks.foreach_midi_time_axis (
1131 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1133 if (_color_mode == mode && !force) {
1137 if (_channel_selector) {
1138 if (mode == ChannelColors) {
1139 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1141 _channel_selector->set_default_channel_color();
1146 set_gui_property ("color-mode", enum_2_string(_color_mode));
1148 _view->redisplay_track();
1154 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1156 if (apply_to_selection) {
1157 _editor.get_selection().tracks.foreach_midi_time_axis (
1158 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1160 if (!_ignore_signals) {
1161 midi_view()->set_note_range(range);
1167 MidiTimeAxisView::update_range()
1172 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1174 using namespace MIDI::Name;
1176 if (apply_to_selection) {
1177 _editor.get_selection().tracks.foreach_midi_time_axis (
1178 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1181 // Show existing automation
1182 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1184 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1185 create_automation_child(*i, true);
1188 // Show automation for all controllers named in midnam file
1189 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1190 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1191 device_names && !device_names->controls().empty()) {
1192 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1193 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1194 for (uint32_t chn = 0; chn < 16; ++chn) {
1195 if ((selected_channels & (0x0001 << chn)) == 0) {
1196 // Channel not in use
1200 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1206 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1207 chan_names->control_list_name());
1208 if (!control_names) {
1212 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1213 c != control_names->controls().end();
1215 const uint16_t ctl = c->second->number();
1216 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1217 /* Skip bank select controllers since they're handled specially */
1218 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1219 create_automation_child(param, true);
1226 RouteTimeAxisView::show_all_automation ();
1231 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1233 if (apply_to_selection) {
1234 _editor.get_selection().tracks.foreach_midi_time_axis (
1235 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1238 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1240 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1241 create_automation_child (*i, true);
1245 RouteTimeAxisView::show_existing_automation ();
1249 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1252 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1254 if (param.type() == NullAutomation) {
1258 AutomationTracks::iterator existing = _automation_tracks.find (param);
1260 if (existing != _automation_tracks.end()) {
1262 /* automation track created because we had existing data for
1263 * the processor, but visibility may need to be controlled
1264 * since it will have been set visible by default.
1267 existing->second->set_marked_for_display (show);
1276 boost::shared_ptr<AutomationTimeAxisView> track;
1277 boost::shared_ptr<AutomationControl> control;
1280 switch (param.type()) {
1282 case GainAutomation:
1283 create_gain_automation_child (param, show);
1286 case MuteAutomation:
1287 create_mute_automation_child (param, show);
1290 case PluginAutomation:
1291 /* handled elsewhere */
1294 case MidiCCAutomation:
1295 case MidiPgmChangeAutomation:
1296 case MidiPitchBenderAutomation:
1297 case MidiChannelPressureAutomation:
1298 case MidiSystemExclusiveAutomation:
1299 /* These controllers are region "automation" - they are owned
1300 * by regions (and their MidiModels), not by the track. As a
1301 * result there is no AutomationList/Line for the track, but we create
1302 * a controller for the user to write immediate events, so the editor
1303 * can act as a control surface for the present MIDI controllers.
1305 * TODO: Record manipulation of the controller to regions?
1308 control = _route->automation_control(param, true);
1309 track.reset (new AutomationTimeAxisView (
1312 control ? _route : boost::shared_ptr<Automatable> (),
1319 _route->describe_parameter(param)));
1322 _view->foreach_regionview (
1323 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1326 add_automation_child (param, track, show);
1328 reshow_selection (_editor.get_selection().time);
1333 case PanWidthAutomation:
1334 case PanElevationAutomation:
1335 case PanAzimuthAutomation:
1336 ensure_pan_views (show);
1340 error << "MidiTimeAxisView: unknown automation child "
1341 << EventTypeMap::instance().to_symbol(param) << endmsg;
1346 MidiTimeAxisView::route_active_changed ()
1348 RouteUI::route_active_changed ();
1349 update_control_names();
1353 MidiTimeAxisView::update_control_names ()
1356 if (_route->active()) {
1357 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1358 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1360 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1361 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1363 } else { // MIDI bus (which doesn't exist yet..)
1364 if (_route->active()) {
1365 controls_base_selected_name = "BusControlsBaseSelected";
1366 controls_base_unselected_name = "BusControlsBaseUnselected";
1368 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1369 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1374 controls_ebox.set_name (controls_base_selected_name);
1375 time_axis_frame.set_name (controls_base_selected_name);
1377 controls_ebox.set_name (controls_base_unselected_name);
1378 time_axis_frame.set_name (controls_base_unselected_name);
1383 MidiTimeAxisView::set_note_selection (uint8_t note)
1385 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1387 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1389 if (_view->num_selected_regionviews() == 0) {
1390 _view->foreach_regionview (
1391 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1394 _view->foreach_selected_regionview (
1395 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1399 _editor.commit_reversible_selection_op();
1403 MidiTimeAxisView::add_note_selection (uint8_t note)
1405 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1407 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1409 if (_view->num_selected_regionviews() == 0) {
1410 _view->foreach_regionview (
1411 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1414 _view->foreach_selected_regionview (
1415 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1419 _editor.commit_reversible_selection_op();
1423 MidiTimeAxisView::extend_note_selection (uint8_t note)
1425 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1427 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1429 if (_view->num_selected_regionviews() == 0) {
1430 _view->foreach_regionview (
1431 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1434 _view->foreach_selected_regionview (
1435 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1439 _editor.commit_reversible_selection_op();
1443 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1445 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1447 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1449 if (_view->num_selected_regionviews() == 0) {
1450 _view->foreach_regionview (
1451 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1454 _view->foreach_selected_regionview (
1455 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1459 _editor.commit_reversible_selection_op();
1463 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1465 _view->foreach_regionview (
1466 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1470 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1472 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1476 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1478 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1482 MidiTimeAxisView::extend_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, true);
1488 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1490 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1494 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1496 Evoral::Sequence<Evoral::Beats>::Notes selected;
1497 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1499 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1501 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1502 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1503 notes.insert (*sel_it);
1506 if (!notes.empty()) {
1507 selection.push_back (make_pair ((rv)->region()->id(), notes));
1512 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1514 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1518 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1519 bool changed = false;
1523 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1525 for (uint32_t chn = 0; chn < 16; ++chn) {
1526 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1527 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1533 if ((selected_channels & (0x0001 << chn)) == 0) {
1534 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1535 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1537 changed = track->set_marked_for_display (false) || changed;
1539 changed = track->set_marked_for_display (true) || changed;
1546 /* TODO: Bender, Pressure */
1548 /* invalidate the controller menu, so that we rebuild it next time */
1549 _controller_menu_map.clear ();
1550 delete controller_menu;
1551 controller_menu = 0;
1559 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1561 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1566 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1567 if (i != _controller_menu_map.end()) {
1571 i = _channel_command_menu_map.find (param);
1572 if (i != _channel_command_menu_map.end()) {
1579 boost::shared_ptr<MidiRegion>
1580 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1582 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1583 MusicFrame pos (f, 0);
1586 real_editor->begin_reversible_command (Operations::create_region);
1588 playlist()->clear_changes ();
1590 real_editor->snap_to (pos, RoundNearest);
1592 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1595 plist.add (ARDOUR::Properties::start, 0);
1596 plist.add (ARDOUR::Properties::length, length);
1597 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1599 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1600 /* sets beat position */
1601 region->set_position (pos.frame, pos.division);
1602 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1603 _session->add_command (new StatefulDiffCommand (playlist()));
1606 real_editor->commit_reversible_command ();
1609 return boost::dynamic_pointer_cast<MidiRegion>(region);
1613 MidiTimeAxisView::ensure_step_editor ()
1615 if (!_step_editor) {
1616 _step_editor = new StepEditor (_editor, midi_track(), *this);
1621 MidiTimeAxisView::start_step_editing ()
1623 ensure_step_editor ();
1624 _step_editor->start_step_editing ();
1628 MidiTimeAxisView::stop_step_editing ()
1631 _step_editor->stop_step_editing ();
1635 /** @return channel (counted from 0) to add an event to, based on the current setting
1636 * of the channel selector.
1639 MidiTimeAxisView::get_channel_for_add () const
1641 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1643 uint8_t channel = 0;
1645 /* pick the highest selected channel, unless all channels are selected,
1646 which is interpreted to mean channel 1 (zero)
1649 for (uint16_t i = 0; i < 16; ++i) {
1650 if (chn_mask & (1<<i)) {
1656 if (chn_cnt == 16) {
1664 MidiTimeAxisView::note_range_changed ()
1666 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1667 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1671 MidiTimeAxisView::contents_height_changed ()
1673 _range_scroomer->queue_resize ();
1677 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1679 if (!_editor.internal_editing()) {
1680 // Non-internal paste, paste regions like any other route
1681 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1684 return midi_view()->paste(pos, selection, ctx, sub_num);