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 "simplerect.h"
86 #include "ardour/midi_track.h"
90 using namespace ARDOUR;
93 using namespace Gtkmm2ext;
94 using namespace Editing;
96 // Minimum height at which a control is displayed
97 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
98 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
100 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
101 boost::shared_ptr<Route> rt, Canvas& canvas)
102 : AxisView(sess) // virtually inherited
103 , RouteTimeAxisView(ed, sess, rt, canvas)
104 , _ignore_signals(false)
106 , _piano_roll_header(0)
107 , _note_mode(Sustained)
109 , _percussion_mode_item(0)
110 , _color_mode(MeterColors)
111 , _meter_color_mode_item(0)
112 , _channel_color_mode_item(0)
113 , _track_color_mode_item(0)
114 , _step_edit_item (0)
115 , _midi_thru_item (0)
116 , default_channel_menu (0)
117 , controller_menu (0)
119 subplugin_menu.set_name ("ArdourContextMenu");
121 _view = new MidiStreamView (*this);
123 ignore_toggle = false;
125 mute_button->set_active (false);
126 solo_button->set_active (false);
128 step_edit_insert_position = 0;
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));
170 HBox* midi_controls_hbox = manage(new HBox());
172 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
174 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
175 for (; m != patch_manager.all_models().end(); ++m) {
176 _model_selector.append_text(m->c_str());
179 _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
181 _custom_device_mode_selector.signal_changed().connect(
182 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
184 // TODO: persist the choice
185 // this initializes the comboboxes and sends out the signal
186 _model_selector.set_active(0);
188 midi_controls_hbox->pack_start(_channel_selector, true, false);
189 if (!patch_manager.all_models().empty()) {
190 _midi_controls_box.pack_start(_model_selector, true, false);
191 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
194 _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
196 controls_vbox.pack_start(_midi_controls_box, false, false);
198 // restore channel selector settings
199 _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
200 _channel_selector.mode_changed.connect(
201 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
202 _channel_selector.mode_changed.connect(
203 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
206 if ((prop = xml_node->property ("color-mode")) != 0) {
207 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
208 if (_color_mode == ChannelColors) {
209 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
213 if ((prop = xml_node->property ("note-mode")) != 0) {
214 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
215 if (_percussion_mode_item) {
216 _percussion_mode_item->set_active (_note_mode == Percussive);
221 MidiTimeAxisView::~MidiTimeAxisView ()
223 delete _piano_roll_header;
224 _piano_roll_header = 0;
226 delete _range_scroomer;
229 delete controller_menu;
232 void MidiTimeAxisView::model_changed()
234 std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
235 .custom_device_mode_names_by_model(_model_selector.get_active_text());
237 _custom_device_mode_selector.clear_items();
239 for (std::list<std::string>::const_iterator i = device_modes.begin();
240 i != device_modes.end(); ++i) {
241 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
242 _custom_device_mode_selector.append_text(*i);
245 _custom_device_mode_selector.set_active(0);
248 void MidiTimeAxisView::custom_device_mode_changed()
250 _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
251 _custom_device_mode_selector.get_active_text());
255 MidiTimeAxisView::midi_view()
257 return dynamic_cast<MidiStreamView*>(_view);
261 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
264 xml_node->add_property ("shown-editor", "yes");
266 guint32 ret = TimeAxisView::show_at (y, nth, parent);
271 MidiTimeAxisView::hide ()
274 xml_node->add_property ("shown-editor", "no");
276 TimeAxisView::hide ();
280 MidiTimeAxisView::set_height (uint32_t h)
282 RouteTimeAxisView::set_height (h);
284 if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
285 _midi_controls_box.show_all ();
287 _midi_controls_box.hide();
290 if (height >= KEYBOARD_MIN_HEIGHT) {
291 if (is_track() && _range_scroomer)
292 _range_scroomer->show();
293 if (is_track() && _piano_roll_header)
294 _piano_roll_header->show();
296 if (is_track() && _range_scroomer)
297 _range_scroomer->hide();
298 if (is_track() && _piano_roll_header)
299 _piano_roll_header->hide();
304 MidiTimeAxisView::append_extra_display_menu_items ()
306 using namespace Menu_Helpers;
308 MenuList& items = display_menu->items();
311 Menu *range_menu = manage(new Menu);
312 MenuList& range_items = range_menu->items();
313 range_menu->set_name ("ArdourContextMenu");
315 range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
316 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
317 MidiStreamView::FullRange)));
319 range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
320 sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
321 MidiStreamView::ContentsRange)));
323 items.push_back (MenuElem (_("Note range"), *range_menu));
324 items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
325 items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
327 items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
328 _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
332 MidiTimeAxisView::build_def_channel_menu ()
334 using namespace Menu_Helpers;
336 default_channel_menu = manage (new Menu ());
338 uint8_t defchn = midi_track()->default_channel();
339 MenuList& def_channel_items = default_channel_menu->items();
341 RadioMenuItem::Group dc_group;
343 for (int i = 0; i < 16; ++i) {
345 snprintf (buf, sizeof (buf), "%d", i+1);
347 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
348 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
349 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
350 item->set_active ((i == defchn));
353 return default_channel_menu;
357 MidiTimeAxisView::set_default_channel (int chn)
359 midi_track()->set_default_channel (chn);
363 MidiTimeAxisView::toggle_midi_thru ()
365 if (!_midi_thru_item) {
369 bool view_yn = _midi_thru_item->get_active();
370 if (view_yn != midi_track()->midi_thru()) {
371 midi_track()->set_midi_thru (view_yn);
376 MidiTimeAxisView::build_automation_action_menu ()
378 using namespace Menu_Helpers;
380 /* If we have a controller menu, we need to detach it before
381 RouteTimeAxis::build_automation_action_menu destroys the
382 menu it is attached to. Otherwise GTK destroys
383 controller_menu's gobj, meaning that it can't be reattached
384 below. See bug #3134.
387 if (controller_menu) {
388 detach_menu (*controller_menu);
391 _channel_command_menu_map.clear ();
392 RouteTimeAxisView::build_automation_action_menu ();
394 MenuList& automation_items = automation_action_menu->items();
396 uint16_t selected_channels = _channel_selector.get_selected_channels();
398 if (selected_channels != 0) {
400 automation_items.push_back (SeparatorElem());
402 /* these 3 MIDI "command" types are semantically more like automation than note data,
403 but they are not MIDI controllers. We give them special status in this menu, since
404 they will not show up in the controller list and anyone who actually knows
405 something about MIDI (!) would not expect to find them there.
408 add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, 0);
409 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
410 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
412 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
413 since it might need to be updated after a channel mode change or other change. Also detach it
414 first in case it has been used anywhere else.
417 build_controller_menu ();
419 automation_items.push_back (SeparatorElem());
420 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
422 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
428 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
430 uint16_t selected_channels = _channel_selector.get_selected_channels();
432 for (uint8_t chn = 0; chn < 16; chn++) {
433 if (selected_channels & (0x0001 << chn)) {
435 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
436 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
439 menu->set_active (yn);
446 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
448 using namespace Menu_Helpers;
450 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
453 uint16_t selected_channels = _channel_selector.get_selected_channels();
456 for (uint8_t chn = 0; chn < 16; chn++) {
457 if (selected_channels & (0x0001 << chn)) {
466 /* multiple channels - create a submenu, with 1 item per channel */
468 Menu* chn_menu = manage (new Menu);
469 MenuList& chn_items (chn_menu->items());
470 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
472 /* add a couple of items to hide/show all of them */
474 chn_items.push_back (MenuElem (_("Hide all channels"),
475 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
476 false, param_without_channel)));
477 chn_items.push_back (MenuElem (_("Show all channels"),
478 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
479 true, param_without_channel)));
481 for (uint8_t chn = 0; chn < 16; chn++) {
482 if (selected_channels & (0x0001 << chn)) {
484 /* for each selected channel, add a menu item for this controller */
486 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
487 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
488 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
489 fully_qualified_param)));
491 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
492 bool visible = false;
495 if (track->marked_for_display()) {
500 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
501 _channel_command_menu_map[fully_qualified_param] = cmi;
502 cmi->set_active (visible);
506 /* now create an item in the parent menu that has the per-channel list as a submenu */
508 items.push_back (MenuElem (label, *chn_menu));
512 /* just one channel - create a single menu item for this command+channel combination*/
514 for (uint8_t chn = 0; chn < 16; chn++) {
515 if (selected_channels & (0x0001 << chn)) {
517 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
518 items.push_back (CheckMenuElem (label,
519 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
520 fully_qualified_param)));
522 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
523 bool visible = false;
526 if (track->marked_for_display()) {
531 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
532 _channel_command_menu_map[fully_qualified_param] = cmi;
533 cmi->set_active (visible);
535 /* one channel only */
543 MidiTimeAxisView::build_controller_menu ()
545 using namespace Menu_Helpers;
547 if (controller_menu) {
548 /* it exists and has not been invalidated by a channel mode change, so just return it */
552 controller_menu = new Menu; // explicitly managed by us
553 MenuList& items (controller_menu->items());
555 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
556 for each controller+channel combination covering the currently selected channels for this track
559 uint16_t selected_channels = _channel_selector.get_selected_channels();
561 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
566 for (uint8_t chn = 0; chn < 16; chn++) {
567 if (selected_channels & (0x0001 << chn)) {
574 /* loop over all 127 MIDI controllers, in groups of 16 */
576 for (int i = 0; i < 127; i += 16) {
578 Menu* ctl_menu = manage (new Menu);
579 MenuList& ctl_items (ctl_menu->items());
582 /* for each controller, consider whether to create a submenu or a single item */
584 for (int ctl = i; ctl < i+16; ++ctl) {
588 /* multiple channels - create a submenu, with 1 item per channel */
590 Menu* chn_menu = manage (new Menu);
591 MenuList& chn_items (chn_menu->items());
593 /* add a couple of items to hide/show this controller on all channels */
595 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
596 chn_items.push_back (MenuElem (_("Hide all channels"),
597 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
598 false, param_without_channel)));
599 chn_items.push_back (MenuElem (_("Show all channels"),
600 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
601 true, param_without_channel)));
603 for (uint8_t chn = 0; chn < 16; chn++) {
604 if (selected_channels & (0x0001 << chn)) {
606 /* for each selected channel, add a menu item for this controller */
608 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
609 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
610 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
611 fully_qualified_param)));
613 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
614 bool visible = false;
617 if (track->marked_for_display()) {
622 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
623 _controller_menu_map[fully_qualified_param] = cmi;
624 cmi->set_active (visible);
628 /* add the per-channel menu to the list of controllers, with the name of the controller */
629 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
630 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
634 /* just one channel - create a single menu item for this ctl+channel combination*/
636 for (uint8_t chn = 0; chn < 16; chn++) {
637 if (selected_channels & (0x0001 << chn)) {
639 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
640 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
641 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
642 fully_qualified_param)));
644 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
645 bool visible = false;
648 if (track->marked_for_display()) {
653 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
654 _controller_menu_map[fully_qualified_param] = cmi;
655 cmi->set_active (visible);
657 /* one channel only */
664 /* add the menu for this block of controllers to the overall controller menu */
666 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
671 MidiTimeAxisView::build_note_mode_menu()
673 using namespace Menu_Helpers;
675 Menu* mode_menu = manage (new Menu);
676 MenuList& items = mode_menu->items();
677 mode_menu->set_name ("ArdourContextMenu");
679 RadioMenuItem::Group mode_group;
680 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
681 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
682 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
683 _note_mode_item->set_active(_note_mode == Sustained);
685 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
686 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
687 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
688 _percussion_mode_item->set_active(_note_mode == Percussive);
694 MidiTimeAxisView::build_color_mode_menu()
696 using namespace Menu_Helpers;
698 Menu* mode_menu = manage (new Menu);
699 MenuList& items = mode_menu->items();
700 mode_menu->set_name ("ArdourContextMenu");
702 RadioMenuItem::Group mode_group;
703 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
704 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
705 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
706 _meter_color_mode_item->set_active(_color_mode == MeterColors);
708 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
709 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
710 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
711 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
713 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
714 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
715 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
716 _channel_color_mode_item->set_active(_color_mode == TrackColor);
722 MidiTimeAxisView::set_note_mode(NoteMode mode)
724 if (_note_mode != mode || midi_track()->note_mode() != mode) {
726 midi_track()->set_note_mode(mode);
727 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
728 _view->redisplay_track();
733 MidiTimeAxisView::set_color_mode(ColorMode mode)
735 if (_color_mode != mode) {
736 if (mode == ChannelColors) {
737 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
739 _channel_selector.set_default_channel_color();
743 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
744 _view->redisplay_track();
749 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
751 if (!_ignore_signals)
752 midi_view()->set_note_range(range);
757 MidiTimeAxisView::update_range()
759 MidiGhostRegion* mgr;
761 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
762 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
769 MidiTimeAxisView::show_all_automation ()
772 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
774 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
775 create_automation_child(*i, true);
779 RouteTimeAxisView::show_all_automation ();
783 MidiTimeAxisView::show_existing_automation ()
786 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
788 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
789 create_automation_child(*i, true);
793 RouteTimeAxisView::show_existing_automation ();
796 /** Create an automation track for the given parameter (pitch bend, channel pressure).
799 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
801 /* These controllers are region "automation", so we do not create
802 * an AutomationList/Line for the track */
804 if (param.type() == NullAutomation) {
805 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
809 AutomationTracks::iterator existing = _automation_tracks.find (param);
810 if (existing != _automation_tracks.end()) {
814 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
818 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
819 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
824 _route->describe_parameter(param)));
826 add_automation_child (param, track, show);
831 MidiTimeAxisView::route_active_changed ()
833 RouteUI::route_active_changed ();
836 if (_route->active()) {
837 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
838 controls_base_selected_name = "MidiTrackControlsBaseSelected";
839 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
841 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
842 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
843 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
849 if (_route->active()) {
850 controls_ebox.set_name ("BusControlsBaseUnselected");
851 controls_base_selected_name = "BusControlsBaseSelected";
852 controls_base_unselected_name = "BusControlsBaseUnselected";
854 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
855 controls_base_selected_name = "BusControlsBaseInactiveSelected";
856 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
862 MidiTimeAxisView::start_step_editing ()
864 step_edit_insert_position = _editor.get_preferred_edit_position ();
865 step_edit_beat_pos = 0;
866 step_edit_region = playlist()->top_region_at (step_edit_insert_position);
868 if (step_edit_region) {
869 RegionView* rv = view()->find_view (step_edit_region);
870 step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
872 step_edit_region_view = 0;
875 midi_track()->set_step_editing (true);
879 MidiTimeAxisView::stop_step_editing ()
881 midi_track()->set_step_editing (false);
885 MidiTimeAxisView::check_step_edit ()
887 MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
888 Evoral::Note<Evoral::MusicalTime> note;
890 uint32_t bufsize = 32;
892 buf = new uint8_t[bufsize];
894 while (incoming.read_space()) {
896 Evoral::EventType type;
899 incoming.read_prefix (&time, &type, &size);
901 if (size > bufsize) {
904 buf = new uint8_t[bufsize];
907 incoming.read_contents (size, buf);
909 if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
911 if (step_edit_region == 0) {
913 step_edit_region = add_region (step_edit_insert_position);
914 RegionView* rv = view()->find_view (step_edit_region);
917 step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
919 fatal << X_("programming error: no view found for new MIDI region") << endmsg;
924 if (step_edit_region_view) {
927 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
933 step_edit_region_view->add_note (buf[0] & 0xf, buf[1], buf[2], step_edit_beat_pos, beats);
934 step_edit_beat_pos += beats;
942 MidiTimeAxisView::step_edit_rest ()
945 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
946 step_edit_beat_pos += beats;
949 boost::shared_ptr<Region>
950 MidiTimeAxisView::add_region (nframes64_t pos)
952 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
954 real_editor->begin_reversible_command (_("create region"));
955 playlist()->clear_history ();
957 framepos_t start = pos;
958 real_editor->snap_to (start, -1);
959 const Meter& m = _session->tempo_map().meter_at(start);
960 const Tempo& t = _session->tempo_map().tempo_at(start);
961 double length = floor (m.frames_per_bar(t, _session->frame_rate()));
963 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
964 view()->trackview().track()->name());
967 plist.add (ARDOUR::Properties::start, 0);
968 plist.add (ARDOUR::Properties::length, length);
969 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
971 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
973 playlist()->add_region (region, start);
974 _session->add_command (new StatefulDiffCommand (playlist()));
976 real_editor->commit_reversible_command();
982 MidiTimeAxisView::add_note_selection (uint8_t note)
984 if (!_editor.internal_editing()) {
988 uint16_t chn_mask = _channel_selector.get_selected_channels();
990 if (_view->num_selected_regionviews() == 0) {
991 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
993 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
998 MidiTimeAxisView::extend_note_selection (uint8_t note)
1000 if (!_editor.internal_editing()) {
1004 uint16_t chn_mask = _channel_selector.get_selected_channels();
1006 if (_view->num_selected_regionviews() == 0) {
1007 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1009 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1014 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1016 if (!_editor.internal_editing()) {
1020 uint16_t chn_mask = _channel_selector.get_selected_channels();
1022 if (_view->num_selected_regionviews() == 0) {
1023 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1025 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1030 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1032 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1036 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1038 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1042 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1044 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1048 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1050 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1054 uint16_t selected_channels = _channel_selector.get_selected_channels();
1055 bool changed = false;
1059 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1061 for (uint32_t chn = 0; chn < 16; ++chn) {
1062 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1063 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1069 if ((selected_channels & (0x0001 << chn)) == 0) {
1070 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1071 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1073 changed = track->set_visibility (false) || changed;
1075 changed = track->set_visibility (true) || changed;
1082 /* TODO: Bender, PgmChange, Pressure */
1084 /* invalidate the controller menu, so that we rebuilt it next time */
1085 _controller_menu_map.clear ();
1086 delete controller_menu;
1087 controller_menu = 0;
1090 _route->gui_changed ("track_height", this);
1095 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1097 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1102 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1103 if (i != _controller_menu_map.end()) {
1107 i = _channel_command_menu_map.find (param);
1108 if (i != _channel_command_menu_map.end()) {