ardour
midi_time_axis.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 Paul Davis
3 
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.
8 
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.
13 
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.
17 */
18 
19 #include <cstdlib>
20 #include <cmath>
21 
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25 
26 #include <sigc++/bind.h>
27 
28 #include "pbd/error.h"
29 #include "pbd/ffs.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
36 
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
40 #include "gtkmm2ext/utils.h"
41 
42 #include "ardour/event_type_map.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
62 
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
67 #include "editor.h"
68 #include "enums.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
71 #include "keyboard.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
82 #include "prompter.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
87 #include "utils.h"
88 #include "note_base.h"
89 
90 #include "ardour/midi_track.h"
91 
92 #include "i18n.h"
93 
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
96 using namespace PBD;
97 using namespace Gtk;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
100 using namespace std;
101 
102 // Minimum height at which a control is displayed
103 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
104 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
105 
106 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
107  : AxisView(sess) // virtually inherited
108  , RouteTimeAxisView(ed, sess, canvas)
109  , _ignore_signals(false)
110  , _range_scroomer(0)
111  , _piano_roll_header(0)
112  , _note_mode(Sustained)
113  , _note_mode_item(0)
114  , _percussion_mode_item(0)
115  , _color_mode(MeterColors)
116  , _meter_color_mode_item(0)
117  , _channel_color_mode_item(0)
118  , _track_color_mode_item(0)
119  , _channel_selector (0)
120  , _step_edit_item (0)
121  , controller_menu (0)
122  , _step_editor (0)
123 {
124 }
125 
126 void
128 {
129  _route = rt;
130 
131  _view = new MidiStreamView (*this);
132 
133  if (is_track ()) {
135  _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
136  _range_scroomer->DoubleClicked.connect (
137  sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
139  }
140 
141  /* This next call will result in our height being set up, so it must come after
142  the creation of the piano roll / range scroomer as their visibility is set up
143  when our height is.
144  */
146 
148 
149  subplugin_menu.set_name ("ArdourContextMenu");
150 
151  if (!gui_property ("note-range-min").empty ()) {
152  midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
153  atoi (gui_property ("note-range-max").c_str()),
154  true);
155  }
156 
157  midi_view()->NoteRangeChanged.connect (
158  sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
159  _view->ContentsHeightChanged.connect (
160  sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
161 
162  ignore_toggle = false;
163 
164  if (is_midi_track()) {
165  controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166  time_axis_frame.set_name ("MidiTimeAxisViewControlsBaseUnselected");
168  } else { // MIDI bus (which doesn't exist yet..)
169  controls_ebox.set_name ("MidiBusControlsBaseUnselected");
170  time_axis_frame.set_name ("MidiBusControlsBaseUnselected");
171  }
172 
173  /* if set_state above didn't create a gain automation child, we need to make one */
174  if (automation_child (GainAutomation) == 0) {
176  }
177 
178  /* if set_state above didn't create a mute automation child, we need to make one */
179  if (automation_child (MuteAutomation) == 0) {
181  }
182 
183  if (_route->panner_shell()) {
184  _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
185  }
186 
187  /* map current state of the route */
188  ensure_pan_views (false);
189 
191 
192  _route->processors_changed.connect (*this, invalidator (*this),
193  boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
194  gui_context());
195 
196  if (is_track()) {
198  sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
200  sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
202  sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
204  sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
205 
206  /* Suspend updates of the StreamView during scroomer drags to speed things up */
207  _range_scroomer->DragStarting.connect (
208  sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
209  _range_scroomer->DragFinishing.connect (
210  sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
211 
212  /* Put the scroomer and the keyboard in a VBox with a padding
213  label so that they can be reduced in height for stacked-view
214  tracks.
215  */
216 
217  HSeparator* separator = manage (new HSeparator());
218  separator->set_name("TrackSeparator");
219  separator->set_size_request(-1, 1);
220  separator->show();
221 
222  VBox* v = manage (new VBox);
223  HBox* h = manage (new HBox);
224  h->pack_end (*_piano_roll_header);
225  h->pack_end (*_range_scroomer);
226  v->pack_start (*separator, false, false);
227  v->pack_start (*h, true, true);
228  v->show ();
229  h->show ();
231  time_axis_hbox.pack_end(*v, false, false, 0);
232  midi_scroomer_size_group->add_widget (*v);
233 
234  controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
235  time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
236  controls_base_selected_name = "MidiTrackControlsBaseSelected";
237  controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
238 
239  midi_view()->NoteRangeChanged.connect (
240  sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 
242  /* ask for notifications of any new RegionViews */
243  _view->RegionViewAdded.connect (
244  sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 
247  *this, invalidator (*this),
249  gui_context());
251  *this, invalidator (*this),
253  gui_context());
255  *this, invalidator (*this),
257  gui_context());
259  *this, invalidator (*this),
261  gui_context());
262 
265 
266  if (!_editor.have_idled()) {
267  /* first idle will do what we need */
268  } else {
269  first_idle ();
270  }
271  }
272 
273  typedef MIDI::Name::MidiPatchManager PatchManager;
274 
275  PatchManager& patch_manager = PatchManager::instance();
276 
277  for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
278  m != patch_manager.devices_by_manufacturer().end(); ++m) {
279  Menu* menu = Gtk::manage(new Menu);
280  Menu_Helpers::MenuList& items = menu->items();
281 
282  // Build manufacturer submenu
283  for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
284  n != m->second.end(); ++n) {
285  Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
286  n->first.c_str(),
287  sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
288  n->first.c_str()));
289 
290  items.push_back(elem);
291  }
292 
293  // Add manufacturer submenu to selector
294  _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
295  }
296 
297  if (gui_property (X_("midnam-model-name")).empty()) {
298  set_gui_property (X_("midnam-model-name"), "Generic");
299  }
300 
301  if (gui_property (X_("midnam-custom-device-mode")).empty()) {
303  if (device_names) {
304  set_gui_property (X_("midnam-custom-device-mode"),
305  *device_names->custom_device_mode_names().begin());
306  }
307  }
308 
309  ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
311 
312  _midi_controls_box.set_homogeneous(false);
313  _midi_controls_box.set_border_width (2);
314 
315  _channel_status_box.set_homogeneous (false);
316  _channel_status_box.set_spacing (4);
317 
318  ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
319  channel_selector_button->set_name ("route button");
320  ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
321 
322  // Insert expanding space labels to get full width justification
323  _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
324  _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
325  _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
326  _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
327  _channel_status_box.pack_end (*channel_selector_button, false, false);
328  _channel_status_box.show_all ();
329 
330  channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
331 
332  _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
333 
334  if (!patch_manager.all_models().empty()) {
335 
336  _midnam_model_selector.show ();
337  _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
338 
340 
341  _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
342  }
343 
344  model_changed(gui_property(X_("midnam-model-name")));
345  custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
346 
347  controls_vbox.pack_start(_midi_controls_box, false, false);
348 
349  const string color_mode = gui_property ("color-mode");
350  if (!color_mode.empty()) {
354  }
355  }
356 
357  set_color_mode (_color_mode, true, false);
358 
359  const string note_mode = gui_property ("note-mode");
360  if (!note_mode.empty()) {
361  _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
362  if (_percussion_mode_item) {
364  }
365  }
366 
367  /* Look for any GUI object state nodes that represent automation children
368  * that should exist, and create the children.
369  */
370 
371  const list<string> gui_ids = gui_object_state().all_ids ();
372  for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
373  PBD::ID route_id;
374  bool has_parameter;
375  Evoral::Parameter parameter (0, 0, 0);
376 
378  *i, route_id, has_parameter, parameter);
379  if (p && route_id == _route->id () && has_parameter) {
380  const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
381  create_automation_child (parameter, string_is_affirmative (visible));
382  }
383  }
384 }
385 
386 void
388 {
389  if (is_track ()) {
390  _view->attach ();
391  }
392 }
393 
395 {
396  delete _channel_selector;
397 
398  delete _piano_roll_header;
399  _piano_roll_header = 0;
400 
401  delete _range_scroomer;
402  _range_scroomer = 0;
403 
404  delete controller_menu;
405  delete _step_editor;
406 }
407 
408 void
410 {
413 }
414 
415 void
416 MidiTimeAxisView::model_changed(const std::string& model)
417 {
418  set_gui_property (X_("midnam-model-name"), model);
419 
420  const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
422 
425 
426  for (std::list<std::string>::const_iterator i = device_modes.begin();
427  i != device_modes.end(); ++i) {
429  Gtk::Menu_Helpers::MenuElem(
430  *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
431  *i)));
432  }
433 
434  if (!device_modes.empty()) {
435  custom_device_mode_changed(device_modes.front());
436  }
437 
438  if (device_modes.size() > 1) {
440  } else {
442  }
443 
444  if (device_modes.size() > 0) {
445  _route->instrument_info().set_external_instrument (model, device_modes.front());
446  } else {
448  }
449 
450  // Rebuild controller menu
451  _controller_menu_map.clear ();
452  delete controller_menu;
453  controller_menu = 0;
455 }
456 
457 void
459 {
460  const std::string model = gui_property (X_("midnam-model-name"));
461 
462  set_gui_property (X_("midnam-custom-device-mode"), mode);
465 }
466 
469 {
470  return dynamic_cast<MidiStreamView*>(_view);
471 }
472 
473 void
475 {
476  if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
477  _midi_controls_box.show ();
478  } else {
479  _midi_controls_box.hide();
480  }
481 
482  if (h >= KEYBOARD_MIN_HEIGHT) {
483  if (is_track() && _range_scroomer) {
484  _range_scroomer->show();
485  }
486  if (is_track() && _piano_roll_header) {
487  _piano_roll_header->show();
488  }
489  } else {
490  if (is_track() && _range_scroomer) {
491  _range_scroomer->hide();
492  }
493  if (is_track() && _piano_roll_header) {
494  _piano_roll_header->hide();
495  }
496  }
497 
498  /* We need to do this after changing visibility of our stuff, as it will
499  eventually trigger a call to Editor::reset_controls_layout_width(),
500  which needs to know if we have just shown or hidden a scroomer /
501  piano roll.
502  */
504 }
505 
506 void
508 {
509  using namespace Menu_Helpers;
510 
511  MenuList& items = display_menu->items();
512 
513  // Note range
514  Menu *range_menu = manage(new Menu);
515  MenuList& range_items = range_menu->items();
516  range_menu->set_name ("ArdourContextMenu");
517 
518  range_items.push_back (
519  MenuElem (_("Show Full Range"),
520  sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
521  MidiStreamView::FullRange, true)));
522 
523  range_items.push_back (
524  MenuElem (_("Fit Contents"),
525  sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
527 
528  items.push_back (MenuElem (_("Note Range"), *range_menu));
529  items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
530  items.push_back (MenuElem (_("Channel Selector"),
531  sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
532 
534  if (color_mode_menu) {
535  items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
536  }
537 
538  items.push_back (SeparatorElem ());
539 }
540 
541 void
543 {
544  if (!_channel_selector) {
546 
547  if (_color_mode == ChannelColors) {
549  } else {
551  }
552 
553  _channel_selector->show_all ();
554  } else {
556  }
557 }
558 
559 void
561 {
562  using namespace Menu_Helpers;
563 
564  /* If we have a controller menu, we need to detach it before
565  RouteTimeAxis::build_automation_action_menu destroys the
566  menu it is attached to. Otherwise GTK destroys
567  controller_menu's gobj, meaning that it can't be reattached
568  below. See bug #3134.
569  */
570 
571  if (controller_menu) {
573  }
574 
575  _channel_command_menu_map.clear ();
577 
578  MenuList& automation_items = automation_action_menu->items();
579 
580  uint16_t selected_channels = midi_track()->get_playback_channel_mask();
581 
582  if (selected_channels != 0) {
583 
584  automation_items.push_back (SeparatorElem());
585 
586  /* these 2 MIDI "command" types are semantically more like automation
587  than note data, but they are not MIDI controllers. We give them
588  special status in this menu, since they will not show up in the
589  controller list and anyone who actually knows something about MIDI
590  (!) would not expect to find them there.
591  */
592 
594  automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
595  automation_items.back().set_sensitive (
596  !for_selection || _editor.get_selection().tracks.size() == 1);
598  automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
599  automation_items.back().set_sensitive (
600  !for_selection || _editor.get_selection().tracks.size() == 1);
601 
602  /* now all MIDI controllers. Always offer the possibility that we will
603  rebuild the controllers menu since it might need to be updated after
604  a channel mode change or other change. Also detach it first in case
605  it has been used anywhere else.
606  */
607 
609 
610  automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
611  automation_items.back().set_sensitive (
612  !for_selection || _editor.get_selection().tracks.size() == 1);
613  } else {
614  automation_items.push_back (
615  MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
616  dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
617  }
618 }
619 
620 void
622 {
623  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
624 
625  for (uint8_t chn = 0; chn < 16; chn++) {
626  if (selected_channels & (0x0001 << chn)) {
627 
628  Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
629  Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
630 
631  if (menu) {
632  menu->set_active (yn);
633  }
634  }
635  }
636 }
637 
638 void
639 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
640  const string& label,
641  AutomationType auto_type,
642  uint8_t cmd)
643 {
644  using namespace Menu_Helpers;
645 
646  /* count the number of selected channels because we will build a different menu
647  structure if there is more than 1 selected.
648  */
649 
650  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
651  int chn_cnt = 0;
652 
653  for (uint8_t chn = 0; chn < 16; chn++) {
654  if (selected_channels & (0x0001 << chn)) {
655  if (++chn_cnt > 1) {
656  break;
657  }
658  }
659  }
660 
661  if (chn_cnt > 1) {
662 
663  /* multiple channels - create a submenu, with 1 item per channel */
664 
665  Menu* chn_menu = manage (new Menu);
666  MenuList& chn_items (chn_menu->items());
667  Evoral::Parameter param_without_channel (auto_type, 0, cmd);
668 
669  /* add a couple of items to hide/show all of them */
670 
671  chn_items.push_back (
672  MenuElem (_("Hide all channels"),
673  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
674  false, param_without_channel)));
675  chn_items.push_back (
676  MenuElem (_("Show all channels"),
677  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
678  true, param_without_channel)));
679 
680  for (uint8_t chn = 0; chn < 16; chn++) {
681  if (selected_channels & (0x0001 << chn)) {
682 
683  /* for each selected channel, add a menu item for this controller */
684 
685  Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
686  chn_items.push_back (
687  CheckMenuElem (string_compose (_("Channel %1"), chn+1),
688  sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
689  fully_qualified_param)));
690 
692  bool visible = false;
693 
694  if (track) {
695  if (track->marked_for_display()) {
696  visible = true;
697  }
698  }
699 
700  Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
701  _channel_command_menu_map[fully_qualified_param] = cmi;
702  cmi->set_active (visible);
703  }
704  }
705 
706  /* now create an item in the parent menu that has the per-channel list as a submenu */
707 
708  items.push_back (MenuElem (label, *chn_menu));
709 
710  } else {
711 
712  /* just one channel - create a single menu item for this command+channel combination*/
713 
714  for (uint8_t chn = 0; chn < 16; chn++) {
715  if (selected_channels & (0x0001 << chn)) {
716 
717  Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
718  items.push_back (
719  CheckMenuElem (label,
720  sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
721  fully_qualified_param)));
722 
724  bool visible = false;
725 
726  if (track) {
727  if (track->marked_for_display()) {
728  visible = true;
729  }
730  }
731 
732  Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
733  _channel_command_menu_map[fully_qualified_param] = cmi;
734  cmi->set_active (visible);
735 
736  /* one channel only */
737  break;
738  }
739  }
740  }
741 }
742 
744 void
746  int ctl,
747  const std::string& name)
748 {
749  using namespace Menu_Helpers;
750 
751  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
752  for (uint8_t chn = 0; chn < 16; chn++) {
753  if (selected_channels & (0x0001 << chn)) {
754 
755  Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
756  ctl_items.push_back (
757  CheckMenuElem (
758  string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
759  sigc::bind (
760  sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
761  fully_qualified_param)));
762  dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
763 
765  fully_qualified_param);
766 
767  bool visible = false;
768  if (track) {
769  if (track->marked_for_display()) {
770  visible = true;
771  }
772  }
773 
774  Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
775  _controller_menu_map[fully_qualified_param] = cmi;
776  cmi->set_active (visible);
777 
778  /* one channel only */
779  break;
780  }
781  }
782 }
783 
785 void
786 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
787  int ctl,
788  const std::string& name)
789 {
790  using namespace Menu_Helpers;
791 
792  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
793 
794  Menu* chn_menu = manage (new Menu);
795  MenuList& chn_items (chn_menu->items());
796 
797  /* add a couple of items to hide/show this controller on all channels */
798 
799  Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
800  chn_items.push_back (
801  MenuElem (_("Hide all channels"),
802  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
803  false, param_without_channel)));
804  chn_items.push_back (
805  MenuElem (_("Show all channels"),
806  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
807  true, param_without_channel)));
808 
809  for (uint8_t chn = 0; chn < 16; chn++) {
810  if (selected_channels & (0x0001 << chn)) {
811 
812  /* for each selected channel, add a menu item for this controller */
813 
814  Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
815  chn_items.push_back (
816  CheckMenuElem (string_compose (_("Channel %1"), chn+1),
817  sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
818  fully_qualified_param)));
819 
821  fully_qualified_param);
822  bool visible = false;
823 
824  if (track) {
825  if (track->marked_for_display()) {
826  visible = true;
827  }
828  }
829 
830  Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
831  _controller_menu_map[fully_qualified_param] = cmi;
832  cmi->set_active (visible);
833  }
834  }
835 
836  /* add the per-channel menu to the list of controllers, with the name of the controller */
837  ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
838  *chn_menu));
839  dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
840 }
841 
844 {
845  using namespace MIDI::Name;
846 
848  if (!device_names) {
850  }
851 
852  return device_names->custom_device_mode_by_name(
853  gui_property (X_("midnam-custom-device-mode")));
854 }
855 
858 {
859  using namespace MIDI::Name;
860 
861  const std::string model = gui_property (X_("midnam-model-name"));
862 
863  boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
864  .document_by_model(model);
865  if (midnam) {
866  return midnam->master_device_names(model);
867  } else {
869  }
870 }
871 
872 void
874 {
875  using namespace Menu_Helpers;
876 
877  if (controller_menu) {
878  /* it exists and has not been invalidated by a channel mode change */
879  return;
880  }
881 
882  controller_menu = new Menu; // explicitly managed by us
883  MenuList& items (controller_menu->items());
884 
885  /* create several "top level" menu items for sets of controllers (16 at a
886  time), and populate each one with a submenu for each controller+channel
887  combination covering the currently selected channels for this track
888  */
889 
890  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
891 
892  /* count the number of selected channels because we will build a different menu
893  structure if there is more than 1 selected.
894  */
895 
896  int chn_cnt = 0;
897  for (uint8_t chn = 0; chn < 16; chn++) {
898  if (selected_channels & (0x0001 << chn)) {
899  if (++chn_cnt > 1) {
900  break;
901  }
902  }
903  }
904 
905  using namespace MIDI::Name;
907 
908  if (device_names && !device_names->controls().empty()) {
909  /* Controllers names available in midnam file, generate fancy menu */
910  unsigned n_items = 0;
911  unsigned n_groups = 0;
912 
913  /* TODO: This is not correct, should look up the currently applicable ControlNameList
914  and only build a menu for that one. */
915  for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
916  l != device_names->controls().end(); ++l) {
917  boost::shared_ptr<ControlNameList> name_list = l->second;
918  Menu* ctl_menu = NULL;
919 
920  for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
921  c != name_list->controls().end();) {
922  const uint16_t ctl = c->second->number();
923  if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
924  /* Skip bank select controllers since they're handled specially */
925  if (n_items == 0) {
926  /* Create a new submenu */
927  ctl_menu = manage (new Menu);
928  }
929 
930  MenuList& ctl_items (ctl_menu->items());
931  if (chn_cnt > 1) {
932  add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
933  } else {
934  add_single_channel_controller_item(ctl_items, ctl, c->second->name());
935  }
936  }
937 
938  ++c;
939  if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
940  /* Submenu has 16 items or we're done, add it to controller menu and reset */
941  items.push_back(
942  MenuElem(string_compose(_("Controllers %1-%2"),
943  (16 * n_groups), (16 * n_groups) + n_items - 1),
944  *ctl_menu));
945  ctl_menu = NULL;
946  n_items = 0;
947  ++n_groups;
948  }
949  }
950  }
951  } else {
952  /* No controllers names, generate generic numeric menu */
953  for (int i = 0; i < 127; i += 16) {
954  Menu* ctl_menu = manage (new Menu);
955  MenuList& ctl_items (ctl_menu->items());
956 
957  for (int ctl = i; ctl < i+16; ++ctl) {
958  if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
959  /* Skip bank select controllers since they're handled specially */
960  continue;
961  }
962 
963  if (chn_cnt > 1) {
965  ctl_items, ctl, string_compose(_("Controller %1"), ctl));
966  } else {
968  ctl_items, ctl, string_compose(_("Controller %1"), ctl));
969  }
970  }
971 
972  /* Add submenu for this block of controllers to controller menu */
973  items.push_back (
974  MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
975  *ctl_menu));
976  }
977  }
978 }
979 
980 Gtk::Menu*
982 {
983  using namespace Menu_Helpers;
984 
985  Menu* mode_menu = manage (new Menu);
986  MenuList& items = mode_menu->items();
987  mode_menu->set_name ("ArdourContextMenu");
988 
989  RadioMenuItem::Group mode_group;
990  items.push_back (
991  RadioMenuElem (mode_group,_("Sustained"),
992  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
993  Sustained, true)));
994  _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
995  _note_mode_item->set_active(_note_mode == Sustained);
996 
997  items.push_back (
998  RadioMenuElem (mode_group, _("Percussive"),
999  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1000  Percussive, true)));
1001  _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1003 
1004  return mode_menu;
1005 }
1006 
1007 Gtk::Menu*
1009 {
1010  using namespace Menu_Helpers;
1011 
1012  Menu* mode_menu = manage (new Menu);
1013  MenuList& items = mode_menu->items();
1014  mode_menu->set_name ("ArdourContextMenu");
1015 
1016  RadioMenuItem::Group mode_group;
1017  items.push_back (
1018  RadioMenuElem (mode_group, _("Meter Colors"),
1019  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1020  MeterColors, false, true, true)));
1021  _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1023 
1024  items.push_back (
1025  RadioMenuElem (mode_group, _("Channel Colors"),
1026  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1027  ChannelColors, false, true, true)));
1028  _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1030 
1031  items.push_back (
1032  RadioMenuElem (mode_group, _("Track Color"),
1033  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1034  TrackColor, false, true, true)));
1035  _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1037 
1038  return mode_menu;
1039 }
1040 
1041 void
1042 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1043 {
1044  if (apply_to_selection) {
1046  boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1047  } else {
1048  if (_note_mode != mode || midi_track()->note_mode() != mode) {
1049  _note_mode = mode;
1050  midi_track()->set_note_mode(mode);
1051  set_gui_property ("note-mode", enum_2_string(_note_mode));
1053  }
1054  }
1055 }
1056 
1057 void
1058 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1059 {
1060  if (apply_to_selection) {
1062  boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1063  } else {
1064  if (_color_mode == mode && !force) {
1065  return;
1066  }
1067 
1068  if (_channel_selector) {
1069  if (mode == ChannelColors) {
1071  } else {
1073  }
1074  }
1075 
1076  _color_mode = mode;
1077  set_gui_property ("color-mode", enum_2_string(_color_mode));
1078  if (redisplay) {
1080  }
1081  }
1082 }
1083 
1084 void
1086 {
1087  if (apply_to_selection) {
1089  boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1090  } else {
1091  if (!_ignore_signals) {
1092  midi_view()->set_note_range(range);
1093  }
1094  }
1095 }
1096 
1097 void
1099 {
1100  MidiGhostRegion* mgr;
1101 
1102  for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1103  if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1104  mgr->update_range();
1105  }
1106  }
1107 }
1108 
1109 void
1110 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1111 {
1112  using namespace MIDI::Name;
1113 
1114  if (apply_to_selection) {
1116  boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1117  } else {
1118  if (midi_track()) {
1119  // Show existing automation
1120  const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1121 
1122  for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1123  create_automation_child(*i, true);
1124  }
1125 
1126  // Show automation for all controllers named in midnam file
1128  if (gui_property (X_("midnam-model-name")) != "Generic" &&
1129  device_names && !device_names->controls().empty()) {
1130  const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1131  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1132  for (uint32_t chn = 0; chn < 16; ++chn) {
1133  if ((selected_channels & (0x0001 << chn)) == 0) {
1134  // Channel not in use
1135  continue;
1136  }
1137 
1138  boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1139  device_mode, chn);
1140  if (!chan_names) {
1141  continue;
1142  }
1143 
1144  boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1145  chan_names->control_list_name());
1146  if (!control_names) {
1147  continue;
1148  }
1149 
1150  for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1151  c != control_names->controls().end();
1152  ++c) {
1153  const uint16_t ctl = c->second->number();
1154  if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1155  /* Skip bank select controllers since they're handled specially */
1156  const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1157  create_automation_child(param, true);
1158  }
1159  }
1160  }
1161  }
1162  }
1163 
1165  }
1166 }
1167 
1168 void
1170 {
1171  if (apply_to_selection) {
1173  boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1174  } else {
1175  if (midi_track()) {
1176  const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1177 
1178  for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1179  create_automation_child (*i, true);
1180  }
1181  }
1182 
1184  }
1185 }
1186 
1189 void
1191 {
1192  if (param.type() == NullAutomation) {
1193  return;
1194  }
1195 
1196  AutomationTracks::iterator existing = _automation_tracks.find (param);
1197 
1198  if (existing != _automation_tracks.end()) {
1199 
1200  /* automation track created because we had existing data for
1201  * the processor, but visibility may need to be controlled
1202  * since it will have been set visible by default.
1203  */
1204 
1205  existing->second->set_marked_for_display (show);
1206 
1207  if (!no_redraw) {
1208  request_redraw ();
1209  }
1210 
1211  return;
1212  }
1213 
1216 
1217 
1218  switch (param.type()) {
1219 
1220  case GainAutomation:
1221  create_gain_automation_child (param, show);
1222  break;
1223 
1224  case MuteAutomation:
1225  create_mute_automation_child (param, show);
1226  break;
1227 
1228  case PluginAutomation:
1229  /* handled elsewhere */
1230  break;
1231 
1232  case MidiCCAutomation:
1237  /* These controllers are region "automation" - they are owned
1238  * by regions (and their MidiModels), not by the track. As a
1239  * result there is no AutomationList/Line for the track, but we create
1240  * a controller for the user to write immediate events, so the editor
1241  * can act as a control surface for the present MIDI controllers.
1242  *
1243  * TODO: Record manipulation of the controller to regions?
1244  */
1245 
1246  control = _route->automation_control(param, true);
1247  track.reset (new AutomationTimeAxisView (
1248  _session,
1249  _route,
1250  control ? _route : boost::shared_ptr<Automatable> (),
1251  control,
1252  param,
1253  _editor,
1254  *this,
1255  true,
1256  parent_canvas,
1257  _route->describe_parameter(param)));
1258 
1259  if (_view) {
1261  sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1262  }
1263 
1264  add_automation_child (param, track, show);
1265  break;
1266 
1267  case PanWidthAutomation:
1269  case PanAzimuthAutomation:
1270  ensure_pan_views (show);
1271  break;
1272 
1273  default:
1274  error << "MidiTimeAxisView: unknown automation child "
1275  << EventTypeMap::instance().to_symbol(param) << endmsg;
1276  }
1277 }
1278 
1279 void
1281 {
1283 
1284  if (is_track()) {
1285  if (_route->active()) {
1286  controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1287  time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1288  controls_base_selected_name = "MidiTrackControlsBaseSelected";
1289  controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1290  } else {
1291  controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1292  time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1293  controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1294  controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1295  }
1296  } else {
1297  if (_route->active()) {
1298  controls_ebox.set_name ("BusControlsBaseUnselected");
1299  time_axis_frame.set_name ("BusControlsBaseUnselected");
1300  controls_base_selected_name = "BusControlsBaseSelected";
1301  controls_base_unselected_name = "BusControlsBaseUnselected";
1302  } else {
1303  controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1304  time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1305  controls_base_selected_name = "BusControlsBaseInactiveSelected";
1306  controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1307  }
1308  }
1309 }
1310 
1311 void
1313 {
1314  uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1315 
1316  _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1317 
1318  if (_view->num_selected_regionviews() == 0) {
1320  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1321  note, chn_mask));
1322  } else {
1324  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1325  note, chn_mask));
1326  }
1327 
1329 }
1330 
1331 void
1333 {
1334  const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1335 
1336  _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1337 
1338  if (_view->num_selected_regionviews() == 0) {
1340  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1341  note, chn_mask));
1342  } else {
1344  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1345  note, chn_mask));
1346  }
1347 
1349 }
1350 
1351 void
1353 {
1354  const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1355 
1356  _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1357 
1358  if (_view->num_selected_regionviews() == 0) {
1360  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1361  note, chn_mask));
1362  } else {
1364  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1365  note, chn_mask));
1366  }
1367 
1369 }
1370 
1371 void
1373 {
1374  const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1375 
1376  _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1377 
1378  if (_view->num_selected_regionviews() == 0) {
1380  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1381  note, chn_mask));
1382  } else {
1384  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1385  note, chn_mask));
1386  }
1387 
1389 }
1390 
1391 void
1393 {
1395  sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1396 }
1397 
1398 void
1399 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1400 {
1401  dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1402 }
1403 
1404 void
1405 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1406 {
1407  dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1408 }
1409 
1410 void
1412 {
1413  dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1414 }
1415 
1416 void
1418 {
1419  dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1420 }
1421 
1422 void
1424 {
1426  dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1427 
1428  std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1429 
1431  for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1432  notes.insert (*sel_it);
1433  }
1434 
1435  if (!notes.empty()) {
1436  selection.push_back (make_pair ((rv)->region()->id(), notes));
1437  }
1438 }
1439 
1440 void
1442 {
1443  /* hide all automation tracks that use the wrong channel(s) and show all those that use
1444  the right ones.
1445  */
1446 
1447  const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1448  bool changed = false;
1449 
1450  no_redraw = true;
1451 
1452  for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1453 
1454  for (uint32_t chn = 0; chn < 16; ++chn) {
1455  Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1457 
1458  if (!track) {
1459  continue;
1460  }
1461 
1462  if ((selected_channels & (0x0001 << chn)) == 0) {
1463  /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1464  which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1465  */
1466  changed = track->set_marked_for_display (false) || changed;
1467  } else {
1468  changed = track->set_marked_for_display (true) || changed;
1469  }
1470  }
1471  }
1472 
1473  no_redraw = false;
1474 
1475  /* TODO: Bender, Pressure */
1476 
1477  /* invalidate the controller menu, so that we rebuild it next time */
1478  _controller_menu_map.clear ();
1479  delete controller_menu;
1480  controller_menu = 0;
1481 
1482  if (changed) {
1483  request_redraw ();
1484  }
1485 }
1486 
1487 Gtk::CheckMenuItem*
1489 {
1490  Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1491  if (m) {
1492  return m;
1493  }
1494 
1495  ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1496  if (i != _controller_menu_map.end()) {
1497  return i->second;
1498  }
1499 
1500  i = _channel_command_menu_map.find (param);
1501  if (i != _channel_command_menu_map.end()) {
1502  return i->second;
1503  }
1504 
1505  return 0;
1506 }
1507 
1510 {
1511  Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1512 
1514  playlist()->clear_changes ();
1515 
1516  real_editor->snap_to (pos, RoundNearest);
1517 
1519  PropertyList plist;
1520 
1521  plist.add (ARDOUR::Properties::start, 0);
1522  plist.add (ARDOUR::Properties::length, length);
1524 
1525  boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1526 
1527  playlist()->add_region (region, pos);
1529 
1530  if (commit) {
1531  real_editor->commit_reversible_command ();
1532  }
1533 
1534  return boost::dynamic_pointer_cast<MidiRegion>(region);
1535 }
1536 
1537 void
1539 {
1540  if (!_step_editor) {
1541  _step_editor = new StepEditor (_editor, midi_track(), *this);
1542  }
1543 }
1544 
1545 void
1547 {
1548  ensure_step_editor ();
1550 
1551 }
1552 void
1554 {
1555  if (_step_editor) {
1557  }
1558 }
1559 
1563 uint8_t
1565 {
1566  uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1567  int chn_cnt = 0;
1568  uint8_t channel = 0;
1569 
1570  /* pick the highest selected channel, unless all channels are selected,
1571  which is interpreted to mean channel 1 (zero)
1572  */
1573 
1574  for (uint16_t i = 0; i < 16; ++i) {
1575  if (chn_mask & (1<<i)) {
1576  channel = i;
1577  chn_cnt++;
1578  }
1579  }
1580 
1581  if (chn_cnt == 16) {
1582  channel = 0;
1583  }
1584 
1585  return channel;
1586 }
1587 
1588 void
1590 {
1591  set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1592  set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1593 }
1594 
1595 void
1597 {
1598  _range_scroomer->queue_resize ();
1599 }
1600 
1601 void
1603 {
1604  switch (midi_track()->get_playback_channel_mode()) {
1605  case AllChannels:
1606  _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1607  break;
1608  case FilterChannels:
1609  _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1610  break;
1611  case ForceChannel:
1612  _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1613  break;
1614  }
1615 }
1616 
1617 void
1619 {
1620  switch (midi_track()->get_capture_channel_mode()) {
1621  case AllChannels:
1622  _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1623  break;
1624  case FilterChannels:
1625  _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1626  break;
1627  case ForceChannel:
1628  _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1629  break;
1630  }
1631 }
1632 
1633 bool
1635 {
1636  if (!_editor.internal_editing()) {
1637  // Non-internal paste, paste regions like any other route
1638  return RouteTimeAxisView::paste(pos, selection, ctx);
1639  }
1640 
1641  return midi_view()->paste(pos, selection, ctx);
1642 }
Gtk::Menu * display_menu
StepEditor * _step_editor
Gdk::Color color() const
Definition: route_ui.cc:2138
boost::shared_ptr< ARDOUR::Playlist > playlist() const
#define MIDI_CTL_MSB_BANK
Definition: midi_events.h:33
void set_route(boost::shared_ptr< ARDOUR::Route >)
int atoi(const string &s)
Definition: convert.cc:140
Force all events to a certain channel.
Definition: types.h:212
void custom_device_mode_changed(const std::string &mode)
std::multiset< NotePtr, EarlierNoteComparator > Notes
Definition: Sequence.hpp:153
boost::shared_ptr< ARDOUR::MidiTrack > midi_track() const
Definition: route_ui.cc:1762
static const uint32_t midi_channel_colors[16]
hue circle divided into 16 equal-looking parts, courtesy Thorsten Wilms
Definition: note_base.h:132
void stop_step_editing()
Definition: step_editor.cc:163
void set_channel_colors(const uint32_t new_channel_colors[16])
void extend_note_selection_region_view(RegionView *, uint8_t note, uint16_t chn_mask)
std::string get_string(const std::string &id, const std::string &prop_name, bool *empty=0)
Definition: gui_object.cc:92
virtual Gtk::CheckMenuItem * automation_child_menu_item(Evoral::Parameter)
sigc::signal< void > signal_clicked
PBD::Signal0< void > ChannelModeChanged
bool is_midi_track() const
Definition: route_ui.cc:1756
NoteMode
Definition: types.h:204
int ffs(int x)
Definition: ffs.cc:28
bool paste(ARDOUR::framepos_t, const Selection &, PasteContext &ctx)
void begin_reversible_command(std::string cmd_name)
std::string gui_property(const std::string &property_name) const
Definition: axis_view.cc:67
#define MIDI_CTL_LSB_BANK
Definition: midi_events.h:49
std::string name() const
uint32_t num_selected_regionviews() const
Definition: streamview.cc:493
Gtk::Menu subplugin_menu
MidiTimeAxisView(PublicEditor &, ARDOUR::Session *, ArdourCanvas::Canvas &canvas)
void capture_channel_mode_changed()
#define enum_2_string(e)
Definition: enumwriter.h:97
sigc::signal< void, RegionView * > RegionViewAdded
Definition: streamview.h:122
void add_note_selection(uint8_t note)
StreamView * _view
virtual void redisplay_track()=0
static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT
virtual bool have_idled() const =0
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
Gtk::Menu * controller_menu
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
Gtk::RadioMenuItem * _meter_color_mode_item
Gtk::Menu * build_color_mode_menu()
Lists of selected things.
Definition: selection.h:66
void set_external_instrument(const std::string &model, const std::string &mode)
void change_all_channel_tracks_visibility(bool yn, Evoral::Parameter param)
ColorMode
Definition: types.h:215
void add_command(Command *const cmd)
Definition: session.h:787
Gtk::VBox _midi_controls_box
void set_route(boost::shared_ptr< ARDOUR::Route >)
void append_extra_display_menu_items()
Representation of the interface of the Editor class.
std::list< std::string > custom_device_mode_names_by_model(std::string model_name)
Gtk::Label _playback_channel_status
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
ArdourCanvas::Canvas & parent_canvas
void set_note_selection(uint8_t note)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
uint16_t get_playback_channel_mask() const
Definition: midi_track.h:119
ChannelMode
Definition: types.h:209
Gtk::Menu * color_mode_menu
StreamView * view() const
void extend_note_selection(uint8_t note)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
LIBARDOUR_API GQuark create_region
Definition: operations.cc:34
void contents_height_changed()
Gtk::Frame time_axis_frame
Round to nearest.
Definition: types.h:224
MidiChannelFilter & playback_filter()
Definition: midi_track.h:122
void set_note_range(MidiStreamView::VisibleNoteRange range, bool apply_to_selection=false)
virtual bool set_marked_for_display(bool)
Definition: axis_view.cc:87
#define invalidator(x)
Definition: gui_thread.h:40
bool ignore_toggle
Definition: route_ui.h:94
sigc::signal< void > NoteRangeChanged
Definition: id.h:32
Gtk::Menu * build_note_mode_menu()
void add_multi_channel_controller_item(Gtk::Menu_Helpers::MenuList &ctl_items, int ctl, const std::string &name)
virtual void route_active_changed()
Definition: route_ui.h:195
Gtk::Label _capture_channel_status
sigc::signal< void, uint8_t > AddNoteSelection
sigc::signal0< void > DragFinishing
Definition: scroomer.h:63
virtual void show_existing_automation(bool apply_to_selection=false)
PBD::Signal0< void > ChannelMaskChanged
#define _(Text)
Definition: i18n.h:11
uint8_t get_channel_for_add() const
ARDOUR::NoteMode note_mode() const
void set_height(uint32_t h, TrackHeightMode m=OnlySelf)
void foreach_selected_regionview(sigc::slot< void, RegionView * > slot)
Definition: streamview.cc:514
boost::shared_ptr< ARDOUR::MidiRegion > add_region(ARDOUR::framepos_t, ARDOUR::framecnt_t, bool)
std::string controls_base_selected_name
void get_per_region_note_selection_region_view(RegionView *, std::list< std::pair< PBD::ID, std::set< boost::shared_ptr< Evoral::Note< Evoral::Beats > > > > > &)
void create_gain_automation_child(const Evoral::Parameter &, bool)
boost::shared_ptr< ARDOUR::Route > _route
Definition: route_ui.h:87
static bool parse_state_id(std::string const &, PBD::ID &, bool &, Evoral::Parameter &)
void add_region(boost::shared_ptr< Region >, framepos_t position, float times=1, bool auto_partition=false)
Definition: playlist.cc:668
void set_note_mode(NoteMode m)
Definition: midi_track.cc:637
void foreach_regionview(sigc::slot< void, RegionView * > slot)
Definition: streamview.cc:506
uint32_t gdk_color_to_rgba(Gdk::Color const &)
Definition: utils.cc:285
#define X_(Text)
Definition: i18n.h:13
boost::shared_ptr< MIDI::Name::CustomDeviceMode > get_device_mode()
int64_t framecnt_t
Definition: types.h:76
ParameterMenuMap _channel_command_menu_map
#define string_2_enum(str, e)
Definition: enumwriter.h:98
ArdourDropdown _midnam_model_selector
void add_ghost(RegionView *)
ArdourDropdown _midnam_custom_device_mode_selector
void attach()
Definition: streamview.cc:100
Gtk::Fixed scroomer_placeholder
sigc::signal0< void > DoubleClicked
Definition: scroomer.h:65
MidiChannelFilter & capture_filter()
Definition: midi_track.h:123
virtual std::string describe_parameter(Evoral::Parameter param)
Definition: automatable.cc:160
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
virtual void show_all_automation(bool apply_to_selection=false)
void show_all_automation(bool apply_to_selection=false)
const const_iterator & end() const
Definition: Sequence.hpp:280
Definition: amp.h:29
void request_redraw()
Definition: route_ui.cc:2100
const PBD::ID & id() const
Definition: stateful.h:68
sigc::signal0< void > DragStarting
Definition: scroomer.h:62
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
#define gui_context()
Definition: gui_thread.h:36
void region_view_added(RegionView *)
void add_single_channel_controller_item(Gtk::Menu_Helpers::MenuList &ctl_items, int ctl, const std::string &name)
sigc::signal< void > ContentsHeightChanged
Definition: streamview.h:125
void add_channel_command_menu_item(Gtk::Menu_Helpers::MenuList &items, const std::string &label, ARDOUR::AutomationType auto_type, uint8_t cmd)
bool paste(ARDOUR::framepos_t pos, const Selection &selection, PasteContext &ctx)
AutomationType
Definition: types.h:121
void playback_channel_mode_changed()
void get_per_region_note_selection(std::list< std::pair< PBD::ID, std::set< boost::shared_ptr< Evoral::Note< Evoral::Beats > > > > > &)
void create_automation_child(const Evoral::Parameter &param, bool show)
int64_t framepos_t
Definition: types.h:66
virtual Selection & get_selection() const =0
void add_automation_child(Evoral::Parameter param, boost::shared_ptr< AutomationTimeAxisView > track, bool show=true)
PianoRollHeader * _piano_roll_header
void model_changed(const std::string &model)
void ensure_pan_views(bool show=true)
NoteMode note_mode() const
Definition: midi_track.h:98
boost::shared_ptr< PannerShell > panner_shell() const
Definition: route.cc:4036
static GUIObjectState & gui_object_state()
Definition: axis_view.cc:98
AutomationTracks _automation_tracks
T * get() const
Definition: shared_ptr.hpp:268
Gtk::Menu * automation_action_menu
bool is_track() const
Definition: route_ui.cc:1732
void set_note_mode(ARDOUR::NoteMode mode, bool apply_to_selection=false)
Gtk::Menu * mode_menu
std::list< GhostRegion * > ghosts
void set_tip(Gtk::Widget &w, const gchar *tip)
void apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views)
bool active() const
Definition: route.h:95
void build_controller_menu()
ARDOUR::ColorMode _color_mode
void processors_changed(ARDOUR::RouteProcessorChange)
virtual void build_automation_action_menu(bool)
LIBPBD_API Glib::ustring basename_nosuffix(Glib::ustring)
PBD::Signal1< void, RouteProcessorChange > processors_changed
Definition: route.h:312
void create_mute_automation_child(const Evoral::Parameter &, bool)
Gtk::HBox top_hbox
void set_height(uint32_t, TrackHeightMode m=OnlySelf)
virtual bool internal_editing() const =0
Gtk::RadioMenuItem * _note_mode_item
uint32_t id() const
Definition: Parameter.hpp:49
Definition: editor.h:134
Gtk::RadioMenuItem * _channel_color_mode_item
void toggle_note_selection(uint8_t note)
void toggle_channel_selector()
sigc::signal< void, uint8_t > ToggleNoteSelection
std::string name() const
static const uint32_t KEYBOARD_MIN_HEIGHT
TrackSelection tracks
Definition: selection.h:81
void set_text(const std::string &)
const_iterator begin(Time t=Time(), bool force_discrete=false, const std::set< Evoral::Parameter > &f=std::set< Evoral::Parameter >(), const std::set< WeakNotePtr > *active_notes=NULL) const
Definition: Sequence.hpp:272
boost::shared_ptr< AutomationTimeAxisView > automation_child(Evoral::Parameter param)
void set_color_mode(ARDOUR::ColorMode, bool force=false, bool redisplay=true, bool apply_to_selection=false)
void set_note_range(VisibleNoteRange r)
Gtk::CheckMenuItem * automation_child_menu_item(Evoral::Parameter)
boost::shared_ptr< MidiSource > create_midi_source_by_stealing_name(boost::shared_ptr< Track >)
Definition: session.cc:4051
uint32_t type() const
Definition: Parameter.hpp:47
Definition: debug.h:30
Pass through all channel information unmodified.
Definition: types.h:210
Gtk::HBox time_axis_hbox
boost::shared_ptr< AutomationControl > automation_control(const Evoral::Parameter &id, bool create_if_missing=false)
Definition: automatable.cc:475
virtual ~MidiTimeAxisView()
void start_step_editing()
Definition: step_editor.cc:59
void toggle_note_selection_region_view(RegionView *, uint8_t note, uint16_t chn_mask)
sigc::signal< void, uint8_t > SetNoteSelection
std::string controls_base_unselected_name
void set_gui_property(const std::string &property_name, const T &value)
Definition: axis_view.h:66
std::list< std::string > all_ids() const
Definition: gui_object.cc:142
InstrumentInfo & instrument_info()
Definition: route.h:440
Gtk::RadioMenuItem * _percussion_mode_item
void commit_reversible_command()
Definition: editor.cc:3483
PublicEditor & _editor
bool paste(ARDOUR::framepos_t, const Selection &, PasteContext &ctx)
virtual void begin_reversible_selection_op(std::string cmd_name)=0
MidiChannelSelectorWindow * _channel_selector
boost::shared_ptr< MIDI::Name::MasterDeviceNames > get_device_names()
void show_existing_automation(bool apply_to_selection=false)
void apply_color(uint32_t, ColorTarget t)
Definition: streamview.cc:354
bool marked_for_display() const
Definition: axis_view.cc:80
LIBGTKMM2EXT_API void detach_menu(Gtk::Menu &)
Definition: utils.cc:361
void add_note_selection_region_view(RegionView *rv, uint8_t note, uint16_t chn_mask)
void check_step_edit()
Definition: step_editor.cc:177
void set_note_selection_region_view(RegionView *rv, uint8_t note, uint16_t chn_mask)
void clear_changes()
Definition: stateful.cc:184
Gtk::EventBox controls_ebox
static MidiPatchManager & instance()
ARDOUR::NoteMode _note_mode
bool add(PropertyBase *prop)
ARDOUR::Session * _session
MidiStreamView * midi_view()
static Glib::RefPtr< Gtk::SizeGroup > midi_scroomer_size_group
ParameterMenuMap _controller_menu_map
void AddMenuElem(Gtk::Menu_Helpers::MenuElem e)
Gtk::VBox controls_vbox
boost::shared_ptr< MidiPlaylist > midi_playlist()
Definition: midi_track.cc:808
sigc::signal< void, uint8_t > ExtendNoteSelection
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void set_channel_mode(ARDOUR::ChannelMode, uint16_t)
ARDOUR::ColorMode color_mode() const
Ignore events on certain channels.
Definition: types.h:211
virtual void commit_reversible_selection_op()=0
void build_automation_action_menu(bool)
void foreach_midi_time_axis(Function f)
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
Gtk::HBox _channel_status_box
void snap_to(framepos_t &first, ARDOUR::RoundMode direction=ARDOUR::RoundNearest, bool for_mark=false)
Definition: editor.cc:2611
MidiScroomer * _range_scroomer
void toggle_automation_track(const Evoral::Parameter &param)