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_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 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 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
438 menu->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 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
491 bool visible = false;
494 if (track->marked_for_display()) {
499 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
500 _parameter_menu_map[fully_qualified_param] = cmi;
501 cmi->set_active (visible);
505 /* now create an item in the parent menu that has the per-channel list as a submenu */
507 items.push_back (MenuElem (label, *chn_menu));
511 /* just one channel - create a single menu item for this command+channel combination*/
513 for (uint8_t chn = 0; chn < 16; chn++) {
514 if (selected_channels & (0x0001 << chn)) {
516 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
517 items.push_back (CheckMenuElem (label,
518 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
519 fully_qualified_param)));
521 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
522 bool visible = false;
525 if (track->marked_for_display()) {
530 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
531 _parameter_menu_map[fully_qualified_param] = cmi;
532 cmi->set_active (visible);
534 /* one channel only */
542 MidiTimeAxisView::build_controller_menu ()
544 using namespace Menu_Helpers;
546 if (controller_menu) {
547 /* it exists and has not been invalidated by a channel mode change, so just return it */
551 controller_menu = new Menu; // explicitly managed by us
552 MenuList& items (controller_menu->items());
554 /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
555 for each controller+channel combination covering the currently selected channels for this track
558 uint16_t selected_channels = _channel_selector.get_selected_channels();
560 /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
565 for (uint8_t chn = 0; chn < 16; chn++) {
566 if (selected_channels & (0x0001 << chn)) {
573 /* loop over all 127 MIDI controllers, in groups of 16 */
575 for (int i = 0; i < 127; i += 16) {
577 Menu* ctl_menu = manage (new Menu);
578 MenuList& ctl_items (ctl_menu->items());
581 /* for each controller, consider whether to create a submenu or a single item */
583 for (int ctl = i; ctl < i+16; ++ctl) {
587 /* multiple channels - create a submenu, with 1 item per channel */
589 Menu* chn_menu = manage (new Menu);
590 MenuList& chn_items (chn_menu->items());
592 /* add a couple of items to hide/show this controller on all channels */
594 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
595 chn_items.push_back (MenuElem (_("Hide all channels"),
596 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
597 false, param_without_channel)));
598 chn_items.push_back (MenuElem (_("Show all channels"),
599 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
600 true, param_without_channel)));
602 for (uint8_t chn = 0; chn < 16; chn++) {
603 if (selected_channels & (0x0001 << chn)) {
605 /* for each selected channel, add a menu item for this controller */
607 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
608 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
609 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
610 fully_qualified_param)));
612 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
613 bool visible = false;
616 if (track->marked_for_display()) {
621 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
622 _parameter_menu_map[fully_qualified_param] = cmi;
623 cmi->set_active (visible);
627 /* add the per-channel menu to the list of controllers, with the name of the controller */
628 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
629 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
633 /* just one channel - create a single menu item for this ctl+channel combination*/
635 for (uint8_t chn = 0; chn < 16; chn++) {
636 if (selected_channels & (0x0001 << chn)) {
638 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
639 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
640 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
641 fully_qualified_param)));
643 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
644 bool visible = false;
647 if (track->marked_for_display()) {
652 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
653 _parameter_menu_map[fully_qualified_param] = cmi;
654 cmi->set_active (visible);
656 /* one channel only */
663 /* add the menu for this block of controllers to the overall controller menu */
665 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
670 MidiTimeAxisView::build_note_mode_menu()
672 using namespace Menu_Helpers;
674 Menu* mode_menu = manage (new Menu);
675 MenuList& items = mode_menu->items();
676 mode_menu->set_name ("ArdourContextMenu");
678 RadioMenuItem::Group mode_group;
679 items.push_back (RadioMenuElem (mode_group, _("Sustained"),
680 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
681 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
682 _note_mode_item->set_active(_note_mode == Sustained);
684 items.push_back (RadioMenuElem (mode_group, _("Percussive"),
685 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
686 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
687 _percussion_mode_item->set_active(_note_mode == Percussive);
693 MidiTimeAxisView::build_color_mode_menu()
695 using namespace Menu_Helpers;
697 Menu* mode_menu = manage (new Menu);
698 MenuList& items = mode_menu->items();
699 mode_menu->set_name ("ArdourContextMenu");
701 RadioMenuItem::Group mode_group;
702 items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
703 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
704 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
705 _meter_color_mode_item->set_active(_color_mode == MeterColors);
707 items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
708 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
709 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
710 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
712 items.push_back (RadioMenuElem (mode_group, _("Track Color"),
713 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
714 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
715 _channel_color_mode_item->set_active(_color_mode == TrackColor);
721 MidiTimeAxisView::set_note_mode(NoteMode mode)
723 if (_note_mode != mode || midi_track()->note_mode() != mode) {
725 midi_track()->set_note_mode(mode);
726 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
727 _view->redisplay_track();
732 MidiTimeAxisView::set_color_mode(ColorMode mode)
734 if (_color_mode != mode) {
735 if (mode == ChannelColors) {
736 _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
738 _channel_selector.set_default_channel_color();
742 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
743 _view->redisplay_track();
748 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
750 if (!_ignore_signals)
751 midi_view()->set_note_range(range);
756 MidiTimeAxisView::update_range()
758 MidiGhostRegion* mgr;
760 for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
761 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
768 MidiTimeAxisView::show_all_automation ()
771 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
773 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
774 create_automation_child(*i, true);
778 RouteTimeAxisView::show_all_automation ();
782 MidiTimeAxisView::show_existing_automation ()
785 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
787 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
788 create_automation_child(*i, true);
792 RouteTimeAxisView::show_existing_automation ();
795 /** Hide an automation track for the given parameter (pitch bend, channel pressure).
798 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
800 /* These controllers are region "automation", so we do not create
801 * an AutomationList/Line for the track */
803 if (param.type() == NullAutomation) {
804 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
808 AutomationTracks::iterator existing = _automation_tracks.find (param);
809 if (existing != _automation_tracks.end()) {
813 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
817 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
818 _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
823 _route->describe_parameter(param)));
825 add_automation_child (param, track, show);
830 MidiTimeAxisView::route_active_changed ()
832 RouteUI::route_active_changed ();
835 if (_route->active()) {
836 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
837 controls_base_selected_name = "MidiTrackControlsBaseSelected";
838 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
840 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
841 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
842 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
848 if (_route->active()) {
849 controls_ebox.set_name ("BusControlsBaseUnselected");
850 controls_base_selected_name = "BusControlsBaseSelected";
851 controls_base_unselected_name = "BusControlsBaseUnselected";
853 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
854 controls_base_selected_name = "BusControlsBaseInactiveSelected";
855 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
861 MidiTimeAxisView::start_step_editing ()
863 step_edit_insert_position = _editor.get_preferred_edit_position ();
864 step_edit_beat_pos = 0;
865 step_edit_region = playlist()->top_region_at (step_edit_insert_position);
867 if (step_edit_region) {
868 RegionView* rv = view()->find_view (step_edit_region);
869 step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
871 step_edit_region_view = 0;
874 midi_track()->set_step_editing (true);
878 MidiTimeAxisView::stop_step_editing ()
880 midi_track()->set_step_editing (false);
884 MidiTimeAxisView::check_step_edit ()
886 MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
887 Evoral::Note<Evoral::MusicalTime> note;
889 uint32_t bufsize = 32;
891 buf = new uint8_t[bufsize];
893 while (incoming.read_space()) {
895 Evoral::EventType type;
898 incoming.read_prefix (&time, &type, &size);
900 if (size > bufsize) {
903 buf = new uint8_t[bufsize];
906 incoming.read_contents (size, buf);
908 if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
910 if (step_edit_region == 0) {
912 step_edit_region = add_region (step_edit_insert_position);
913 RegionView* rv = view()->find_view (step_edit_region);
916 step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
918 fatal << X_("programming error: no view found for new MIDI region") << endmsg;
923 if (step_edit_region_view) {
926 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
932 step_edit_region_view->add_note (buf[0] & 0xf, buf[1], buf[2], step_edit_beat_pos, beats);
933 step_edit_beat_pos += beats;
941 MidiTimeAxisView::step_edit_rest ()
944 Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
945 step_edit_beat_pos += beats;
948 boost::shared_ptr<Region>
949 MidiTimeAxisView::add_region (nframes64_t pos)
951 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
953 real_editor->begin_reversible_command (_("create region"));
954 playlist()->clear_history ();
956 framepos_t start = pos;
957 real_editor->snap_to (start, -1);
958 const Meter& m = _session->tempo_map().meter_at(start);
959 const Tempo& t = _session->tempo_map().tempo_at(start);
960 double length = floor (m.frames_per_bar(t, _session->frame_rate()));
962 boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track()->name());
966 plist.add (ARDOUR::Properties::start, 0);
967 plist.add (ARDOUR::Properties::length, length);
968 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
970 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
972 playlist()->add_region (region, start);
973 _session->add_command (new StatefulDiffCommand (playlist()));
975 real_editor->commit_reversible_command();
981 MidiTimeAxisView::add_note_selection (uint8_t note)
983 if (!_editor.internal_editing()) {
987 uint16_t chn_mask = _channel_selector.get_selected_channels();
989 if (_view->num_selected_regionviews() == 0) {
990 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
992 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
997 MidiTimeAxisView::extend_note_selection (uint8_t note)
999 if (!_editor.internal_editing()) {
1003 uint16_t chn_mask = _channel_selector.get_selected_channels();
1005 if (_view->num_selected_regionviews() == 0) {
1006 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1008 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
1013 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1015 if (!_editor.internal_editing()) {
1019 uint16_t chn_mask = _channel_selector.get_selected_channels();
1021 if (_view->num_selected_regionviews() == 0) {
1022 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1024 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
1029 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1031 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1035 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1037 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1041 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1043 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1047 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1049 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1053 uint16_t selected_channels = _channel_selector.get_selected_channels();
1054 bool changed = false;
1058 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1060 for (uint32_t chn = 0; chn < 16; ++chn) {
1061 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1062 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1068 if ((selected_channels & (0x0001 << chn)) == 0) {
1069 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1070 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1072 changed = track->set_visibility (false) || changed;
1074 changed = track->set_visibility (true) || changed;
1081 /* TODO: Bender, PgmChange, Pressure */
1083 /* invalidate the controller menu, so that we rebuilt it next time */
1084 delete controller_menu;
1085 controller_menu = 0;
1088 _route->gui_changed ("track_height", this);