X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_time_axis.cc;h=f449dcaef05b6db1d745990e64d196bf531689bf;hb=4901f9d1d20ea5878b34db025a3dc305d3a78c2e;hp=9cda4185579e9899e45c2a629fba3857dad08f60;hpb=ed626628b54e67dd9621c08d82a42afaed00c7ac;p=ardour.git diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 9cda418557..f449dcaef0 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -39,30 +39,30 @@ #include "gtkmm2ext/utils.h" #include "ardour/file_source.h" -#include "ardour/midi_playlist.h" +#include "ardour/ladspa_plugin.h" +#include "ardour/location.h" #include "ardour/midi_diskstream.h" #include "ardour/midi_patch_manager.h" +#include "ardour/midi_playlist.h" +#include "ardour/midi_region.h" #include "ardour/midi_source.h" -#include "ardour/processor.h" -#include "ardour/ladspa_plugin.h" -#include "ardour/location.h" +#include "ardour/operations.h" #include "ardour/playlist.h" +#include "ardour/processor.h" #include "ardour/region_factory.h" #include "ardour/session.h" #include "ardour/session_playlist.h" #include "ardour/tempo.h" #include "ardour/utils.h" -#include "ardour/operations.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" @@ -99,10 +99,9 @@ using namespace Editing; static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162; static const uint32_t KEYBOARD_MIN_HEIGHT = 140; -MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, - boost::shared_ptr rt, Canvas& canvas) +MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas) : AxisView(sess) // virtually inherited - , RouteTimeAxisView(ed, sess, rt, canvas) + , RouteTimeAxisView(ed, sess, canvas) , _ignore_signals(false) , _range_scroomer(0) , _piano_roll_header(0) @@ -118,14 +117,36 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, , controller_menu (0) , _step_editor (0) { - subplugin_menu.set_name ("ArdourContextMenu"); +} +void +MidiTimeAxisView::set_route (boost::shared_ptr 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); + } - ignore_toggle = false; + /* 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); - mute_button->set_active (false); - solo_button->set_active (false); + subplugin_menu.set_name ("ArdourContextMenu"); + + 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)); + + ignore_toggle = false; if (is_midi_track()) { controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected"); @@ -138,21 +159,14 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, processors_changed (RouteProcessorChange ()); - ensure_xml_node (); - - set_state (*xml_node, Stateful::loading_state_version); - _route->processors_changed.connect (*this, invalidator (*this), ui_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)); @@ -211,22 +225,39 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, _channel_selector.mode_changed.connect( sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode)); - XMLProperty *prop; - if ((prop = xml_node->property ("color-mode")) != 0) { - _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode)); + string prop = gui_property ("color-mode"); + if (!prop.empty()) { + _color_mode = ColorMode (string_2_enum(prop, _color_mode)); if (_color_mode == ChannelColors) { _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors); } } - if ((prop = xml_node->property ("note-mode")) != 0) { - _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode)); + set_color_mode (_color_mode, true, false); + + prop = gui_property ("note-mode"); + if (!prop.empty()) { + _note_mode = NoteMode (string_2_enum (prop, _note_mode)); if (_percussion_mode_item) { _percussion_mode_item->set_active (_note_mode == Percussive); } } - set_color_mode (_color_mode, true, false); + /* Look for any GUI object state nodes that represent automation children that should exist, and create + * the children. + */ + + list gui_ids = gui_object_state().all_ids (); + for (list::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, 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, X_("visible")))); + } + } } void @@ -301,47 +332,37 @@ MidiTimeAxisView::midi_view() return dynamic_cast(_view); } -guint32 -MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent) -{ - ensure_xml_node (); - xml_node->add_property ("shown-editor", "yes"); - - guint32 ret = TimeAxisView::show_at (y, nth, parent); - return ret; -} - -void -MidiTimeAxisView::hide () -{ - ensure_xml_node (); - xml_node->add_property ("shown-editor", "no"); - - TimeAxisView::hide (); -} - void MidiTimeAxisView::set_height (uint32_t h) { - RouteTimeAxisView::set_height (h); - - if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) { + if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) { _midi_controls_box.show_all (); } else { _midi_controls_box.hide(); } - - if (height >= KEYBOARD_MIN_HEIGHT) { - if (is_track() && _range_scroomer) + + if (h >= KEYBOARD_MIN_HEIGHT) { + if (is_track() && _range_scroomer) { _range_scroomer->show(); - if (is_track() && _piano_roll_header) + } + if (is_track() && _piano_roll_header) { _piano_roll_header->show(); + } } else { - if (is_track() && _range_scroomer) + if (is_track() && _range_scroomer) { _range_scroomer->hide(); - if (is_track() && _piano_roll_header) + } + if (is_track() && _piano_roll_header) { _piano_roll_header->hide(); + } } + + /* We need to do this after changing visibility of our stuff, as it will + eventually trigger a call to Editor::reset_controls_layout_width(), + which needs to know if we have just shown or hidden a scroomer / + piano roll. + */ + RouteTimeAxisView::set_height (h); } void @@ -754,7 +775,7 @@ MidiTimeAxisView::set_note_mode(NoteMode mode) if (_note_mode != mode || midi_track()->note_mode() != mode) { _note_mode = mode; midi_track()->set_note_mode(mode); - xml_node->add_property ("note-mode", enum_2_string(_note_mode)); + set_gui_property ("note-mode", enum_2_string(_note_mode)); _view->redisplay_track(); } } @@ -773,7 +794,7 @@ MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay) } _color_mode = mode; - xml_node->add_property ("color-mode", enum_2_string(_color_mode)); + set_gui_property ("color-mode", enum_2_string(_color_mode)); if (redisplay) { _view->redisplay_track(); } @@ -827,7 +848,7 @@ MidiTimeAxisView::show_existing_automation (bool apply_to_selection) const set params = midi_track()->midi_playlist()->contained_automation(); for (set::const_iterator i = params.begin(); i != params.end(); ++i) { - create_automation_child(*i, true); + create_automation_child (*i, true); } } @@ -846,41 +867,71 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool } AutomationTracks::iterator existing = _automation_tracks.find (param); + if (existing != _automation_tracks.end()) { + + /* automation track created because we had existing data for + * the processor, but visibility may need to be controlled + * 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 (); + } + return; } - if (param.type() == GainAutomation) { - create_gain_automation_child (param, show); - } else { + boost::shared_ptr track; - /* These controllers are region "automation", so we do not create - * an AutomationList/Line for the track */ - - boost::shared_ptr track ( - new AutomationTimeAxisView ( - _session, - _route, - boost::shared_ptr (), - boost::shared_ptr (), - param, - _editor, - *this, - true, - parent_canvas, - _route->describe_parameter(param) - ) - ); + switch (param.type()) { + + case GainAutomation: + create_gain_automation_child (param, show); + break; + + case PluginAutomation: + /* handled elsewhere */ + break; + + case MidiCCAutomation: + case MidiPgmChangeAutomation: + case MidiPitchBenderAutomation: + case MidiChannelPressureAutomation: + case MidiSystemExclusiveAutomation: + /* These controllers are region "automation" - they are owned + * by regions (and their MidiModels), not by the track. As a + * result we do not create an AutomationList/Line for the track + * ... except here we are doing something!! XXX + */ + + track.reset (new AutomationTimeAxisView ( + _session, + _route, + boost::shared_ptr (), + boost::shared_ptr (), + param, + _editor, + *this, + true, + parent_canvas, + _route->describe_parameter(param) + )); if (_view) { _view->foreach_regionview (sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost)); } add_automation_child (param, track, show); + break; + + default: + error << "MidiTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg; } } - void MidiTimeAxisView::route_active_changed () { @@ -912,7 +963,21 @@ MidiTimeAxisView::route_active_changed () } } +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) @@ -963,11 +1028,17 @@ MidiTimeAxisView::toggle_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(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(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) { @@ -1006,9 +1077,9 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t) /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden() which will cause a redraw. We don't want one per channel, so block that with no_redraw. */ - changed = track->set_visibility (false) || changed; + changed = track->set_marked_for_display (false) || changed; } else { - changed = track->set_visibility (true) || changed; + changed = track->set_marked_for_display (true) || changed; } } } @@ -1023,7 +1094,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t) controller_menu = 0; if (changed) { - _route->gui_changed ("track_height", this); + request_redraw (); } } @@ -1129,3 +1200,10 @@ MidiTimeAxisView::get_channel_for_add () const return channel; } + +void +MidiTimeAxisView::note_range_changed () +{ + set_gui_property ("note-range-min", (int) midi_view()->lowest_note ()); + set_gui_property ("note-range-max", (int) midi_view()->highest_note ()); +}