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());
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().get(),
963 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 _controller_menu_map
.clear ();
1085 delete controller_menu
;
1086 controller_menu
= 0;
1089 _route
->gui_changed ("track_height", this);
1094 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param
)
1096 Gtk::CheckMenuItem
* m
= RouteTimeAxisView::automation_child_menu_item (param
);
1101 ParameterMenuMap::iterator i
= _controller_menu_map
.find (param
);
1102 if (i
!= _controller_menu_map
.end()) {
1106 i
= _channel_command_menu_map
.find (param
);
1107 if (i
!= _channel_command_menu_map
.end()) {