2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/whitespace.h"
31 #include "pbd/basename.h"
32 #include "pbd/enumwriter.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/stateful_diff_command.h"
36 #include "gtkmm2ext/gtk_ui.h"
37 #include "gtkmm2ext/selector.h"
38 #include "gtkmm2ext/bindable_button.h"
39 #include "gtkmm2ext/utils.h"
41 #include "ardour/file_source.h"
42 #include "ardour/midi_playlist.h"
43 #include "ardour/midi_diskstream.h"
44 #include "ardour/midi_patch_manager.h"
45 #include "ardour/midi_source.h"
46 #include "ardour/processor.h"
47 #include "ardour/ladspa_plugin.h"
48 #include "ardour/location.h"
49 #include "ardour/playlist.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/session.h"
52 #include "ardour/session_playlist.h"
53 #include "ardour/tempo.h"
54 #include "ardour/utils.h"
56 #include "midi++/names.h"
58 #include "add_midi_cc_track_dialog.h"
59 #include "ardour_ui.h"
60 #include "automation_line.h"
61 #include "automation_time_axis.h"
62 #include "canvas-note-event.h"
63 #include "canvas_impl.h"
64 #include "crossfade_view.h"
67 #include "ghostregion.h"
68 #include "gui_thread.h"
70 #include "midi_scroomer.h"
71 #include "midi_streamview.h"
72 #include "midi_region_view.h"
73 #include "midi_time_axis.h"
74 #include "piano_roll_header.h"
75 #include "playlist_selector.h"
76 #include "plugin_selector.h"
77 #include "plugin_ui.h"
78 #include "point_selection.h"
80 #include "region_view.h"
81 #include "rgb_macros.h"
82 #include "selection.h"
83 #include "step_editor.h"
84 #include "simplerect.h"
87 #include "ardour/midi_track.h"
91 using namespace ARDOUR;
94 using namespace Gtkmm2ext;
95 using namespace Editing;
97 // Minimum height at which a control is displayed
98 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
99 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
101 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
102 boost::shared_ptr<Route> rt, Canvas& canvas)
103 : AxisView(sess) // virtually inherited
104 , RouteTimeAxisView(ed, sess, rt, canvas)
105 , _ignore_signals(false)
107 , _piano_roll_header(0)
108 , _note_mode(Sustained)
110 , _percussion_mode_item(0)
111 , _color_mode(MeterColors)
112 , _meter_color_mode_item(0)
113 , _channel_color_mode_item(0)
114 , _track_color_mode_item(0)
115 , _step_edit_item (0)
116 , _midi_thru_item (0)
117 , default_channel_menu (0)
118 , controller_menu (0)
120 subplugin_menu.set_name ("ArdourContextMenu");
122 _view = new MidiStreamView (*this);
124 ignore_toggle = false;
126 mute_button->set_active (false);
127 solo_button->set_active (false);
129 if (is_midi_track()) {
130 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
131 _note_mode = midi_track()->note_mode();
132 } else { // MIDI bus (which doesn't exist yet..)
133 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
136 /* map current state of the route */
138 processors_changed (RouteProcessorChange ());
142 set_state (*xml_node, Stateful::loading_state_version);
144 _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
147 _piano_roll_header = new PianoRollHeader(*midi_view());
149 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
150 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
151 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
153 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
155 controls_hbox.pack_start(*_range_scroomer);
156 controls_hbox.pack_start(*_piano_roll_header);
158 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
159 controls_base_selected_name = "MidiTrackControlsBaseSelected";
160 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
162 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
164 /* ask for notifications of any new RegionViews */
165 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
170 HBox* midi_controls_hbox = manage(new HBox());
172 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
174 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
175 for (; m != patch_manager.all_models().end(); ++m) {
176 _model_selector.append_text(m->c_str());
179 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
181 _custom_device_mode_selector.signal_changed().connect(
182 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
184 // TODO: persist the choice
185 // this initializes the comboboxes and sends out the signal
186 _model_selector.set_active(0);
188 midi_controls_hbox->pack_start(_channel_selector, true, false);
189 if (!patch_manager.all_models().empty()) {
190 _midi_controls_box.pack_start(_model_selector, true, false);
191 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
194 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
196 controls_vbox.pack_start(_midi_controls_box, false, false);
198 // restore channel selector settings
199 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
200 _channel_selector.mode_changed.connect(
201 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
202 _channel_selector.mode_changed.connect(
203 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
206 if ((prop = xml_node->property ("color-mode")) != 0) {
207 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
208 if (_color_mode == ChannelColors) {
209 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
213 if ((prop = xml_node->property ("note-mode")) != 0) {
214 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
215 if (_percussion_mode_item) {
216 _percussion_mode_item->set_active (_note_mode == Percussive);
221 MidiTimeAxisView::~MidiTimeAxisView ()
223 delete _piano_roll_header;
224 _piano_roll_header = 0;
226 delete _range_scroomer;
229 delete controller_menu;
234 MidiTimeAxisView::check_step_edit ()
236 _step_editor->check_step_edit ();
240 MidiTimeAxisView::model_changed()
242 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
243 .custom_device_mode_names_by_model(_model_selector.get_active_text());
245 _custom_device_mode_selector.clear_items();
247 for (std::list<std::string>::const_iterator i = device_modes.begin();
248 i != device_modes.end(); ++i) {
249 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
250 _custom_device_mode_selector.append_text(*i);
253 _custom_device_mode_selector.set_active(0);
256 void MidiTimeAxisView::custom_device_mode_changed()
258 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
259 _custom_device_mode_selector.get_active_text());
263 MidiTimeAxisView::midi_view()
265 return dynamic_cast<MidiStreamView*>(_view);
269 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
272 xml_node->add_property ("shown-editor", "yes");
274 guint32 ret = TimeAxisView::show_at (y, nth, parent);
279 MidiTimeAxisView::hide ()
282 xml_node->add_property ("shown-editor", "no");
284 TimeAxisView::hide ();
288 MidiTimeAxisView::set_height (uint32_t h)
290 RouteTimeAxisView::set_height (h);
292 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
293 _midi_controls_box.show_all ();
295 _midi_controls_box.hide();
298 if (height >= KEYBOARD_MIN_HEIGHT) {
299 if (is_track() && _range_scroomer)
300 _range_scroomer->show();
301 if (is_track() && _piano_roll_header)
302 _piano_roll_header->show();
304 if (is_track() && _range_scroomer)
305 _range_scroomer->hide();
306 if (is_track() && _piano_roll_header)
307 _piano_roll_header->hide();
312 MidiTimeAxisView::append_extra_display_menu_items ()
314 using namespace Menu_Helpers;
316 MenuList& items = display_menu->items();
319 Menu *range_menu = manage(new Menu);
320 MenuList& range_items = range_menu->items();
321 range_menu->set_name ("ArdourContextMenu");
323 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
324 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
325 MidiStreamView::FullRange)));
327 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
328 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
329 MidiStreamView::ContentsRange)));
331 items.push_back (MenuElem (_("Note range"), *range_menu));
332 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
333 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
335 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
336 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
340 MidiTimeAxisView::build_def_channel_menu ()
342 using namespace Menu_Helpers;
344 default_channel_menu = manage (new Menu ());
346 uint8_t defchn = midi_track()->default_channel();
347 MenuList& def_channel_items = default_channel_menu->items();
349 RadioMenuItem::Group dc_group;
351 for (int i = 0; i < 16; ++i) {
353 snprintf (buf, sizeof (buf), "%d", i+1);
355 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
356 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
357 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
358 item->set_active ((i == defchn));
361 return default_channel_menu;
365 MidiTimeAxisView::set_default_channel (int chn)
367 midi_track()->set_default_channel (chn);
371 MidiTimeAxisView::toggle_midi_thru ()
373 if (!_midi_thru_item) {
377 bool view_yn = _midi_thru_item->get_active();
378 if (view_yn != midi_track()->midi_thru()) {
379 midi_track()->set_midi_thru (view_yn);
384 MidiTimeAxisView::build_automation_action_menu ()
386 using namespace Menu_Helpers;
388 /* If we have a controller menu, we need to detach it before
389 RouteTimeAxis::build_automation_action_menu destroys the
390 menu it is attached to. Otherwise GTK destroys
391 controller_menu's gobj, meaning that it can't be reattached
392 below. See bug #3134.
395 if (controller_menu) {
396 detach_menu (*controller_menu);
399 _channel_command_menu_map.clear ();
400 RouteTimeAxisView::build_automation_action_menu ();
402 MenuList& automation_items = automation_action_menu->items();
404 uint16_t selected_channels = _channel_selector.get_selected_channels();
406 if (selected_channels != 0) {
408 automation_items.push_back (SeparatorElem());
410 /* these 3 MIDI "command" types are semantically more like automation than note data,
411 but they are not MIDI controllers. We give them special status in this menu, since
412 they will not show up in the controller list and anyone who actually knows
413 something about MIDI (!) would not expect to find them there.
416 add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, 0);
417 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
418 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
420 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
421 since it might need to be updated after a channel mode change or other change. Also detach it
422 first in case it has been used anywhere else.
425 build_controller_menu ();
427 automation_items.push_back (SeparatorElem());
428 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
430 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
436 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
438 uint16_t selected_channels = _channel_selector.get_selected_channels();
440 for (uint8_t chn = 0; chn < 16; chn++) {
441 if (selected_channels & (0x0001 << chn)) {
443 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
444 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
447 menu->set_active (yn);
454 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
456 using namespace Menu_Helpers;
458 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
461 uint16_t selected_channels = _channel_selector.get_selected_channels();
464 for (uint8_t chn = 0; chn < 16; chn++) {
465 if (selected_channels & (0x0001 << chn)) {
474 /* multiple channels - create a submenu, with 1 item per channel */
476 Menu* chn_menu = manage (new Menu);
477 MenuList& chn_items (chn_menu->items());
478 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
480 /* add a couple of items to hide/show all of them */
482 chn_items.push_back (MenuElem (_("Hide all channels"),
483 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
484 false, param_without_channel)));
485 chn_items.push_back (MenuElem (_("Show all channels"),
486 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
487 true, param_without_channel)));
489 for (uint8_t chn = 0; chn < 16; chn++) {
490 if (selected_channels & (0x0001 << chn)) {
492 /* for each selected channel, add a menu item for this controller */
494 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
495 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
496 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
497 fully_qualified_param)));
499 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
500 bool visible = false;
503 if (track->marked_for_display()) {
508 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
509 _channel_command_menu_map[fully_qualified_param] = cmi;
510 cmi->set_active (visible);
514 /* now create an item in the parent menu that has the per-channel list as a submenu */
516 items.push_back (MenuElem (label, *chn_menu));
520 /* just one channel - create a single menu item for this command+channel combination*/
522 for (uint8_t chn = 0; chn < 16; chn++) {
523 if (selected_channels & (0x0001 << chn)) {
525 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
526 items.push_back (CheckMenuElem (label,
527 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
528 fully_qualified_param)));
530 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
531 bool visible = false;
534 if (track->marked_for_display()) {
539 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
540 _channel_command_menu_map[fully_qualified_param] = cmi;
541 cmi->set_active (visible);
543 /* one channel only */
551 MidiTimeAxisView::build_controller_menu ()
553 using namespace Menu_Helpers;
555 if (controller_menu) {
556 /* it exists and has not been invalidated by a channel mode change, so just return it */
560 controller_menu = new Menu; // explicitly managed by us
561 MenuList& items (controller_menu->items());
563 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
564 for each controller+channel combination covering the currently selected channels for this track
567 uint16_t selected_channels = _channel_selector.get_selected_channels();
569 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
574 for (uint8_t chn = 0; chn < 16; chn++) {
575 if (selected_channels & (0x0001 << chn)) {
582 /* loop over all 127 MIDI controllers, in groups of 16 */
584 for (int i = 0; i < 127; i += 16) {
586 Menu* ctl_menu = manage (new Menu);
587 MenuList& ctl_items (ctl_menu->items());
590 /* for each controller, consider whether to create a submenu or a single item */
592 for (int ctl = i; ctl < i+16; ++ctl) {
596 /* multiple channels - create a submenu, with 1 item per channel */
598 Menu* chn_menu = manage (new Menu);
599 MenuList& chn_items (chn_menu->items());
601 /* add a couple of items to hide/show this controller on all channels */
603 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
604 chn_items.push_back (MenuElem (_("Hide all channels"),
605 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
606 false, param_without_channel)));
607 chn_items.push_back (MenuElem (_("Show all channels"),
608 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
609 true, param_without_channel)));
611 for (uint8_t chn = 0; chn < 16; chn++) {
612 if (selected_channels & (0x0001 << chn)) {
614 /* for each selected channel, add a menu item for this controller */
616 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
617 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
618 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
619 fully_qualified_param)));
621 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
622 bool visible = false;
625 if (track->marked_for_display()) {
630 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
631 _controller_menu_map[fully_qualified_param] = cmi;
632 cmi->set_active (visible);
636 /* add the per-channel menu to the list of controllers, with the name of the controller */
637 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
638 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
642 /* just one channel - create a single menu item for this ctl+channel combination*/
644 for (uint8_t chn = 0; chn < 16; chn++) {
645 if (selected_channels & (0x0001 << chn)) {
647 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
648 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
649 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
650 fully_qualified_param)));
652 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
653 bool visible = false;
656 if (track->marked_for_display()) {
661 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
662 _controller_menu_map[fully_qualified_param] = cmi;
663 cmi->set_active (visible);
665 /* one channel only */
672 /* add the menu for this block of controllers to the overall controller menu */
674 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
679 MidiTimeAxisView::build_note_mode_menu()
681 using namespace Menu_Helpers;
683 Menu* mode_menu = manage (new Menu);
684 MenuList& items = mode_menu->items();
685 mode_menu->set_name ("ArdourContextMenu");
687 RadioMenuItem::Group mode_group;
688 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
689 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
690 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
691 _note_mode_item->set_active(_note_mode == Sustained);
693 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
694 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
695 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
696 _percussion_mode_item->set_active(_note_mode == Percussive);
702 MidiTimeAxisView::build_color_mode_menu()
704 using namespace Menu_Helpers;
706 Menu* mode_menu = manage (new Menu);
707 MenuList& items = mode_menu->items();
708 mode_menu->set_name ("ArdourContextMenu");
710 RadioMenuItem::Group mode_group;
711 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
712 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
713 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
714 _meter_color_mode_item->set_active(_color_mode == MeterColors);
716 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
717 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
718 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
719 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
721 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
722 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
723 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
724 _channel_color_mode_item->set_active(_color_mode == TrackColor);
730 MidiTimeAxisView::set_note_mode(NoteMode mode)
732 if (_note_mode != mode || midi_track()->note_mode() != mode) {
734 midi_track()->set_note_mode(mode);
735 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
736 _view->redisplay_track();
741 MidiTimeAxisView::set_color_mode(ColorMode mode)
743 if (_color_mode != mode) {
744 if (mode == ChannelColors) {
745 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
747 _channel_selector.set_default_channel_color();
751 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
752 _view->redisplay_track();
757 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
759 if (!_ignore_signals)
760 midi_view()->set_note_range(range);
765 MidiTimeAxisView::update_range()
767 MidiGhostRegion* mgr;
769 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
770 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
777 MidiTimeAxisView::show_all_automation ()
780 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
782 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
783 create_automation_child(*i, true);
787 RouteTimeAxisView::show_all_automation ();
791 MidiTimeAxisView::show_existing_automation ()
794 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
796 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
797 create_automation_child(*i, true);
801 RouteTimeAxisView::show_existing_automation ();
804 /** Create an automation track for the given parameter (pitch bend, channel pressure).
807 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
809 /* These controllers are region "automation", so we do not create
810 * an AutomationList/Line for the track */
812 if (param.type() == NullAutomation) {
813 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
817 AutomationTracks::iterator existing = _automation_tracks.find (param);
818 if (existing != _automation_tracks.end()) {
822 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
826 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
827 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
832 _route->describe_parameter(param)));
834 add_automation_child (param, track, show);
839 MidiTimeAxisView::route_active_changed ()
841 RouteUI::route_active_changed ();
844 if (_route->active()) {
845 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
846 controls_base_selected_name = "MidiTrackControlsBaseSelected";
847 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
849 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
850 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
851 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
857 if (_route->active()) {
858 controls_ebox.set_name ("BusControlsBaseUnselected");
859 controls_base_selected_name = "BusControlsBaseSelected";
860 controls_base_unselected_name = "BusControlsBaseUnselected";
862 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
863 controls_base_selected_name = "BusControlsBaseInactiveSelected";
864 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
872 MidiTimeAxisView::add_note_selection (uint8_t note)
874 if (!_editor.internal_editing()) {
878 uint16_t chn_mask = _channel_selector.get_selected_channels();
880 if (_view->num_selected_regionviews() == 0) {
881 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
883 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
888 MidiTimeAxisView::extend_note_selection (uint8_t note)
890 if (!_editor.internal_editing()) {
894 uint16_t chn_mask = _channel_selector.get_selected_channels();
896 if (_view->num_selected_regionviews() == 0) {
897 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
899 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
904 MidiTimeAxisView::toggle_note_selection (uint8_t note)
906 if (!_editor.internal_editing()) {
910 uint16_t chn_mask = _channel_selector.get_selected_channels();
912 if (_view->num_selected_regionviews() == 0) {
913 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
915 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
920 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
922 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
926 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
928 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
932 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
934 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
938 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
940 /* hide all automation tracks that use the wrong channel(s) and show all those that use
944 uint16_t selected_channels = _channel_selector.get_selected_channels();
945 bool changed = false;
949 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
951 for (uint32_t chn = 0; chn < 16; ++chn) {
952 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
953 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
959 if ((selected_channels & (0x0001 << chn)) == 0) {
960 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
961 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
963 changed = track->set_visibility (false) || changed;
965 changed = track->set_visibility (true) || changed;
972 /* TODO: Bender, PgmChange, Pressure */
974 /* invalidate the controller menu, so that we rebuilt it next time */
975 _controller_menu_map.clear ();
976 delete controller_menu;
980 _route->gui_changed ("track_height", this);
985 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
987 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
992 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
993 if (i != _controller_menu_map.end()) {
997 i = _channel_command_menu_map.find (param);
998 if (i != _channel_command_menu_map.end()) {
1005 boost::shared_ptr<MidiRegion>
1006 MidiTimeAxisView::add_region (framepos_t pos)
1008 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1010 real_editor->begin_reversible_command (_("create region"));
1011 playlist()->clear_history ();
1013 real_editor->snap_to (pos, 0);
1014 const Meter& m = _session->tempo_map().meter_at(pos);
1015 const Tempo& t = _session->tempo_map().tempo_at(pos);
1016 double length = floor (m.frames_per_bar(t, _session->frame_rate()));
1018 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1019 view()->trackview().track()->name());
1022 plist.add (ARDOUR::Properties::start, 0);
1023 plist.add (ARDOUR::Properties::length, length);
1024 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1026 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1028 playlist()->add_region (region, pos);
1029 _session->add_command (new StatefulDiffCommand (playlist()));
1031 real_editor->commit_reversible_command();
1033 return boost::dynamic_pointer_cast<MidiRegion>(region);
1037 MidiTimeAxisView::start_step_editing ()
1039 if (!_step_editor) {
1040 _step_editor = new StepEditor (_editor, midi_track(), *this);
1043 _step_editor->start_step_editing ();
1047 MidiTimeAxisView::stop_step_editing ()
1050 _step_editor->stop_step_editing ();