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));
171 HBox* midi_controls_hbox = manage(new HBox());
173 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
175 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
176 for (; m != patch_manager.all_models().end(); ++m) {
177 _model_selector.append_text(m->c_str());
180 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
182 _custom_device_mode_selector.signal_changed().connect(
183 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
185 // TODO: persist the choice
186 // this initializes the comboboxes and sends out the signal
187 _model_selector.set_active(0);
189 midi_controls_hbox->pack_start(_channel_selector, true, false);
190 if (!patch_manager.all_models().empty()) {
191 _midi_controls_box.pack_start(_model_selector, true, false);
192 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
195 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
197 controls_vbox.pack_start(_midi_controls_box, false, false);
199 // restore channel selector settings
200 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
201 _channel_selector.mode_changed.connect(
202 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
203 _channel_selector.mode_changed.connect(
204 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
207 if ((prop = xml_node->property ("color-mode")) != 0) {
208 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
209 if (_color_mode == ChannelColors) {
210 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
214 if ((prop = xml_node->property ("note-mode")) != 0) {
215 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
216 if (_percussion_mode_item) {
217 _percussion_mode_item->set_active (_note_mode == Percussive);
222 MidiTimeAxisView::~MidiTimeAxisView ()
224 delete _piano_roll_header;
225 _piano_roll_header = 0;
227 delete _range_scroomer;
230 delete controller_menu;
235 MidiTimeAxisView::check_step_edit ()
237 _step_editor->check_step_edit ();
241 MidiTimeAxisView::model_changed()
243 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
244 .custom_device_mode_names_by_model(_model_selector.get_active_text());
246 _custom_device_mode_selector.clear_items();
248 for (std::list<std::string>::const_iterator i = device_modes.begin();
249 i != device_modes.end(); ++i) {
250 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
251 _custom_device_mode_selector.append_text(*i);
254 _custom_device_mode_selector.set_active(0);
257 void MidiTimeAxisView::custom_device_mode_changed()
259 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
260 _custom_device_mode_selector.get_active_text());
264 MidiTimeAxisView::midi_view()
266 return dynamic_cast<MidiStreamView*>(_view);
270 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
273 xml_node->add_property ("shown-editor", "yes");
275 guint32 ret = TimeAxisView::show_at (y, nth, parent);
280 MidiTimeAxisView::hide ()
283 xml_node->add_property ("shown-editor", "no");
285 TimeAxisView::hide ();
289 MidiTimeAxisView::set_height (uint32_t h)
291 RouteTimeAxisView::set_height (h);
293 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
294 _midi_controls_box.show_all ();
296 _midi_controls_box.hide();
299 if (height >= KEYBOARD_MIN_HEIGHT) {
300 if (is_track() && _range_scroomer)
301 _range_scroomer->show();
302 if (is_track() && _piano_roll_header)
303 _piano_roll_header->show();
305 if (is_track() && _range_scroomer)
306 _range_scroomer->hide();
307 if (is_track() && _piano_roll_header)
308 _piano_roll_header->hide();
313 MidiTimeAxisView::append_extra_display_menu_items ()
315 using namespace Menu_Helpers;
317 MenuList& items = display_menu->items();
320 Menu *range_menu = manage(new Menu);
321 MenuList& range_items = range_menu->items();
322 range_menu->set_name ("ArdourContextMenu");
324 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
325 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
326 MidiStreamView::FullRange)));
328 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
329 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
330 MidiStreamView::ContentsRange)));
332 items.push_back (MenuElem (_("Note range"), *range_menu));
333 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
334 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
336 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
337 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
341 MidiTimeAxisView::build_def_channel_menu ()
343 using namespace Menu_Helpers;
345 default_channel_menu = manage (new Menu ());
347 uint8_t defchn = midi_track()->default_channel();
348 MenuList& def_channel_items = default_channel_menu->items();
350 RadioMenuItem::Group dc_group;
352 for (int i = 0; i < 16; ++i) {
354 snprintf (buf, sizeof (buf), "%d", i+1);
356 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
357 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
358 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
359 item->set_active ((i == defchn));
362 return default_channel_menu;
366 MidiTimeAxisView::set_default_channel (int chn)
368 midi_track()->set_default_channel (chn);
372 MidiTimeAxisView::toggle_midi_thru ()
374 if (!_midi_thru_item) {
378 bool view_yn = _midi_thru_item->get_active();
379 if (view_yn != midi_track()->midi_thru()) {
380 midi_track()->set_midi_thru (view_yn);
385 MidiTimeAxisView::build_automation_action_menu ()
387 using namespace Menu_Helpers;
389 /* If we have a controller menu, we need to detach it before
390 RouteTimeAxis::build_automation_action_menu destroys the
391 menu it is attached to. Otherwise GTK destroys
392 controller_menu's gobj, meaning that it can't be reattached
393 below. See bug #3134.
396 if (controller_menu) {
397 detach_menu (*controller_menu);
400 _channel_command_menu_map.clear ();
401 RouteTimeAxisView::build_automation_action_menu ();
403 MenuList& automation_items = automation_action_menu->items();
405 uint16_t selected_channels = _channel_selector.get_selected_channels();
407 if (selected_channels != 0) {
409 automation_items.push_back (SeparatorElem());
411 /* these 3 MIDI "command" types are semantically more like automation than note data,
412 but they are not MIDI controllers. We give them special status in this menu, since
413 they will not show up in the controller list and anyone who actually knows
414 something about MIDI (!) would not expect to find them there.
417 add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, 0);
418 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
419 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
421 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
422 since it might need to be updated after a channel mode change or other change. Also detach it
423 first in case it has been used anywhere else.
426 build_controller_menu ();
428 automation_items.push_back (SeparatorElem());
429 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
431 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
437 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
439 uint16_t selected_channels = _channel_selector.get_selected_channels();
441 for (uint8_t chn = 0; chn < 16; chn++) {
442 if (selected_channels & (0x0001 << chn)) {
444 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
445 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
448 menu->set_active (yn);
455 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
457 using namespace Menu_Helpers;
459 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
462 uint16_t selected_channels = _channel_selector.get_selected_channels();
465 for (uint8_t chn = 0; chn < 16; chn++) {
466 if (selected_channels & (0x0001 << chn)) {
475 /* multiple channels - create a submenu, with 1 item per channel */
477 Menu* chn_menu = manage (new Menu);
478 MenuList& chn_items (chn_menu->items());
479 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
481 /* add a couple of items to hide/show all of them */
483 chn_items.push_back (MenuElem (_("Hide all channels"),
484 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
485 false, param_without_channel)));
486 chn_items.push_back (MenuElem (_("Show all channels"),
487 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
488 true, param_without_channel)));
490 for (uint8_t chn = 0; chn < 16; chn++) {
491 if (selected_channels & (0x0001 << chn)) {
493 /* for each selected channel, add a menu item for this controller */
495 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
496 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
497 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
498 fully_qualified_param)));
500 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
501 bool visible = false;
504 if (track->marked_for_display()) {
509 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
510 _channel_command_menu_map[fully_qualified_param] = cmi;
511 cmi->set_active (visible);
515 /* now create an item in the parent menu that has the per-channel list as a submenu */
517 items.push_back (MenuElem (label, *chn_menu));
521 /* just one channel - create a single menu item for this command+channel combination*/
523 for (uint8_t chn = 0; chn < 16; chn++) {
524 if (selected_channels & (0x0001 << chn)) {
526 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
527 items.push_back (CheckMenuElem (label,
528 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
529 fully_qualified_param)));
531 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
532 bool visible = false;
535 if (track->marked_for_display()) {
540 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
541 _channel_command_menu_map[fully_qualified_param] = cmi;
542 cmi->set_active (visible);
544 /* one channel only */
552 MidiTimeAxisView::build_controller_menu ()
554 using namespace Menu_Helpers;
556 if (controller_menu) {
557 /* it exists and has not been invalidated by a channel mode change, so just return it */
561 controller_menu = new Menu; // explicitly managed by us
562 MenuList& items (controller_menu->items());
564 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
565 for each controller+channel combination covering the currently selected channels for this track
568 uint16_t selected_channels = _channel_selector.get_selected_channels();
570 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
575 for (uint8_t chn = 0; chn < 16; chn++) {
576 if (selected_channels & (0x0001 << chn)) {
583 /* loop over all 127 MIDI controllers, in groups of 16 */
585 for (int i = 0; i < 127; i += 16) {
587 Menu* ctl_menu = manage (new Menu);
588 MenuList& ctl_items (ctl_menu->items());
591 /* for each controller, consider whether to create a submenu or a single item */
593 for (int ctl = i; ctl < i+16; ++ctl) {
597 /* multiple channels - create a submenu, with 1 item per channel */
599 Menu* chn_menu = manage (new Menu);
600 MenuList& chn_items (chn_menu->items());
602 /* add a couple of items to hide/show this controller on all channels */
604 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
605 chn_items.push_back (MenuElem (_("Hide all channels"),
606 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
607 false, param_without_channel)));
608 chn_items.push_back (MenuElem (_("Show all channels"),
609 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
610 true, param_without_channel)));
612 for (uint8_t chn = 0; chn < 16; chn++) {
613 if (selected_channels & (0x0001 << chn)) {
615 /* for each selected channel, add a menu item for this controller */
617 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
618 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
619 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
620 fully_qualified_param)));
622 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
623 bool visible = false;
626 if (track->marked_for_display()) {
631 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
632 _controller_menu_map[fully_qualified_param] = cmi;
633 cmi->set_active (visible);
637 /* add the per-channel menu to the list of controllers, with the name of the controller */
638 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
639 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
643 /* just one channel - create a single menu item for this ctl+channel combination*/
645 for (uint8_t chn = 0; chn < 16; chn++) {
646 if (selected_channels & (0x0001 << chn)) {
648 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
649 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
650 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
651 fully_qualified_param)));
653 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
654 bool visible = false;
657 if (track->marked_for_display()) {
662 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
663 _controller_menu_map[fully_qualified_param] = cmi;
664 cmi->set_active (visible);
666 /* one channel only */
673 /* add the menu for this block of controllers to the overall controller menu */
675 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
680 MidiTimeAxisView::build_note_mode_menu()
682 using namespace Menu_Helpers;
684 Menu* mode_menu = manage (new Menu);
685 MenuList& items = mode_menu->items();
686 mode_menu->set_name ("ArdourContextMenu");
688 RadioMenuItem::Group mode_group;
689 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
690 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
691 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
692 _note_mode_item->set_active(_note_mode == Sustained);
694 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
695 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
696 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
697 _percussion_mode_item->set_active(_note_mode == Percussive);
703 MidiTimeAxisView::build_color_mode_menu()
705 using namespace Menu_Helpers;
707 Menu* mode_menu = manage (new Menu);
708 MenuList& items = mode_menu->items();
709 mode_menu->set_name ("ArdourContextMenu");
711 RadioMenuItem::Group mode_group;
712 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
713 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
714 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
715 _meter_color_mode_item->set_active(_color_mode == MeterColors);
717 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
718 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
719 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
720 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
722 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
723 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
724 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
725 _channel_color_mode_item->set_active(_color_mode == TrackColor);
731 MidiTimeAxisView::set_note_mode(NoteMode mode)
733 if (_note_mode != mode || midi_track()->note_mode() != mode) {
735 midi_track()->set_note_mode(mode);
736 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
737 _view->redisplay_track();
742 MidiTimeAxisView::set_color_mode(ColorMode mode)
744 if (_color_mode != mode) {
745 if (mode == ChannelColors) {
746 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
748 _channel_selector.set_default_channel_color();
752 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
753 _view->redisplay_track();
758 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
760 if (!_ignore_signals)
761 midi_view()->set_note_range(range);
766 MidiTimeAxisView::update_range()
768 MidiGhostRegion* mgr;
770 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
771 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
778 MidiTimeAxisView::show_all_automation ()
781 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
783 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
784 create_automation_child(*i, true);
788 RouteTimeAxisView::show_all_automation ();
792 MidiTimeAxisView::show_existing_automation ()
795 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
797 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
798 create_automation_child(*i, true);
802 RouteTimeAxisView::show_existing_automation ();
805 /** Create an automation track for the given parameter (pitch bend, channel pressure).
808 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
810 /* These controllers are region "automation", so we do not create
811 * an AutomationList/Line for the track */
813 if (param.type() == NullAutomation) {
814 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
818 AutomationTracks::iterator existing = _automation_tracks.find (param);
819 if (existing != _automation_tracks.end()) {
823 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
827 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
828 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
833 _route->describe_parameter(param)));
835 add_automation_child (param, track, show);
840 MidiTimeAxisView::route_active_changed ()
842 RouteUI::route_active_changed ();
845 if (_route->active()) {
846 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
847 controls_base_selected_name = "MidiTrackControlsBaseSelected";
848 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
850 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
851 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
852 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
858 if (_route->active()) {
859 controls_ebox.set_name ("BusControlsBaseUnselected");
860 controls_base_selected_name = "BusControlsBaseSelected";
861 controls_base_unselected_name = "BusControlsBaseUnselected";
863 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
864 controls_base_selected_name = "BusControlsBaseInactiveSelected";
865 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
873 MidiTimeAxisView::add_note_selection (uint8_t note)
875 if (!_editor.internal_editing()) {
879 uint16_t chn_mask = _channel_selector.get_selected_channels();
881 if (_view->num_selected_regionviews() == 0) {
882 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
884 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
889 MidiTimeAxisView::extend_note_selection (uint8_t note)
891 if (!_editor.internal_editing()) {
895 uint16_t chn_mask = _channel_selector.get_selected_channels();
897 if (_view->num_selected_regionviews() == 0) {
898 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
900 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
905 MidiTimeAxisView::toggle_note_selection (uint8_t note)
907 if (!_editor.internal_editing()) {
911 uint16_t chn_mask = _channel_selector.get_selected_channels();
913 if (_view->num_selected_regionviews() == 0) {
914 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
916 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
921 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
923 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
927 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
929 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
933 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
935 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
939 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
941 /* hide all automation tracks that use the wrong channel(s) and show all those that use
945 uint16_t selected_channels = _channel_selector.get_selected_channels();
946 bool changed = false;
950 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
952 for (uint32_t chn = 0; chn < 16; ++chn) {
953 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
954 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
960 if ((selected_channels & (0x0001 << chn)) == 0) {
961 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
962 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
964 changed = track->set_visibility (false) || changed;
966 changed = track->set_visibility (true) || changed;
973 /* TODO: Bender, PgmChange, Pressure */
975 /* invalidate the controller menu, so that we rebuilt it next time */
976 _controller_menu_map.clear ();
977 delete controller_menu;
981 _route->gui_changed ("track_height", this);
986 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
988 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
993 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
994 if (i != _controller_menu_map.end()) {
998 i = _channel_command_menu_map.find (param);
999 if (i != _channel_command_menu_map.end()) {
1006 boost::shared_ptr<MidiRegion>
1007 MidiTimeAxisView::add_region (framepos_t pos)
1009 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1011 real_editor->begin_reversible_command (_("create region"));
1012 playlist()->clear_history ();
1014 real_editor->snap_to (pos, 0);
1015 const Meter& m = _session->tempo_map().meter_at(pos);
1016 const Tempo& t = _session->tempo_map().tempo_at(pos);
1017 double length = floor (m.frames_per_bar(t, _session->frame_rate()));
1019 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1020 view()->trackview().track()->name());
1023 plist.add (ARDOUR::Properties::start, 0);
1024 plist.add (ARDOUR::Properties::length, length);
1025 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1027 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1029 playlist()->add_region (region, pos);
1030 _session->add_command (new StatefulDiffCommand (playlist()));
1032 real_editor->commit_reversible_command();
1034 return boost::dynamic_pointer_cast<MidiRegion>(region);
1038 MidiTimeAxisView::start_step_editing ()
1040 if (!_step_editor) {
1041 _step_editor = new StepEditor (_editor, midi_track(), *this);
1044 _step_editor->start_step_editing ();
1048 MidiTimeAxisView::stop_step_editing ()
1051 _step_editor->stop_step_editing ();