#include "gtkmm2ext/bindable_button.h"
#include "gtkmm2ext/utils.h"
-#include "ardour/file_source.h"
-#include "ardour/ladspa_plugin.h"
-#include "ardour/location.h"
-#include "ardour/midi_diskstream.h"
+#include "ardour/event_type_map.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_region.h"
#include "ardour/midi_source.h"
+#include "ardour/midi_track.h"
#include "ardour/operations.h"
#include "ardour/playlist.h"
-#include "ardour/processor.h"
+#include "ardour/region.h"
#include "ardour/region_factory.h"
+#include "ardour/route.h"
#include "ardour/session.h"
-#include "ardour/session_playlist.h"
-#include "ardour/tempo.h"
-#include "ardour/utils.h"
+#include "ardour/session_object.h"
+#include "ardour/source.h"
+#include "ardour/track.h"
+#include "ardour/types.h"
#include "midi++/names.h"
-#include "add_midi_cc_track_dialog.h"
#include "ardour_ui.h"
#include "ardour_button.h"
#include "automation_line.h"
#include "automation_time_axis.h"
#include "canvas-note-event.h"
#include "canvas_impl.h"
-#include "crossfade_view.h"
#include "editor.h"
#include "enums.h"
#include "ghostregion.h"
void
MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
{
+ _route = rt;
+
+ _view = new MidiStreamView (*this);
+
+ if (is_track ()) {
+ _piano_roll_header = new PianoRollHeader(*midi_view());
+ _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
+ }
+
+ /* This next call will result in our height being set up, so it must come after
+ the creation of the piano roll / range scroomer as their visibility is set up
+ when our height is.
+ */
RouteTimeAxisView::set_route (rt);
+ _view->apply_color (_color, StreamView::RegionColor);
+
subplugin_menu.set_name ("ArdourContextMenu");
- _view = new MidiStreamView (*this);
if (!gui_property ("note-range-min").empty ()) {
midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()), atoi (gui_property ("note-range-max").c_str()), true);
}
midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
+ _view->ContentsHeightChanged.connect (sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
ignore_toggle = false;
processors_changed (RouteProcessorChange ());
- _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
+ _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
if (is_track()) {
- _piano_roll_header = new PianoRollHeader(*midi_view());
-
+ _piano_roll_header->SetNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
_piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
_piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
_piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
- _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
-
/* Suspend updates of the StreamView during scroomer drags to speed things up */
_range_scroomer->DragStarting.connect (sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
_range_scroomer->DragFinishing.connect (sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
- controls_hbox.pack_start(*_range_scroomer);
- controls_hbox.pack_start(*_piano_roll_header);
+ /* Put the scroomer and the keyboard in a VBox with a padding
+ label so that they can be reduced in height for stacked-view
+ tracks.
+ */
+ VBox* v = manage (new VBox);
+ HBox* h = manage (new HBox);
+ h->pack_start (*_range_scroomer);
+ h->pack_start (*_piano_roll_header);
+ v->pack_start (*h, false, false);
+ v->pack_start (*manage (new Label ("")), true, true);
+ controls_hbox.pack_start(*v);
controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
controls_base_selected_name = "MidiTrackControlsBaseSelected";
_model_selector.append_text(m->c_str());
}
+
_model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
_custom_device_mode_selector.signal_changed().connect(
sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
- // TODO: persist the choice
- // this initializes the comboboxes and sends out the signal
- _model_selector.set_active(0);
+ _model_selector.set_active_text (gui_property (X_("midnam-model-name")));
+ _custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
+
+ ARDOUR_UI::instance()->set_tip (_model_selector, _("External MIDI Device"));
+ ARDOUR_UI::instance()->set_tip (_custom_device_mode_selector, _("External Device Mode"));
midi_controls_hbox->pack_start(_channel_selector, true, false);
if (!patch_manager.all_models().empty()) {
+ _midi_controls_box.set_border_width (5);
_midi_controls_box.pack_start(_model_selector, true, false);
_midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
}
/* Look for any GUI object state nodes that represent automation children that should exist, and create
* the children.
*/
-
- GUIObjectState& gui_state = gui_object_state ();
- for (GUIObjectState::StringPropertyMap::const_iterator i = gui_state.begin(); i != gui_state.end(); ++i) {
+
+ list<string> gui_ids = gui_object_state().all_ids ();
+ for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
PBD::ID route_id;
bool has_parameter;
Evoral::Parameter parameter (0, 0, 0);
- bool const p = AutomationTimeAxisView::parse_state_id (i->first, route_id, has_parameter, parameter);
+ bool const p = AutomationTimeAxisView::parse_state_id (*i, route_id, has_parameter, parameter);
if (p && route_id == _route->id () && has_parameter) {
- create_automation_child (parameter, string_is_affirmative (gui_object_state().get_string (i->first, X_("visible"))));
+ create_automation_child (parameter, string_is_affirmative (gui_object_state().get_string (*i, X_("visible"))));
}
}
}
for (std::list<std::string>::const_iterator i = device_modes.begin();
i != device_modes.end(); ++i) {
- cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
_custom_device_mode_selector.append_text(*i);
}
_custom_device_mode_selector.set_active(0);
+
+ _route->instrument_info().set_external_instrument (_model_selector.get_active_text(), _custom_device_mode_selector.get_active_text());
}
-void MidiTimeAxisView::custom_device_mode_changed()
+void
+MidiTimeAxisView::custom_device_mode_changed()
{
- _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
- _custom_device_mode_selector.get_active_text());
+ _route->instrument_info().set_external_instrument (_model_selector.get_active_text(), _custom_device_mode_selector.get_active_text());
}
MidiStreamView*
range_menu->set_name ("ArdourContextMenu");
range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
- sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
- MidiStreamView::FullRange)));
+ sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
+ MidiStreamView::FullRange, true)));
range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
- MidiStreamView::ContentsRange)));
+ MidiStreamView::ContentsRange, true)));
items.push_back (MenuElem (_("Note Range"), *range_menu));
items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
mode_menu->set_name ("ArdourContextMenu");
RadioMenuItem::Group mode_group;
- items.push_back (RadioMenuElem (mode_group, _("Sustained"),
- sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
+ items.push_back (RadioMenuElem (mode_group,_("Sustained"),
+ sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained, true)));
_note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
_note_mode_item->set_active(_note_mode == Sustained);
items.push_back (RadioMenuElem (mode_group, _("Percussive"),
- sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
+ sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive, true)));
_percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
_percussion_mode_item->set_active(_note_mode == Percussive);
RadioMenuItem::Group mode_group;
items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
- MeterColors, false, true)));
+ MeterColors, false, true, true)));
_meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
_meter_color_mode_item->set_active(_color_mode == MeterColors);
items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
- ChannelColors, false, true)));
+ ChannelColors, false, true, true)));
_channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
_channel_color_mode_item->set_active(_color_mode == ChannelColors);
items.push_back (RadioMenuElem (mode_group, _("Track Color"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
- TrackColor, false, true)));
+ TrackColor, false, true, true)));
_channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
_channel_color_mode_item->set_active(_color_mode == TrackColor);
}
void
-MidiTimeAxisView::set_note_mode(NoteMode mode)
+MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
{
- if (_note_mode != mode || midi_track()->note_mode() != mode) {
- _note_mode = mode;
- midi_track()->set_note_mode(mode);
- set_gui_property ("note-mode", enum_2_string(_note_mode));
- _view->redisplay_track();
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_midi_time_axis (boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
+ } else {
+ if (_note_mode != mode || midi_track()->note_mode() != mode) {
+ _note_mode = mode;
+ midi_track()->set_note_mode(mode);
+ set_gui_property ("note-mode", enum_2_string(_note_mode));
+ _view->redisplay_track();
+ }
}
}
void
-MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay)
+MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
{
- if (_color_mode == mode && !force) {
- return;
- }
-
- if (mode == ChannelColors) {
- _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_midi_time_axis (
+ boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false)
+ );
} else {
- _channel_selector.set_default_channel_color();
- }
-
- _color_mode = mode;
- set_gui_property ("color-mode", enum_2_string(_color_mode));
- if (redisplay) {
- _view->redisplay_track();
+
+ if (_color_mode == mode && !force) {
+ return;
+ }
+
+ if (mode == ChannelColors) {
+ _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ } else {
+ _channel_selector.set_default_channel_color();
+ }
+
+ _color_mode = mode;
+ set_gui_property ("color-mode", enum_2_string(_color_mode));
+ if (redisplay) {
+ _view->redisplay_track();
+ }
}
}
void
-MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
+MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
{
- if (!_ignore_signals)
- midi_view()->set_note_range(range);
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_midi_time_axis (
+ boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false)
+ );
+ } else {
+ if (!_ignore_signals) {
+ midi_view()->set_note_range(range);
+ }
+ }
}
-
void
MidiTimeAxisView::update_range()
{
MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
{
if (param.type() == NullAutomation) {
- cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
return;
}
* since it will have been set visible by default.
*/
- cerr << "show existing auto track: " << show << " noredraw " << no_redraw << endl;
-
if (existing->second->set_marked_for_display (show) && !no_redraw) {
request_redraw ();
}
}
}
+void
+MidiTimeAxisView::set_note_selection (uint8_t note)
+{
+ if (!_editor.internal_editing()) {
+ return;
+ }
+
+ uint16_t chn_mask = _channel_selector.get_selected_channels();
+ if (_view->num_selected_regionviews() == 0) {
+ _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view), note, chn_mask));
+ } else {
+ _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view), note, chn_mask));
+ }
+}
void
MidiTimeAxisView::add_note_selection (uint8_t note)
}
void
-MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
+MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
{
dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
}
+void
+MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
+{
+ dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
+}
+
void
MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
{
set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
}
+
+void
+MidiTimeAxisView::contents_height_changed ()
+{
+ _range_scroomer->set_size_request (-1, _view->child_height ());
+}