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/stop_signal.h>
39 #include <gtkmm2ext/bindable_button.h>
40 #include <gtkmm2ext/utils.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();
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 RouteTimeAxisView::build_automation_action_menu ();
393 MenuList& automation_items = automation_action_menu->items();
395 uint16_t selected_channels = _channel_selector.get_selected_channels();
397 if (selected_channels != 0) {
399 automation_items.push_back (SeparatorElem());
401 /* these 3 MIDI "command" types are semantically more like automation than note data,
402 but they are not MIDI controllers. We give them special status in this menu, since
403 they will not show up in the controller list and anyone who actually knows
404 something about MIDI (!) would not expect to find them there.
407 add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, MIDI_CMD_PGM_CHANGE);
408 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, MIDI_CMD_BENDER);
409 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, MIDI_CMD_CHANNEL_PRESSURE);
411 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
412 since it might need to be updated after a channel mode change or other change. Also detach it
413 first in case it has been used anywhere else.
416 build_controller_menu ();
418 automation_items.push_back (SeparatorElem());
419 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
421 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
427 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
429 uint16_t selected_channels = _channel_selector.get_selected_channels();
431 for (uint8_t chn = 0; chn < 16; chn++) {
432 if (selected_channels & (0x0001 << chn)) {
434 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
435 RouteAutomationNode* node = automation_track (fully_qualified_param);
437 if (node && node->menu_item) {
438 node->menu_item->set_active (yn);
445 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
447 using namespace Menu_Helpers;
449 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
452 uint16_t selected_channels = _channel_selector.get_selected_channels();
455 for (uint8_t chn = 0; chn < 16; chn++) {
456 if (selected_channels & (0x0001 << chn)) {
465 /* multiple channels - create a submenu, with 1 item per channel */
467 Menu* chn_menu = manage (new Menu);
468 MenuList& chn_items (chn_menu->items());
469 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
471 /* add a couple of items to hide/show all of them */
473 chn_items.push_back (MenuElem (_("Hide all channels"),
474 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
475 false, param_without_channel)));
476 chn_items.push_back (MenuElem (_("Show all channels"),
477 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
478 true, param_without_channel)));
480 for (uint8_t chn = 0; chn < 16; chn++) {
481 if (selected_channels & (0x0001 << chn)) {
483 /* for each selected channel, add a menu item for this controller */
485 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
486 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
487 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
488 fully_qualified_param)));
490 RouteAutomationNode* node = automation_track (fully_qualified_param);
491 bool visible = false;
494 if (node->track->marked_for_display()) {
499 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
501 node->menu_item = cmi;
504 cmi->set_active (visible);
506 parameter_menu_map[fully_qualified_param] = cmi;
510 /* now create an item in the parent menu that has the per-channel list as a submenu */
512 items.push_back (MenuElem (label, *chn_menu));
516 /* just one channel - create a single menu item for this command+channel combination*/
518 for (uint8_t chn = 0; chn < 16; chn++) {
519 if (selected_channels & (0x0001 << chn)) {
521 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
522 items.push_back (CheckMenuElem (label,
523 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
524 fully_qualified_param)));
526 RouteAutomationNode* node = automation_track (fully_qualified_param);
527 bool visible = false;
530 if (node->track->marked_for_display()) {
535 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
537 node->menu_item = cmi;
540 cmi->set_active (visible);
542 parameter_menu_map[fully_qualified_param] = cmi;
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 RouteAutomationNode* node = automation_track (fully_qualified_param);
623 bool visible = false;
626 if (node->track->marked_for_display()) {
631 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
634 node->menu_item = cmi;
637 cmi->set_active (visible);
639 parameter_menu_map[fully_qualified_param] = cmi;
643 /* add the per-channel menu to the list of controllers, with the name of the controller */
644 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
645 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
649 /* just one channel - create a single menu item for this ctl+channel combination*/
651 for (uint8_t chn = 0; chn < 16; chn++) {
652 if (selected_channels & (0x0001 << chn)) {
654 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
655 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
656 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
657 fully_qualified_param)));
659 RouteAutomationNode* node = automation_track (fully_qualified_param);
660 bool visible = false;
663 if (node->track->marked_for_display()) {
668 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
670 node->menu_item = cmi;
673 cmi->set_active (visible);
676 parameter_menu_map[fully_qualified_param] = cmi;
677 /* one channel only */
684 /* add the menu for this block of controllers to the overall controller menu */
686 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
691 MidiTimeAxisView::build_note_mode_menu()
693 using namespace Menu_Helpers;
695 Menu* mode_menu = manage (new Menu);
696 MenuList& items = mode_menu->items();
697 mode_menu->set_name ("ArdourContextMenu");
699 RadioMenuItem::Group mode_group;
700 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
701 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
702 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
703 _note_mode_item->set_active(_note_mode == Sustained);
705 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
706 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
707 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
708 _percussion_mode_item->set_active(_note_mode == Percussive);
714 MidiTimeAxisView::build_color_mode_menu()
716 using namespace Menu_Helpers;
718 Menu* mode_menu = manage (new Menu);
719 MenuList& items = mode_menu->items();
720 mode_menu->set_name ("ArdourContextMenu");
722 RadioMenuItem::Group mode_group;
723 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
724 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
725 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
726 _meter_color_mode_item->set_active(_color_mode == MeterColors);
728 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
729 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
730 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
731 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
733 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
734 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
735 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
736 _channel_color_mode_item->set_active(_color_mode == TrackColor);
742 MidiTimeAxisView::set_note_mode(NoteMode mode)
744 if (_note_mode != mode || midi_track()->note_mode() != mode) {
746 midi_track()->set_note_mode(mode);
747 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
748 _view->redisplay_track();
753 MidiTimeAxisView::set_color_mode(ColorMode mode)
755 if (_color_mode != mode) {
756 if (mode == ChannelColors) {
757 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
759 _channel_selector.set_default_channel_color();
763 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
764 _view->redisplay_track();
769 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
771 if (!_ignore_signals)
772 midi_view()->set_note_range(range);
777 MidiTimeAxisView::update_range()
779 MidiGhostRegion* mgr;
781 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
782 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
789 MidiTimeAxisView::show_all_automation ()
792 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
794 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
795 create_automation_child(*i, true);
799 RouteTimeAxisView::show_all_automation ();
803 MidiTimeAxisView::show_existing_automation ()
806 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
808 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
809 create_automation_child(*i, true);
813 RouteTimeAxisView::show_existing_automation ();
816 /** Hide an automation track for the given parameter (pitch bend, channel pressure).
819 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
821 /* These controllers are region "automation", so we do not create
822 * an AutomationList/Line for the track */
824 if (param.type() == NullAutomation) {
825 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
829 AutomationTracks::iterator existing = _automation_tracks.find (param);
830 if (existing != _automation_tracks.end()) {
834 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
838 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
839 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
844 _route->describe_parameter(param)));
846 add_automation_child (param, track, show);
851 MidiTimeAxisView::route_active_changed ()
853 RouteUI::route_active_changed ();
856 if (_route->active()) {
857 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
858 controls_base_selected_name = "MidiTrackControlsBaseSelected";
859 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
861 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
862 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
863 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
869 if (_route->active()) {
870 controls_ebox.set_name ("BusControlsBaseUnselected");
871 controls_base_selected_name = "BusControlsBaseSelected";
872 controls_base_unselected_name = "BusControlsBaseUnselected";
874 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
875 controls_base_selected_name = "BusControlsBaseInactiveSelected";
876 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
882 MidiTimeAxisView::start_step_editing ()
884 step_edit_insert_position = _editor.get_preferred_edit_position ();
885 step_edit_beat_pos = 0;
886 step_edit_region = playlist()->top_region_at (step_edit_insert_position);
888 if (step_edit_region) {
889 RegionView* rv = view()->find_view (step_edit_region);
890 step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
892 step_edit_region_view = 0;
895 midi_track()->set_step_editing (true);
899 MidiTimeAxisView::stop_step_editing ()
901 midi_track()->set_step_editing (false);
905 MidiTimeAxisView::check_step_edit ()
907 MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
908 Evoral::Note<Evoral::MusicalTime> note;
910 uint32_t bufsize = 32;
912 buf = new uint8_t[bufsize];
914 while (incoming.read_space()) {
916 Evoral::EventType type;
919 incoming.read_prefix (&time, &type, &size);
921 if (size > bufsize) {
924 buf = new uint8_t[bufsize];
927 incoming.read_contents (size, buf);
929 if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
931 if (step_edit_region == 0) {
933 step_edit_region = add_region (step_edit_insert_position);
934 RegionView* rv = view()->find_view (step_edit_region);
937 step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
939 fatal << X_("programming error: no view found for new MIDI region") << endmsg;
944 if (step_edit_region_view) {
947 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
953 step_edit_region_view->add_note (buf[0] & 0xf, buf[1], buf[2], step_edit_beat_pos, beats);
954 step_edit_beat_pos += beats;
962 MidiTimeAxisView::step_edit_rest ()
965 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
966 step_edit_beat_pos += beats;
969 boost::shared_ptr<Region>
970 MidiTimeAxisView::add_region (nframes64_t pos)
972 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
974 real_editor->begin_reversible_command (_("create region"));
975 playlist()->clear_history ();
977 framepos_t start = pos;
978 real_editor->snap_to (start, -1);
979 const Meter& m = _session->tempo_map().meter_at(start);
980 const Tempo& t = _session->tempo_map().tempo_at(start);
981 double length = floor (m.frames_per_bar(t, _session->frame_rate()));
983 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track()->name());
987 plist.add (ARDOUR::Properties::start, 0);
988 plist.add (ARDOUR::Properties::length, length);
989 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
991 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
993 playlist()->add_region (region, start);
994 _session->add_command (new StatefulDiffCommand (playlist()));
996 real_editor->commit_reversible_command();
1002 MidiTimeAxisView::add_note_selection (uint8_t note)
1004 if (!_editor.internal_editing()) {
1008 uint16_t chn_mask = _channel_selector.get_selected_channels();
1010 if (_view->num_selected_regionviews() == 0) {
1011 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
1013 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
1018 MidiTimeAxisView::extend_note_selection (uint8_t note)
1020 if (!_editor.internal_editing()) {
1024 uint16_t chn_mask = _channel_selector.get_selected_channels();
1026 if (_view->num_selected_regionviews() == 0) {
1027 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1029 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1034 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1036 if (!_editor.internal_editing()) {
1040 uint16_t chn_mask = _channel_selector.get_selected_channels();
1042 if (_view->num_selected_regionviews() == 0) {
1043 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1045 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1050 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1052 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1056 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1058 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1062 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1064 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1068 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1070 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1074 uint16_t selected_channels = _channel_selector.get_selected_channels();
1075 bool changed = false;
1079 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1081 for (uint32_t chn = 0; chn < 16; ++chn) {
1082 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1083 RouteAutomationNode* node = automation_track (fully_qualified_param);
1089 if ((selected_channels & (0x0001 << chn)) == 0) {
1090 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1091 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1093 changed = node->track->set_visibility (false) || changed;
1095 changed = node->track->set_visibility (true) || changed;
1102 /* TODO: Bender, PgmChange, Pressure */
1104 /* invalidate the controller menu, so that we rebuilt it next time */
1105 delete controller_menu;
1106 controller_menu = 0;
1109 _route->gui_changed ("track_height", this);