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"
55 #include "ardour/operations.h"
57 #include "midi++/names.h"
59 #include "add_midi_cc_track_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_line.h"
62 #include "automation_time_axis.h"
63 #include "canvas-note-event.h"
64 #include "canvas_impl.h"
65 #include "crossfade_view.h"
68 #include "ghostregion.h"
69 #include "gui_thread.h"
71 #include "midi_scroomer.h"
72 #include "midi_streamview.h"
73 #include "midi_region_view.h"
74 #include "midi_time_axis.h"
75 #include "piano_roll_header.h"
76 #include "playlist_selector.h"
77 #include "plugin_selector.h"
78 #include "plugin_ui.h"
79 #include "point_selection.h"
81 #include "region_view.h"
82 #include "rgb_macros.h"
83 #include "selection.h"
84 #include "step_editor.h"
85 #include "simplerect.h"
88 #include "ardour/midi_track.h"
92 using namespace ARDOUR;
95 using namespace Gtkmm2ext;
96 using namespace Editing;
98 // Minimum height at which a control is displayed
99 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
100 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
102 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
103 boost::shared_ptr<Route> rt, Canvas& canvas)
104 : AxisView(sess) // virtually inherited
105 , RouteTimeAxisView(ed, sess, rt, canvas)
106 , _ignore_signals(false)
108 , _piano_roll_header(0)
109 , _note_mode(Sustained)
111 , _percussion_mode_item(0)
112 , _color_mode(MeterColors)
113 , _meter_color_mode_item(0)
114 , _channel_color_mode_item(0)
115 , _track_color_mode_item(0)
116 , _step_edit_item (0)
117 , _midi_thru_item (0)
118 , default_channel_menu (0)
119 , controller_menu (0)
122 subplugin_menu.set_name ("ArdourContextMenu");
124 _view = new MidiStreamView (*this);
126 ignore_toggle = false;
128 mute_button->set_active (false);
129 solo_button->set_active (false);
131 if (is_midi_track()) {
132 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
133 _note_mode = midi_track()->note_mode();
134 } else { // MIDI bus (which doesn't exist yet..)
135 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
138 /* map current state of the route */
140 processors_changed (RouteProcessorChange ());
144 set_state (*xml_node, Stateful::loading_state_version);
146 _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
149 _piano_roll_header = new PianoRollHeader(*midi_view());
151 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
152 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
153 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
155 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
157 controls_hbox.pack_start(*_range_scroomer);
158 controls_hbox.pack_start(*_piano_roll_header);
160 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
161 controls_base_selected_name = "MidiTrackControlsBaseSelected";
162 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
164 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
166 /* ask for notifications of any new RegionViews */
167 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
169 if (!_editor.have_idled()) {
170 /* first idle will do what we need */
176 HBox* midi_controls_hbox = manage(new HBox());
178 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
180 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
181 for (; m != patch_manager.all_models().end(); ++m) {
182 _model_selector.append_text(m->c_str());
185 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
187 _custom_device_mode_selector.signal_changed().connect(
188 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
190 // TODO: persist the choice
191 // this initializes the comboboxes and sends out the signal
192 _model_selector.set_active(0);
194 midi_controls_hbox->pack_start(_channel_selector, true, false);
195 if (!patch_manager.all_models().empty()) {
196 _midi_controls_box.pack_start(_model_selector, true, false);
197 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
200 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
202 controls_vbox.pack_start(_midi_controls_box, false, false);
204 // restore channel selector settings
205 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
206 _channel_selector.mode_changed.connect(
207 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
208 _channel_selector.mode_changed.connect(
209 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
212 if ((prop = xml_node->property ("color-mode")) != 0) {
213 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
214 if (_color_mode == ChannelColors) {
215 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
219 if ((prop = xml_node->property ("note-mode")) != 0) {
220 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
221 if (_percussion_mode_item) {
222 _percussion_mode_item->set_active (_note_mode == Percussive);
228 MidiTimeAxisView::first_idle ()
235 MidiTimeAxisView::~MidiTimeAxisView ()
237 delete _piano_roll_header;
238 _piano_roll_header = 0;
240 delete _range_scroomer;
243 delete controller_menu;
248 MidiTimeAxisView::check_step_edit ()
250 ensure_step_editor ();
251 _step_editor->check_step_edit ();
255 MidiTimeAxisView::model_changed()
257 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
258 .custom_device_mode_names_by_model(_model_selector.get_active_text());
260 _custom_device_mode_selector.clear_items();
262 for (std::list<std::string>::const_iterator i = device_modes.begin();
263 i != device_modes.end(); ++i) {
264 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
265 _custom_device_mode_selector.append_text(*i);
268 _custom_device_mode_selector.set_active(0);
271 void MidiTimeAxisView::custom_device_mode_changed()
273 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
274 _custom_device_mode_selector.get_active_text());
278 MidiTimeAxisView::midi_view()
280 return dynamic_cast<MidiStreamView*>(_view);
284 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
287 xml_node->add_property ("shown-editor", "yes");
289 guint32 ret = TimeAxisView::show_at (y, nth, parent);
294 MidiTimeAxisView::hide ()
297 xml_node->add_property ("shown-editor", "no");
299 TimeAxisView::hide ();
303 MidiTimeAxisView::set_height (uint32_t h)
305 RouteTimeAxisView::set_height (h);
307 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
308 _midi_controls_box.show_all ();
310 _midi_controls_box.hide();
313 if (height >= KEYBOARD_MIN_HEIGHT) {
314 if (is_track() && _range_scroomer)
315 _range_scroomer->show();
316 if (is_track() && _piano_roll_header)
317 _piano_roll_header->show();
319 if (is_track() && _range_scroomer)
320 _range_scroomer->hide();
321 if (is_track() && _piano_roll_header)
322 _piano_roll_header->hide();
327 MidiTimeAxisView::append_extra_display_menu_items ()
329 using namespace Menu_Helpers;
331 MenuList& items = display_menu->items();
334 Menu *range_menu = manage(new Menu);
335 MenuList& range_items = range_menu->items();
336 range_menu->set_name ("ArdourContextMenu");
338 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
339 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
340 MidiStreamView::FullRange)));
342 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
343 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
344 MidiStreamView::ContentsRange)));
346 items.push_back (MenuElem (_("Note range"), *range_menu));
347 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
348 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
350 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
351 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
355 MidiTimeAxisView::build_def_channel_menu ()
357 using namespace Menu_Helpers;
359 default_channel_menu = manage (new Menu ());
361 uint8_t defchn = midi_track()->default_channel();
362 MenuList& def_channel_items = default_channel_menu->items();
364 RadioMenuItem::Group dc_group;
366 for (int i = 0; i < 16; ++i) {
368 snprintf (buf, sizeof (buf), "%d", i+1);
370 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
371 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
372 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
373 item->set_active ((i == defchn));
376 return default_channel_menu;
380 MidiTimeAxisView::set_default_channel (int chn)
382 midi_track()->set_default_channel (chn);
386 MidiTimeAxisView::toggle_midi_thru ()
388 if (!_midi_thru_item) {
392 bool view_yn = _midi_thru_item->get_active();
393 if (view_yn != midi_track()->midi_thru()) {
394 midi_track()->set_midi_thru (view_yn);
399 MidiTimeAxisView::build_automation_action_menu ()
401 using namespace Menu_Helpers;
403 /* If we have a controller menu, we need to detach it before
404 RouteTimeAxis::build_automation_action_menu destroys the
405 menu it is attached to. Otherwise GTK destroys
406 controller_menu's gobj, meaning that it can't be reattached
407 below. See bug #3134.
410 if (controller_menu) {
411 detach_menu (*controller_menu);
414 _channel_command_menu_map.clear ();
415 RouteTimeAxisView::build_automation_action_menu ();
417 MenuList& automation_items = automation_action_menu->items();
419 uint16_t selected_channels = _channel_selector.get_selected_channels();
421 if (selected_channels != 0) {
423 automation_items.push_back (SeparatorElem());
425 /* these 2 MIDI "command" types are semantically more like automation than note data,
426 but they are not MIDI controllers. We give them special status in this menu, since
427 they will not show up in the controller list and anyone who actually knows
428 something about MIDI (!) would not expect to find them there.
431 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
432 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
434 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
435 since it might need to be updated after a channel mode change or other change. Also detach it
436 first in case it has been used anywhere else.
439 build_controller_menu ();
441 automation_items.push_back (SeparatorElem());
442 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
444 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
445 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
451 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
453 uint16_t selected_channels = _channel_selector.get_selected_channels();
455 for (uint8_t chn = 0; chn < 16; chn++) {
456 if (selected_channels & (0x0001 << chn)) {
458 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
459 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
462 menu->set_active (yn);
469 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
471 using namespace Menu_Helpers;
473 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
476 uint16_t selected_channels = _channel_selector.get_selected_channels();
479 for (uint8_t chn = 0; chn < 16; chn++) {
480 if (selected_channels & (0x0001 << chn)) {
489 /* multiple channels - create a submenu, with 1 item per channel */
491 Menu* chn_menu = manage (new Menu);
492 MenuList& chn_items (chn_menu->items());
493 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
495 /* add a couple of items to hide/show all of them */
497 chn_items.push_back (MenuElem (_("Hide all channels"),
498 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
499 false, param_without_channel)));
500 chn_items.push_back (MenuElem (_("Show all channels"),
501 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
502 true, param_without_channel)));
504 for (uint8_t chn = 0; chn < 16; chn++) {
505 if (selected_channels & (0x0001 << chn)) {
507 /* for each selected channel, add a menu item for this controller */
509 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
510 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
511 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
512 fully_qualified_param)));
514 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
515 bool visible = false;
518 if (track->marked_for_display()) {
523 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
524 _channel_command_menu_map[fully_qualified_param] = cmi;
525 cmi->set_active (visible);
529 /* now create an item in the parent menu that has the per-channel list as a submenu */
531 items.push_back (MenuElem (label, *chn_menu));
535 /* just one channel - create a single menu item for this command+channel combination*/
537 for (uint8_t chn = 0; chn < 16; chn++) {
538 if (selected_channels & (0x0001 << chn)) {
540 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
541 items.push_back (CheckMenuElem (label,
542 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
543 fully_qualified_param)));
545 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
546 bool visible = false;
549 if (track->marked_for_display()) {
554 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
555 _channel_command_menu_map[fully_qualified_param] = cmi;
556 cmi->set_active (visible);
558 /* one channel only */
566 MidiTimeAxisView::build_controller_menu ()
568 using namespace Menu_Helpers;
570 if (controller_menu) {
571 /* it exists and has not been invalidated by a channel mode change, so just return it */
575 controller_menu = new Menu; // explicitly managed by us
576 MenuList& items (controller_menu->items());
578 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
579 for each controller+channel combination covering the currently selected channels for this track
582 uint16_t selected_channels = _channel_selector.get_selected_channels();
584 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
589 for (uint8_t chn = 0; chn < 16; chn++) {
590 if (selected_channels & (0x0001 << chn)) {
597 /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
598 bank select controllers, as they are handled by the `patch' code */
600 for (int i = 0; i < 127; i += 16) {
602 Menu* ctl_menu = manage (new Menu);
603 MenuList& ctl_items (ctl_menu->items());
606 /* for each controller, consider whether to create a submenu or a single item */
608 for (int ctl = i; ctl < i+16; ++ctl) {
610 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
616 /* multiple channels - create a submenu, with 1 item per channel */
618 Menu* chn_menu = manage (new Menu);
619 MenuList& chn_items (chn_menu->items());
621 /* add a couple of items to hide/show this controller on all channels */
623 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
624 chn_items.push_back (MenuElem (_("Hide all channels"),
625 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
626 false, param_without_channel)));
627 chn_items.push_back (MenuElem (_("Show all channels"),
628 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
629 true, param_without_channel)));
631 for (uint8_t chn = 0; chn < 16; chn++) {
632 if (selected_channels & (0x0001 << chn)) {
634 /* for each selected channel, add a menu item for this controller */
636 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
637 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
638 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
639 fully_qualified_param)));
641 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
642 bool visible = false;
645 if (track->marked_for_display()) {
650 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
651 _controller_menu_map[fully_qualified_param] = cmi;
652 cmi->set_active (visible);
656 /* add the per-channel menu to the list of controllers, with the name of the controller */
657 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
658 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
662 /* just one channel - create a single menu item for this ctl+channel combination*/
664 for (uint8_t chn = 0; chn < 16; chn++) {
665 if (selected_channels & (0x0001 << chn)) {
667 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
668 ctl_items.push_back (
670 string_compose ("<b>%1</b>: %2 [%3]", ctl, midi_name (ctl), int (chn)),
671 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
672 fully_qualified_param)
675 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
677 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
678 bool visible = false;
681 if (track->marked_for_display()) {
686 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
687 _controller_menu_map[fully_qualified_param] = cmi;
688 cmi->set_active (visible);
690 /* one channel only */
697 /* add the menu for this block of controllers to the overall controller menu */
699 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
704 MidiTimeAxisView::build_note_mode_menu()
706 using namespace Menu_Helpers;
708 Menu* mode_menu = manage (new Menu);
709 MenuList& items = mode_menu->items();
710 mode_menu->set_name ("ArdourContextMenu");
712 RadioMenuItem::Group mode_group;
713 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
714 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
715 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
716 _note_mode_item->set_active(_note_mode == Sustained);
718 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
719 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
720 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
721 _percussion_mode_item->set_active(_note_mode == Percussive);
727 MidiTimeAxisView::build_color_mode_menu()
729 using namespace Menu_Helpers;
731 Menu* mode_menu = manage (new Menu);
732 MenuList& items = mode_menu->items();
733 mode_menu->set_name ("ArdourContextMenu");
735 RadioMenuItem::Group mode_group;
736 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
737 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
738 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
739 _meter_color_mode_item->set_active(_color_mode == MeterColors);
741 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
742 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
743 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
744 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
746 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
747 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
748 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
749 _channel_color_mode_item->set_active(_color_mode == TrackColor);
755 MidiTimeAxisView::set_note_mode(NoteMode mode)
757 if (_note_mode != mode || midi_track()->note_mode() != mode) {
759 midi_track()->set_note_mode(mode);
760 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
761 _view->redisplay_track();
766 MidiTimeAxisView::set_color_mode(ColorMode mode)
768 if (_color_mode != mode) {
769 if (mode == ChannelColors) {
770 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
772 _channel_selector.set_default_channel_color();
776 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
777 _view->redisplay_track();
782 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
784 if (!_ignore_signals)
785 midi_view()->set_note_range(range);
790 MidiTimeAxisView::update_range()
792 MidiGhostRegion* mgr;
794 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
795 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
802 MidiTimeAxisView::show_all_automation ()
805 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
807 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
808 create_automation_child(*i, true);
812 RouteTimeAxisView::show_all_automation ();
816 MidiTimeAxisView::show_existing_automation ()
819 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
821 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
822 create_automation_child(*i, true);
826 RouteTimeAxisView::show_existing_automation ();
829 /** Create an automation track for the given parameter (pitch bend, channel pressure).
832 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
834 if (param.type() == NullAutomation) {
835 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
839 AutomationTracks::iterator existing = _automation_tracks.find (param);
840 if (existing != _automation_tracks.end()) {
844 if (param.type() == GainAutomation) {
845 create_gain_automation_child (param, show);
848 /* These controllers are region "automation", so we do not create
849 * an AutomationList/Line for the track */
851 boost::shared_ptr<AutomationTimeAxisView> track (
852 new AutomationTimeAxisView (
855 boost::shared_ptr<Automatable> (),
856 boost::shared_ptr<AutomationControl> (),
862 _route->describe_parameter(param)
866 add_automation_child (param, track, show);
872 MidiTimeAxisView::route_active_changed ()
874 RouteUI::route_active_changed ();
877 if (_route->active()) {
878 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
879 controls_base_selected_name = "MidiTrackControlsBaseSelected";
880 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
882 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
883 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
884 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
890 if (_route->active()) {
891 controls_ebox.set_name ("BusControlsBaseUnselected");
892 controls_base_selected_name = "BusControlsBaseSelected";
893 controls_base_unselected_name = "BusControlsBaseUnselected";
895 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
896 controls_base_selected_name = "BusControlsBaseInactiveSelected";
897 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
905 MidiTimeAxisView::add_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::add_note_selection_region_view), note, chn_mask));
916 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
921 MidiTimeAxisView::extend_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::extend_note_selection_region_view), note, chn_mask));
932 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
937 MidiTimeAxisView::toggle_note_selection (uint8_t note)
939 if (!_editor.internal_editing()) {
943 uint16_t chn_mask = _channel_selector.get_selected_channels();
945 if (_view->num_selected_regionviews() == 0) {
946 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
948 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
953 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
955 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
959 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
961 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
965 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
967 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
971 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
973 /* hide all automation tracks that use the wrong channel(s) and show all those that use
977 uint16_t selected_channels = _channel_selector.get_selected_channels();
978 bool changed = false;
982 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
984 for (uint32_t chn = 0; chn < 16; ++chn) {
985 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
986 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
992 if ((selected_channels & (0x0001 << chn)) == 0) {
993 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
994 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
996 changed = track->set_visibility (false) || changed;
998 changed = track->set_visibility (true) || changed;
1005 /* TODO: Bender, Pressure */
1007 /* invalidate the controller menu, so that we rebuild it next time */
1008 _controller_menu_map.clear ();
1009 delete controller_menu;
1010 controller_menu = 0;
1013 _route->gui_changed ("track_height", this);
1018 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1020 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1025 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1026 if (i != _controller_menu_map.end()) {
1030 i = _channel_command_menu_map.find (param);
1031 if (i != _channel_command_menu_map.end()) {
1038 boost::shared_ptr<MidiRegion>
1039 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1041 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1043 real_editor->begin_reversible_command (Operations::create_region);
1044 playlist()->clear_changes ();
1046 real_editor->snap_to (pos, 0);
1048 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1049 view()->trackview().track()->name());
1052 plist.add (ARDOUR::Properties::start, 0);
1053 plist.add (ARDOUR::Properties::length, length);
1054 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1056 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1058 playlist()->add_region (region, pos);
1059 _session->add_command (new StatefulDiffCommand (playlist()));
1062 real_editor->commit_reversible_command ();
1065 return boost::dynamic_pointer_cast<MidiRegion>(region);
1069 MidiTimeAxisView::ensure_step_editor ()
1071 if (!_step_editor) {
1072 _step_editor = new StepEditor (_editor, midi_track(), *this);
1077 MidiTimeAxisView::start_step_editing ()
1079 ensure_step_editor ();
1080 _step_editor->start_step_editing ();
1084 MidiTimeAxisView::stop_step_editing ()
1087 _step_editor->stop_step_editing ();