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)
121 subplugin_menu.set_name ("ArdourContextMenu");
123 _view = new MidiStreamView (*this);
125 ignore_toggle = false;
127 mute_button->set_active (false);
128 solo_button->set_active (false);
130 if (is_midi_track()) {
131 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
132 _note_mode = midi_track()->note_mode();
133 } else { // MIDI bus (which doesn't exist yet..)
134 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
137 /* map current state of the route */
139 processors_changed (RouteProcessorChange ());
143 set_state (*xml_node, Stateful::loading_state_version);
145 _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
148 _piano_roll_header = new PianoRollHeader(*midi_view());
150 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
151 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
152 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
154 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
156 controls_hbox.pack_start(*_range_scroomer);
157 controls_hbox.pack_start(*_piano_roll_header);
159 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
160 controls_base_selected_name = "MidiTrackControlsBaseSelected";
161 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
163 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
165 /* ask for notifications of any new RegionViews */
166 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
168 if (!_editor.have_idled()) {
169 /* first idle will do what we need */
175 HBox* midi_controls_hbox = manage(new HBox());
177 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
179 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
180 for (; m != patch_manager.all_models().end(); ++m) {
181 _model_selector.append_text(m->c_str());
184 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
186 _custom_device_mode_selector.signal_changed().connect(
187 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
189 // TODO: persist the choice
190 // this initializes the comboboxes and sends out the signal
191 _model_selector.set_active(0);
193 midi_controls_hbox->pack_start(_channel_selector, true, false);
194 if (!patch_manager.all_models().empty()) {
195 _midi_controls_box.pack_start(_model_selector, true, false);
196 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
199 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
201 controls_vbox.pack_start(_midi_controls_box, false, false);
203 // restore channel selector settings
204 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
205 _channel_selector.mode_changed.connect(
206 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
207 _channel_selector.mode_changed.connect(
208 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
211 if ((prop = xml_node->property ("color-mode")) != 0) {
212 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
213 if (_color_mode == ChannelColors) {
214 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
218 if ((prop = xml_node->property ("note-mode")) != 0) {
219 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
220 if (_percussion_mode_item) {
221 _percussion_mode_item->set_active (_note_mode == Percussive);
227 MidiTimeAxisView::first_idle ()
234 MidiTimeAxisView::~MidiTimeAxisView ()
236 delete _piano_roll_header;
237 _piano_roll_header = 0;
239 delete _range_scroomer;
242 delete controller_menu;
247 MidiTimeAxisView::check_step_edit ()
249 _step_editor->check_step_edit ();
253 MidiTimeAxisView::model_changed()
255 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
256 .custom_device_mode_names_by_model(_model_selector.get_active_text());
258 _custom_device_mode_selector.clear_items();
260 for (std::list<std::string>::const_iterator i = device_modes.begin();
261 i != device_modes.end(); ++i) {
262 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
263 _custom_device_mode_selector.append_text(*i);
266 _custom_device_mode_selector.set_active(0);
269 void MidiTimeAxisView::custom_device_mode_changed()
271 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
272 _custom_device_mode_selector.get_active_text());
276 MidiTimeAxisView::midi_view()
278 return dynamic_cast<MidiStreamView*>(_view);
282 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
285 xml_node->add_property ("shown-editor", "yes");
287 guint32 ret = TimeAxisView::show_at (y, nth, parent);
292 MidiTimeAxisView::hide ()
295 xml_node->add_property ("shown-editor", "no");
297 TimeAxisView::hide ();
301 MidiTimeAxisView::set_height (uint32_t h)
303 RouteTimeAxisView::set_height (h);
305 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
306 _midi_controls_box.show_all ();
308 _midi_controls_box.hide();
311 if (height >= KEYBOARD_MIN_HEIGHT) {
312 if (is_track() && _range_scroomer)
313 _range_scroomer->show();
314 if (is_track() && _piano_roll_header)
315 _piano_roll_header->show();
317 if (is_track() && _range_scroomer)
318 _range_scroomer->hide();
319 if (is_track() && _piano_roll_header)
320 _piano_roll_header->hide();
325 MidiTimeAxisView::append_extra_display_menu_items ()
327 using namespace Menu_Helpers;
329 MenuList& items = display_menu->items();
332 Menu *range_menu = manage(new Menu);
333 MenuList& range_items = range_menu->items();
334 range_menu->set_name ("ArdourContextMenu");
336 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
337 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
338 MidiStreamView::FullRange)));
340 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
341 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
342 MidiStreamView::ContentsRange)));
344 items.push_back (MenuElem (_("Note range"), *range_menu));
345 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
346 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
348 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
349 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
353 MidiTimeAxisView::build_def_channel_menu ()
355 using namespace Menu_Helpers;
357 default_channel_menu = manage (new Menu ());
359 uint8_t defchn = midi_track()->default_channel();
360 MenuList& def_channel_items = default_channel_menu->items();
362 RadioMenuItem::Group dc_group;
364 for (int i = 0; i < 16; ++i) {
366 snprintf (buf, sizeof (buf), "%d", i+1);
368 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
369 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
370 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
371 item->set_active ((i == defchn));
374 return default_channel_menu;
378 MidiTimeAxisView::set_default_channel (int chn)
380 midi_track()->set_default_channel (chn);
384 MidiTimeAxisView::toggle_midi_thru ()
386 if (!_midi_thru_item) {
390 bool view_yn = _midi_thru_item->get_active();
391 if (view_yn != midi_track()->midi_thru()) {
392 midi_track()->set_midi_thru (view_yn);
397 MidiTimeAxisView::build_automation_action_menu ()
399 using namespace Menu_Helpers;
401 /* If we have a controller menu, we need to detach it before
402 RouteTimeAxis::build_automation_action_menu destroys the
403 menu it is attached to. Otherwise GTK destroys
404 controller_menu's gobj, meaning that it can't be reattached
405 below. See bug #3134.
408 if (controller_menu) {
409 detach_menu (*controller_menu);
412 _channel_command_menu_map.clear ();
413 RouteTimeAxisView::build_automation_action_menu ();
415 MenuList& automation_items = automation_action_menu->items();
417 uint16_t selected_channels = _channel_selector.get_selected_channels();
419 if (selected_channels != 0) {
421 automation_items.push_back (SeparatorElem());
423 /* these 2 MIDI "command" types are semantically more like automation than note data,
424 but they are not MIDI controllers. We give them special status in this menu, since
425 they will not show up in the controller list and anyone who actually knows
426 something about MIDI (!) would not expect to find them there.
429 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
430 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
432 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
433 since it might need to be updated after a channel mode change or other change. Also detach it
434 first in case it has been used anywhere else.
437 build_controller_menu ();
439 automation_items.push_back (SeparatorElem());
440 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
442 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
448 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
450 uint16_t selected_channels = _channel_selector.get_selected_channels();
452 for (uint8_t chn = 0; chn < 16; chn++) {
453 if (selected_channels & (0x0001 << chn)) {
455 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
456 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
459 menu->set_active (yn);
466 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
468 using namespace Menu_Helpers;
470 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
473 uint16_t selected_channels = _channel_selector.get_selected_channels();
476 for (uint8_t chn = 0; chn < 16; chn++) {
477 if (selected_channels & (0x0001 << chn)) {
486 /* multiple channels - create a submenu, with 1 item per channel */
488 Menu* chn_menu = manage (new Menu);
489 MenuList& chn_items (chn_menu->items());
490 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
492 /* add a couple of items to hide/show all of them */
494 chn_items.push_back (MenuElem (_("Hide all channels"),
495 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
496 false, param_without_channel)));
497 chn_items.push_back (MenuElem (_("Show all channels"),
498 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
499 true, param_without_channel)));
501 for (uint8_t chn = 0; chn < 16; chn++) {
502 if (selected_channels & (0x0001 << chn)) {
504 /* for each selected channel, add a menu item for this controller */
506 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
507 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
508 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
509 fully_qualified_param)));
511 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
512 bool visible = false;
515 if (track->marked_for_display()) {
520 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
521 _channel_command_menu_map[fully_qualified_param] = cmi;
522 cmi->set_active (visible);
526 /* now create an item in the parent menu that has the per-channel list as a submenu */
528 items.push_back (MenuElem (label, *chn_menu));
532 /* just one channel - create a single menu item for this command+channel combination*/
534 for (uint8_t chn = 0; chn < 16; chn++) {
535 if (selected_channels & (0x0001 << chn)) {
537 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
538 items.push_back (CheckMenuElem (label,
539 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
540 fully_qualified_param)));
542 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
543 bool visible = false;
546 if (track->marked_for_display()) {
551 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
552 _channel_command_menu_map[fully_qualified_param] = cmi;
553 cmi->set_active (visible);
555 /* one channel only */
563 MidiTimeAxisView::build_controller_menu ()
565 using namespace Menu_Helpers;
567 if (controller_menu) {
568 /* it exists and has not been invalidated by a channel mode change, so just return it */
572 controller_menu = new Menu; // explicitly managed by us
573 MenuList& items (controller_menu->items());
575 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
576 for each controller+channel combination covering the currently selected channels for this track
579 uint16_t selected_channels = _channel_selector.get_selected_channels();
581 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
586 for (uint8_t chn = 0; chn < 16; chn++) {
587 if (selected_channels & (0x0001 << chn)) {
594 /* loop over all 127 MIDI controllers, in groups of 16 */
596 for (int i = 0; i < 127; i += 16) {
598 Menu* ctl_menu = manage (new Menu);
599 MenuList& ctl_items (ctl_menu->items());
602 /* for each controller, consider whether to create a submenu or a single item */
604 for (int ctl = i; ctl < i+16; ++ctl) {
608 /* multiple channels - create a submenu, with 1 item per channel */
610 Menu* chn_menu = manage (new Menu);
611 MenuList& chn_items (chn_menu->items());
613 /* add a couple of items to hide/show this controller on all channels */
615 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
616 chn_items.push_back (MenuElem (_("Hide all channels"),
617 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
618 false, param_without_channel)));
619 chn_items.push_back (MenuElem (_("Show all channels"),
620 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
621 true, param_without_channel)));
623 for (uint8_t chn = 0; chn < 16; chn++) {
624 if (selected_channels & (0x0001 << chn)) {
626 /* for each selected channel, add a menu item for this controller */
628 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
629 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
630 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
631 fully_qualified_param)));
633 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
634 bool visible = false;
637 if (track->marked_for_display()) {
642 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
643 _controller_menu_map[fully_qualified_param] = cmi;
644 cmi->set_active (visible);
648 /* add the per-channel menu to the list of controllers, with the name of the controller */
649 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
650 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
654 /* just one channel - create a single menu item for this ctl+channel combination*/
656 for (uint8_t chn = 0; chn < 16; chn++) {
657 if (selected_channels & (0x0001 << chn)) {
659 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
660 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
661 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
662 fully_qualified_param)));
664 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
665 bool visible = false;
668 if (track->marked_for_display()) {
673 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
674 _controller_menu_map[fully_qualified_param] = cmi;
675 cmi->set_active (visible);
677 /* one channel only */
684 /* add the menu for this block of controllers to the overall controller menu */
686 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
691 MidiTimeAxisView::build_note_mode_menu()
693 using namespace Menu_Helpers;
695 Menu* mode_menu = manage (new Menu);
696 MenuList& items = mode_menu->items();
697 mode_menu->set_name ("ArdourContextMenu");
699 RadioMenuItem::Group mode_group;
700 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
701 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
702 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
703 _note_mode_item->set_active(_note_mode == Sustained);
705 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
706 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
707 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
708 _percussion_mode_item->set_active(_note_mode == Percussive);
714 MidiTimeAxisView::build_color_mode_menu()
716 using namespace Menu_Helpers;
718 Menu* mode_menu = manage (new Menu);
719 MenuList& items = mode_menu->items();
720 mode_menu->set_name ("ArdourContextMenu");
722 RadioMenuItem::Group mode_group;
723 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
724 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
725 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
726 _meter_color_mode_item->set_active(_color_mode == MeterColors);
728 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
729 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
730 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
731 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
733 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
734 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
735 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
736 _channel_color_mode_item->set_active(_color_mode == TrackColor);
742 MidiTimeAxisView::set_note_mode(NoteMode mode)
744 if (_note_mode != mode || midi_track()->note_mode() != mode) {
746 midi_track()->set_note_mode(mode);
747 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
748 _view->redisplay_track();
753 MidiTimeAxisView::set_color_mode(ColorMode mode)
755 if (_color_mode != mode) {
756 if (mode == ChannelColors) {
757 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
759 _channel_selector.set_default_channel_color();
763 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
764 _view->redisplay_track();
769 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
771 if (!_ignore_signals)
772 midi_view()->set_note_range(range);
777 MidiTimeAxisView::update_range()
779 MidiGhostRegion* mgr;
781 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
782 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
789 MidiTimeAxisView::show_all_automation ()
792 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
794 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
795 create_automation_child(*i, true);
799 RouteTimeAxisView::show_all_automation ();
803 MidiTimeAxisView::show_existing_automation ()
806 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
808 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
809 create_automation_child(*i, true);
813 RouteTimeAxisView::show_existing_automation ();
816 /** Create an automation track for the given parameter (pitch bend, channel pressure).
819 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
821 if (param.type() == NullAutomation) {
822 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
826 AutomationTracks::iterator existing = _automation_tracks.find (param);
827 if (existing != _automation_tracks.end()) {
831 if (param.type() == GainAutomation) {
832 create_gain_automation_child (param, show);
835 /* These controllers are region "automation", so we do not create
836 * an AutomationList/Line for the track */
838 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
841 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
842 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
847 _route->describe_parameter(param)));
849 add_automation_child (param, track, show);
855 MidiTimeAxisView::route_active_changed ()
857 RouteUI::route_active_changed ();
860 if (_route->active()) {
861 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
862 controls_base_selected_name = "MidiTrackControlsBaseSelected";
863 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
865 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
866 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
867 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
873 if (_route->active()) {
874 controls_ebox.set_name ("BusControlsBaseUnselected");
875 controls_base_selected_name = "BusControlsBaseSelected";
876 controls_base_unselected_name = "BusControlsBaseUnselected";
878 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
879 controls_base_selected_name = "BusControlsBaseInactiveSelected";
880 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
888 MidiTimeAxisView::add_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::add_note_selection_region_view), note, chn_mask));
899 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
904 MidiTimeAxisView::extend_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::extend_note_selection_region_view), note, chn_mask));
915 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
920 MidiTimeAxisView::toggle_note_selection (uint8_t note)
922 if (!_editor.internal_editing()) {
926 uint16_t chn_mask = _channel_selector.get_selected_channels();
928 if (_view->num_selected_regionviews() == 0) {
929 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
931 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
936 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
938 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
942 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
944 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
948 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
950 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
954 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
956 /* hide all automation tracks that use the wrong channel(s) and show all those that use
960 uint16_t selected_channels = _channel_selector.get_selected_channels();
961 bool changed = false;
965 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
967 for (uint32_t chn = 0; chn < 16; ++chn) {
968 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
969 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
975 if ((selected_channels & (0x0001 << chn)) == 0) {
976 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
977 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
979 changed = track->set_visibility (false) || changed;
981 changed = track->set_visibility (true) || changed;
988 /* TODO: Bender, PgmChange, Pressure */
990 /* invalidate the controller menu, so that we rebuilt it next time */
991 _controller_menu_map.clear ();
992 delete controller_menu;
996 _route->gui_changed ("track_height", this);
1001 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1003 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1008 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1009 if (i != _controller_menu_map.end()) {
1013 i = _channel_command_menu_map.find (param);
1014 if (i != _channel_command_menu_map.end()) {
1021 boost::shared_ptr<MidiRegion>
1022 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1024 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1026 real_editor->begin_reversible_command (_("create region"));
1027 playlist()->clear_changes ();
1029 real_editor->snap_to (pos, 0);
1031 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1032 view()->trackview().track()->name());
1035 plist.add (ARDOUR::Properties::start, 0);
1036 plist.add (ARDOUR::Properties::length, length);
1037 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1039 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1041 playlist()->add_region (region, pos);
1042 _session->add_command (new StatefulDiffCommand (playlist()));
1045 real_editor->commit_reversible_command ();
1048 return boost::dynamic_pointer_cast<MidiRegion>(region);
1052 MidiTimeAxisView::start_step_editing ()
1054 if (!_step_editor) {
1055 _step_editor = new StepEditor (_editor, midi_track(), *this);
1058 _step_editor->start_step_editing ();
1062 MidiTimeAxisView::stop_step_editing ()
1065 _step_editor->stop_step_editing ();