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 3 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, _("Program Change"), MidiPgmChangeAutomation, 0);
430 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
431 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
433 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
434 since it might need to be updated after a channel mode change or other change. Also detach it
435 first in case it has been used anywhere else.
438 build_controller_menu ();
440 automation_items.push_back (SeparatorElem());
441 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
443 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
449 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
451 uint16_t selected_channels = _channel_selector.get_selected_channels();
453 for (uint8_t chn = 0; chn < 16; chn++) {
454 if (selected_channels & (0x0001 << chn)) {
456 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
457 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
460 menu->set_active (yn);
467 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
469 using namespace Menu_Helpers;
471 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
474 uint16_t selected_channels = _channel_selector.get_selected_channels();
477 for (uint8_t chn = 0; chn < 16; chn++) {
478 if (selected_channels & (0x0001 << chn)) {
487 /* multiple channels - create a submenu, with 1 item per channel */
489 Menu* chn_menu = manage (new Menu);
490 MenuList& chn_items (chn_menu->items());
491 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
493 /* add a couple of items to hide/show all of them */
495 chn_items.push_back (MenuElem (_("Hide all channels"),
496 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
497 false, param_without_channel)));
498 chn_items.push_back (MenuElem (_("Show all channels"),
499 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
500 true, param_without_channel)));
502 for (uint8_t chn = 0; chn < 16; chn++) {
503 if (selected_channels & (0x0001 << chn)) {
505 /* for each selected channel, add a menu item for this controller */
507 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
508 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
509 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
510 fully_qualified_param)));
512 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
513 bool visible = false;
516 if (track->marked_for_display()) {
521 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
522 _channel_command_menu_map[fully_qualified_param] = cmi;
523 cmi->set_active (visible);
527 /* now create an item in the parent menu that has the per-channel list as a submenu */
529 items.push_back (MenuElem (label, *chn_menu));
533 /* just one channel - create a single menu item for this command+channel combination*/
535 for (uint8_t chn = 0; chn < 16; chn++) {
536 if (selected_channels & (0x0001 << chn)) {
538 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
539 items.push_back (CheckMenuElem (label,
540 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
541 fully_qualified_param)));
543 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
544 bool visible = false;
547 if (track->marked_for_display()) {
552 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
553 _channel_command_menu_map[fully_qualified_param] = cmi;
554 cmi->set_active (visible);
556 /* one channel only */
564 MidiTimeAxisView::build_controller_menu ()
566 using namespace Menu_Helpers;
568 if (controller_menu) {
569 /* it exists and has not been invalidated by a channel mode change, so just return it */
573 controller_menu = new Menu; // explicitly managed by us
574 MenuList& items (controller_menu->items());
576 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
577 for each controller+channel combination covering the currently selected channels for this track
580 uint16_t selected_channels = _channel_selector.get_selected_channels();
582 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
587 for (uint8_t chn = 0; chn < 16; chn++) {
588 if (selected_channels & (0x0001 << chn)) {
595 /* loop over all 127 MIDI controllers, in groups of 16 */
597 for (int i = 0; i < 127; i += 16) {
599 Menu* ctl_menu = manage (new Menu);
600 MenuList& ctl_items (ctl_menu->items());
603 /* for each controller, consider whether to create a submenu or a single item */
605 for (int ctl = i; ctl < i+16; ++ctl) {
609 /* multiple channels - create a submenu, with 1 item per channel */
611 Menu* chn_menu = manage (new Menu);
612 MenuList& chn_items (chn_menu->items());
614 /* add a couple of items to hide/show this controller on all channels */
616 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
617 chn_items.push_back (MenuElem (_("Hide all channels"),
618 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
619 false, param_without_channel)));
620 chn_items.push_back (MenuElem (_("Show all channels"),
621 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
622 true, param_without_channel)));
624 for (uint8_t chn = 0; chn < 16; chn++) {
625 if (selected_channels & (0x0001 << chn)) {
627 /* for each selected channel, add a menu item for this controller */
629 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
630 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
631 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
632 fully_qualified_param)));
634 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
635 bool visible = false;
638 if (track->marked_for_display()) {
643 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
644 _controller_menu_map[fully_qualified_param] = cmi;
645 cmi->set_active (visible);
649 /* add the per-channel menu to the list of controllers, with the name of the controller */
650 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
651 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
655 /* just one channel - create a single menu item for this ctl+channel combination*/
657 for (uint8_t chn = 0; chn < 16; chn++) {
658 if (selected_channels & (0x0001 << chn)) {
660 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
661 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
662 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
663 fully_qualified_param)));
665 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
666 bool visible = false;
669 if (track->marked_for_display()) {
674 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
675 _controller_menu_map[fully_qualified_param] = cmi;
676 cmi->set_active (visible);
678 /* one channel only */
685 /* add the menu for this block of controllers to the overall controller menu */
687 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
692 MidiTimeAxisView::build_note_mode_menu()
694 using namespace Menu_Helpers;
696 Menu* mode_menu = manage (new Menu);
697 MenuList& items = mode_menu->items();
698 mode_menu->set_name ("ArdourContextMenu");
700 RadioMenuItem::Group mode_group;
701 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
702 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
703 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
704 _note_mode_item->set_active(_note_mode == Sustained);
706 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
707 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
708 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
709 _percussion_mode_item->set_active(_note_mode == Percussive);
715 MidiTimeAxisView::build_color_mode_menu()
717 using namespace Menu_Helpers;
719 Menu* mode_menu = manage (new Menu);
720 MenuList& items = mode_menu->items();
721 mode_menu->set_name ("ArdourContextMenu");
723 RadioMenuItem::Group mode_group;
724 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
725 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
726 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
727 _meter_color_mode_item->set_active(_color_mode == MeterColors);
729 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
730 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
731 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
732 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
734 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
735 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
736 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
737 _channel_color_mode_item->set_active(_color_mode == TrackColor);
743 MidiTimeAxisView::set_note_mode(NoteMode mode)
745 if (_note_mode != mode || midi_track()->note_mode() != mode) {
747 midi_track()->set_note_mode(mode);
748 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
749 _view->redisplay_track();
754 MidiTimeAxisView::set_color_mode(ColorMode mode)
756 if (_color_mode != mode) {
757 if (mode == ChannelColors) {
758 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
760 _channel_selector.set_default_channel_color();
764 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
765 _view->redisplay_track();
770 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
772 if (!_ignore_signals)
773 midi_view()->set_note_range(range);
778 MidiTimeAxisView::update_range()
780 MidiGhostRegion* mgr;
782 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
783 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
790 MidiTimeAxisView::show_all_automation ()
793 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
795 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
796 create_automation_child(*i, true);
800 RouteTimeAxisView::show_all_automation ();
804 MidiTimeAxisView::show_existing_automation ()
807 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
809 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
810 create_automation_child(*i, true);
814 RouteTimeAxisView::show_existing_automation ();
817 /** Create an automation track for the given parameter (pitch bend, channel pressure).
820 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
822 if (param.type() == NullAutomation) {
823 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
827 AutomationTracks::iterator existing = _automation_tracks.find (param);
828 if (existing != _automation_tracks.end()) {
832 if (param.type() == GainAutomation) {
833 create_gain_automation_child (param, show);
836 /* These controllers are region "automation", so we do not create
837 * an AutomationList/Line for the track */
839 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
842 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
843 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
848 _route->describe_parameter(param)));
850 add_automation_child (param, track, show);
856 MidiTimeAxisView::route_active_changed ()
858 RouteUI::route_active_changed ();
861 if (_route->active()) {
862 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
863 controls_base_selected_name = "MidiTrackControlsBaseSelected";
864 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
866 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
867 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
868 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
874 if (_route->active()) {
875 controls_ebox.set_name ("BusControlsBaseUnselected");
876 controls_base_selected_name = "BusControlsBaseSelected";
877 controls_base_unselected_name = "BusControlsBaseUnselected";
879 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
880 controls_base_selected_name = "BusControlsBaseInactiveSelected";
881 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
889 MidiTimeAxisView::add_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::add_note_selection_region_view), note, chn_mask));
900 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
905 MidiTimeAxisView::extend_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::extend_note_selection_region_view), note, chn_mask));
916 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
921 MidiTimeAxisView::toggle_note_selection (uint8_t note)
923 if (!_editor.internal_editing()) {
927 uint16_t chn_mask = _channel_selector.get_selected_channels();
929 if (_view->num_selected_regionviews() == 0) {
930 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
932 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
937 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
939 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
943 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
945 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
949 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
951 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
955 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
957 /* hide all automation tracks that use the wrong channel(s) and show all those that use
961 uint16_t selected_channels = _channel_selector.get_selected_channels();
962 bool changed = false;
966 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
968 for (uint32_t chn = 0; chn < 16; ++chn) {
969 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
970 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
976 if ((selected_channels & (0x0001 << chn)) == 0) {
977 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
978 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
980 changed = track->set_visibility (false) || changed;
982 changed = track->set_visibility (true) || changed;
989 /* TODO: Bender, PgmChange, Pressure */
991 /* invalidate the controller menu, so that we rebuilt it next time */
992 _controller_menu_map.clear ();
993 delete controller_menu;
997 _route->gui_changed ("track_height", this);
1002 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1004 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1009 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1010 if (i != _controller_menu_map.end()) {
1014 i = _channel_command_menu_map.find (param);
1015 if (i != _channel_command_menu_map.end()) {
1022 boost::shared_ptr<MidiRegion>
1023 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1025 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1027 real_editor->begin_reversible_command (_("create region"));
1028 playlist()->clear_changes ();
1030 real_editor->snap_to (pos, 0);
1032 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1033 view()->trackview().track()->name());
1036 plist.add (ARDOUR::Properties::start, 0);
1037 plist.add (ARDOUR::Properties::length, length);
1038 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1040 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1042 playlist()->add_region (region, pos);
1043 _session->add_command (new StatefulDiffCommand (playlist()));
1046 real_editor->commit_reversible_command ();
1049 return boost::dynamic_pointer_cast<MidiRegion>(region);
1053 MidiTimeAxisView::start_step_editing ()
1055 if (!_step_editor) {
1056 _step_editor = new StepEditor (_editor, midi_track(), *this);
1059 _step_editor->start_step_editing ();
1063 MidiTimeAxisView::stop_step_editing ()
1066 _step_editor->stop_step_editing ();