From 0d6515a24349be9add8d3919d4c6c4d509bac687 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 1 Jul 2009 13:36:50 +0000 Subject: [PATCH] separate solo & listen. some minor fixes and additional related fixes still to come git-svn-id: svn://localhost/ardour2/branches/3.0@5298 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/mixer_strip.cc | 38 ++-- gtk2_ardour/processor_box.cc | 4 + gtk2_ardour/rc_option_editor.cc | 26 ++- gtk2_ardour/route_time_axis.cc | 8 +- gtk2_ardour/route_ui.cc | 222 ++++++++++++--------- gtk2_ardour/route_ui.h | 1 + libs/ardour/ardour/buffer_set.h | 1 + libs/ardour/ardour/internal_return.h | 2 +- libs/ardour/ardour/rc_configuration_vars.h | 4 +- libs/ardour/ardour/route.h | 7 +- libs/ardour/ardour/session.h | 16 +- libs/ardour/ardour/types.h | 9 +- libs/ardour/buffer_set.cc | 71 +++++++ libs/ardour/enums.cc | 9 +- libs/ardour/globals.cc | 2 +- libs/ardour/internal_return.cc | 6 +- libs/ardour/route.cc | 117 ++++++----- libs/ardour/session.cc | 157 ++++++++++----- libs/ardour/session_state.cc | 8 +- 19 files changed, 449 insertions(+), 259 deletions(-) diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 33bc024ee8..a862b15ccd 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -1459,32 +1459,34 @@ MixerStrip::set_button_names () case Wide: rec_enable_button_label.set_text (_("Rec")); mute_button_label.set_text (_("Mute")); - switch (Config->get_solo_model()) { - case SoloInPlace: + if (!Config->get_solo_control_is_listen_control()) { solo_button_label.set_text (_("Solo")); - break; - case SoloAFL: - solo_button_label.set_text (_("AFL")); - break; - case SoloPFL: - solo_button_label.set_text (_("PFL")); - break; + } else { + switch (Config->get_listen_position()) { + case AfterFaderListen: + solo_button_label.set_text (_("AFL")); + break; + case PreFaderListen: + solo_button_label.set_text (_("PFL")); + break; + } } break; default: rec_enable_button_label.set_text (_("R")); mute_button_label.set_text (_("M")); - switch (Config->get_solo_model()) { - case SoloInPlace: + if (!Config->get_solo_control_is_listen_control()) { solo_button_label.set_text (_("S")); - break; - case SoloAFL: - solo_button_label.set_text (_("A")); - break; - case SoloPFL: - solo_button_label.set_text (_("P")); - break; + } else { + switch (Config->get_listen_position()) { + case AfterFaderListen: + solo_button_label.set_text (_("A")); + break; + case PreFaderListen: + solo_button_label.set_text (_("P")); + break; + } } break; diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index f8ea758549..ae1d6c73ab 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -1063,6 +1063,10 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist) /* do not copy-n-paste amp */ continue; + } else if (type->value() == "intsend" || type->value() == "intreturn") { + /* do not copy-n-paste internal sends&returns */ + continue; + } else if (type->value() == "listen") { p.reset (new Delivery (_session, _route->mute_master(), **niter)); diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index bddc9d5b07..6a3fe486ee 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1158,18 +1158,26 @@ RCOptionEditor::RCOptionEditor () add_option (_("Audio"), new OptionEditorHeading (_("Solo"))); - ComboOption* sm = new ComboOption ( - "solo-model", - _("Solo button controls"), - mem_fun (*_rc_config, &RCConfiguration::get_solo_model), - mem_fun (*_rc_config, &RCConfiguration::set_solo_model) + + add_option (_("Audio"), + new BoolOption ( + "solo-control-is-listen-control", + _("Solo controls are Listen controls"), + mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control), + mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control) + )); + + ComboOption* lp = new ComboOption ( + "listen-position", + _("Listen Position"), + mem_fun (*_rc_config, &RCConfiguration::get_listen_position), + mem_fun (*_rc_config, &RCConfiguration::set_listen_position) ); - sm->add (SoloInPlace, _("solo in place")); - sm->add (SoloAFL, _("post-fader listen via monitor bus")); - sm->add (SoloPFL, _("pre-fader listen via monitor bus")); + lp->add (AfterFaderListen, _("after-fader listen")); + lp->add (PreFaderListen, _("pre-fader listen")); - add_option (_("Audio"), sm); + add_option (_("Audio"), lp); add_option (_("Audio"), new SoloMuteOptions (_rc_config)); add_option (_("Audio"), diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 7d5ac17735..d7e4d3c1b7 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -2396,7 +2396,13 @@ void RouteTimeAxisView::set_button_names () { rec_enable_button_label.set_text (_("r")); - solo_button_label.set_text (_("s")); + + if (Config->get_solo_control_is_listen_control()) { + solo_button_label.set_text (_("l")); + } else { + solo_button_label.set_text (_("s")); + } + mute_button_label.set_text (_("m")); } diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 8877a5a823..ba805f7d4b 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -188,6 +188,7 @@ RouteUI::set_route (boost::shared_ptr rp) connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed))); connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed))); connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed))); + connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed))); connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed))); if (is_track()) { @@ -322,102 +323,110 @@ RouteUI::solo_press(GdkEventButton* ev) if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) { return true; } - multiple_solo_change = false; - if (!ignore_toggle) { - if (Keyboard::is_context_menu_event (ev)) { + if (Config->get_solo_control_is_listen_control()) { - if (solo_menu == 0) { - build_solo_menu (); - } + _route->set_listen (!_route->listening(), this); - solo_menu->popup (1, ev->time); + } else { - } else { - - if (Keyboard::is_button2_event (ev)) { - - // Primary-button2 click is the midi binding click - // button2-click is "momentary" + multiple_solo_change = false; + if (!ignore_toggle) { + + if (Keyboard::is_context_menu_event (ev)) { - if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) { - wait_for_release = true; - } else { - return false; + if (solo_menu == 0) { + build_solo_menu (); } - } - - if (ev->button == 1 || Keyboard::is_button2_event (ev)) { - - if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { - - /* Primary-Tertiary-click applies change to all routes */ - bool was_not_latched = false; - if (!Config->get_solo_latched ()) { - was_not_latched = true; - /* - XXX it makes no sense to solo all tracks if we're - not in latched mode, but doing nothing feels like a bug, - so do it anyway - */ - Config->set_solo_latched (true); - } - _session.begin_reversible_command (_("solo change")); - Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); - _session.set_all_solo (!_route->soloed()); - cmd->mark(); - _session.add_command (cmd); - _session.commit_reversible_command (); - multiple_solo_change = true; - if (was_not_latched) { - Config->set_solo_latched (false); - } + + solo_menu->popup (1, ev->time); + + } else { + + if (Keyboard::is_button2_event (ev)) { - } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { - - // Primary-Secondary-click: exclusively solo this track, not a toggle */ - - _session.begin_reversible_command (_("solo change")); - Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this); - _session.set_all_solo (false); - _route->set_solo (true, this); - cmd->mark(); - _session.add_command(cmd); - _session.commit_reversible_command (); - - } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { - - // shift-click: set this route to solo safe - - if (Profile->get_sae() && ev->button == 1) { - // button 1 and shift-click: disables solo_latched for this click + // Primary-button2 click is the midi binding click + // button2-click is "momentary" + + if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) { + wait_for_release = true; + } else { + return false; + } + } + + if (ev->button == 1 || Keyboard::is_button2_event (ev)) { + + if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { + + /* Primary-Tertiary-click applies change to all routes */ + bool was_not_latched = false; if (!Config->get_solo_latched ()) { + was_not_latched = true; + /* + XXX it makes no sense to solo all tracks if we're + not in latched mode, but doing nothing feels like a bug, + so do it anyway + */ Config->set_solo_latched (true); - reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this); + } + _session.begin_reversible_command (_("solo change")); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); + _session.set_all_solo (!_route->soloed()); + cmd->mark(); + _session.add_command (cmd); + _session.commit_reversible_command (); + multiple_solo_change = true; + if (was_not_latched) { Config->set_solo_latched (false); } + + } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { + + // Primary-Secondary-click: exclusively solo this track, not a toggle */ + + _session.begin_reversible_command (_("solo change")); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this); + _session.set_all_solo (false); + _route->set_solo (true, this); + cmd->mark(); + _session.add_command(cmd); + _session.commit_reversible_command (); + + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { + + // shift-click: set this route to solo safe + + if (Profile->get_sae() && ev->button == 1) { + // button 1 and shift-click: disables solo_latched for this click + if (!Config->get_solo_latched ()) { + Config->set_solo_latched (true); + reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this); + Config->set_solo_latched (false); + } + } else { + _route->set_solo_isolated (!_route->solo_isolated(), this); + wait_for_release = false; + } + + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + + /* Primary-button1: solo mix group. + NOTE: Primary-button2 is MIDI learn. + */ + + if (ev->button == 1) { + set_route_group_solo (_route, !_route->soloed()); + } + } else { - _route->set_solo_isolated (!_route->solo_isolated(), this); - wait_for_release = false; - } - } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - - /* Primary-button1: solo mix group. - NOTE: Primary-button2 is MIDI learn. - */ - - if (ev->button == 1) { - set_route_group_solo (_route, !_route->soloed()); - } - - } else { - - /* click: solo this route */ - if (wait_for_release) { - _route->set_solo (!_route->soloed(), this); - } else { - reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this); + /* click: solo this route */ + if (wait_for_release) { + _route->set_solo (!_route->soloed(), this); + } else { + reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this); + } } } } @@ -614,7 +623,13 @@ RouteUI::send_blink (bool onoff) void RouteUI::solo_changed(void* src) { + Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display)); +} + +void +RouteUI::listen_changed(void* src) +{ Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display)); } @@ -622,21 +637,30 @@ void RouteUI::update_solo_display () { bool x; - vector fg_colors; - Gdk::Color c; - - if (solo_button->get_active() != (x = _route->soloed())){ - ignore_toggle = true; - solo_button->set_active(x); - ignore_toggle = false; - } - - if (_route->solo_isolated()) { - solo_button->set_visual_state (2); - } else if (_route->soloed()) { - solo_button->set_visual_state (1); + + if (Config->get_solo_control_is_listen_control()) { + + if (solo_button->get_active() != (x = _route->listening())) { + ignore_toggle = true; + solo_button->set_active(x); + ignore_toggle = false; + } + } else { - solo_button->set_visual_state (0); + + if (solo_button->get_active() != (x = _route->soloed())){ + ignore_toggle = true; + solo_button->set_active(x); + ignore_toggle = false; + } + + if (_route->solo_isolated()) { + solo_button->set_visual_state (2); + } else if (_route->soloed()) { + solo_button->set_visual_state (1); + } else { + solo_button->set_visual_state (0); + } } } @@ -1383,7 +1407,9 @@ RouteUI::parameter_changed (string const & p) if (p == "disable-disarm-during-roll") { check_rec_enable_sensitivity (); - } else if (p == "solo-model") { + } else if (p == "solo-control-is-listen-control") { + set_button_names (); + } else if (p == "listen-position") { set_button_names (); } } diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index b44bf235b5..3e9d55e62b 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -123,6 +123,7 @@ class RouteUI : public virtual AxisView void solo_changed(void*); void solo_changed_so_update_mute (); void mute_changed(void*); + void listen_changed(void*); virtual void processors_changed () {} void route_rec_enable_changed(); void session_rec_enable_changed(); diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h index ecd4e4ab72..664c22c583 100644 --- a/libs/ardour/ardour/buffer_set.h +++ b/libs/ardour/ardour/buffer_set.h @@ -59,6 +59,7 @@ public: void attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset = 0); void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity); + void ensure_buffers(const ChanCount& chns, size_t buffer_capacity); const ChanCount& available() const { return _available; } ChanCount& available() { return _available; } diff --git a/libs/ardour/ardour/internal_return.h b/libs/ardour/ardour/internal_return.h index a23b17adf8..c057d45cc8 100644 --- a/libs/ardour/ardour/internal_return.h +++ b/libs/ardour/ardour/internal_return.h @@ -34,7 +34,7 @@ class InternalReturn : public Return InternalReturn (Session&); InternalReturn (Session&, const XMLNode&); - bool visible() const { return false; } + bool visible() const { return true; } XMLNode& state(bool full); XMLNode& get_state(void); diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 20b9c85f0e..5217ea6aa7 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -77,7 +77,9 @@ CONFIG_VARIABLE (bool, mute_affects_post_fader, "mute-affects-post-fader", true) CONFIG_VARIABLE (bool, mute_affects_control_outs, "mute-affects-control-outs", true) CONFIG_VARIABLE (bool, mute_affects_main_outs, "mute-affects-main-outs", true) CONFIG_VARIABLE (MonitorModel, monitoring_model, "monitoring-model", ExternalMonitoring) -CONFIG_VARIABLE (SoloModel, solo_model, "solo-model", SoloInPlace) +CONFIG_VARIABLE (ListenPosition, listen_position, "listen-position", AfterFaderListen) + +CONFIG_VARIABLE (bool, solo_control_is_listen_control, "solo-control-is-listen-control", false) CONFIG_VARIABLE (bool, solo_latched, "solo-latched", true) CONFIG_VARIABLE (bool, latched_record_enable, "latched-record-enable", false) CONFIG_VARIABLE (bool, all_safe, "all-safe", false) diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index d346a22342..40a11cdae1 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -124,6 +124,7 @@ class Route : public SessionObject, public AutomatableControls void set_mute (bool yn, void* src); bool muted () const; + /* controls use set_solo() to modify this route's solo state */ @@ -132,6 +133,9 @@ class Route : public SessionObject, public AutomatableControls void set_solo_isolated (bool yn, void *src); bool solo_isolated() const; + + void set_listen (bool yn, void* src); + bool listening () const; void set_phase_invert (bool yn); bool phase_invert() const; @@ -229,6 +233,7 @@ class Route : public SessionObject, public AutomatableControls sigc::signal active_changed; sigc::signal phase_invert_changed; sigc::signal denormal_protection_changed; + sigc::signal listen_changed; sigc::signal solo_changed; sigc::signal solo_safe_changed; sigc::signal solo_isolated_changed; @@ -262,7 +267,7 @@ class Route : public SessionObject, public AutomatableControls sigc::signal SelectedChanged; - int listen_via (boost::shared_ptr, const std::string& name); + int listen_via (boost::shared_ptr, bool); void drop_listen (boost::shared_ptr); bool feeds (boost::shared_ptr); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 39822de678..2be7e418dc 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -723,9 +723,11 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* session-wide solo/mute/rec-enable */ bool soloing() const { return _non_soloed_outs_muted; } - + bool listening() const { return _listen_cnt > 0; } + void set_all_solo (bool); void set_all_mute (bool); + void set_all_listen (bool); sigc::signal SoloActive; sigc::signal SoloChanged; @@ -1031,6 +1033,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable float _meter_hold; float _meter_falloff; bool _non_soloed_outs_muted; + uint32_t _listen_cnt; void set_worst_io_latencies (); void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) { @@ -1451,16 +1454,15 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* mixer stuff */ - bool solo_update_disabled; + bool solo_update_disabled; + void route_listen_changed (void *src, boost::weak_ptr); void route_mute_changed (void *src); void route_solo_changed (void *src, boost::weak_ptr); - void catch_up_on_solo (); - void catch_up_on_solo_mute_override (); - void solo_model_changed (); void update_route_solo_state (boost::shared_ptr r = boost::shared_ptr()); - void modify_solo_mute (bool, bool); - void strip_portname_for_solo (std::string& portname); + + void listen_position_changed (); + void solo_control_mode_changed (); /* REGION MANAGEMENT */ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 3067928161..809eb5b2b2 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -330,10 +330,9 @@ namespace ARDOUR { AddHigher }; - enum SoloModel { - SoloInPlace, - SoloAFL, - SoloPFL + enum ListenPosition { + AfterFaderListen, + PreFaderListen }; enum AutoConnectOption { @@ -455,7 +454,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::AutoConnectOption& sf); std::istream& operator>>(std::istream& o, ARDOUR::EditMode& sf); std::istream& operator>>(std::istream& o, ARDOUR::MonitorModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf); -std::istream& operator>>(std::istream& o, ARDOUR::SoloModel& sf); +std::istream& operator>>(std::istream& o, ARDOUR::ListenPosition& sf); std::istream& operator>>(std::istream& o, ARDOUR::LayerModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::SlaveSource& sf); diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc index 7e6ddd68dd..589c13ce41 100644 --- a/libs/ardour/buffer_set.cc +++ b/libs/ardour/buffer_set.cc @@ -130,6 +130,7 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac } _available.set(type, num_buffers); + _count.set (type, num_buffers); } #ifdef HAVE_SLV2 @@ -149,6 +150,76 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac assert(bufs[0]->capacity() >= buffer_capacity); } +/** Ensure that the number of buffers of each type @a type matches @a chns + * and each buffer is of size at least @a buffer_capacity + */ +void +BufferSet::ensure_buffers(const ChanCount& chns, size_t buffer_capacity) +{ + if (chns == ChanCount::ZERO) { + return; + } + + // If we're a mirror just make sure we're ok + if (_is_mirror) { + assert(_count >= chns); + return; + } + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + + // The vector of buffers of this type + BufferVec& bufs = _buffers[*t]; + + uint32_t nbufs = chns.get (*t); + + if (nbufs == 0) { + // Nuke it + for (BufferVec::iterator i = bufs.begin(); i != bufs.end(); ++i) { + delete (*i); + } + bufs.clear(); + continue; + } + + // If there's not enough or they're too small, just nuke the whole thing and + // rebuild it (so I'm lazy..) + if (bufs.size() < nbufs + || (bufs.size() > 0 && bufs[0]->capacity() < buffer_capacity)) { + + // Nuke it + for (BufferVec::iterator i = bufs.begin(); i != bufs.end(); ++i) { + delete (*i); + } + bufs.clear(); + + // Rebuild it + for (size_t i = 0; i < nbufs; ++i) { + bufs.push_back(Buffer::create(*t, buffer_capacity)); + } + + _available.set (*t, nbufs); + } + +#ifdef HAVE_SLV2 + // Ensure enough low level MIDI format buffers are available for conversion + // in both directions (input & output, out-of-place) + if (*t == DataType::MIDI && _lv2_buffers.size() < _buffers[DataType::MIDI].size() * 2 + 1) { + while (_lv2_buffers.size() < _buffers[DataType::MIDI].size() * 2) { + _lv2_buffers.push_back(std::make_pair(false, new LV2EventBuffer(buffer_capacity))); + } + } +#endif + + // Post-conditions + assert(bufs[0]->type() == *t); + assert(bufs.size() == _available.get(*t)); + assert(bufs[0]->capacity() >= buffer_capacity); + } + + assert (available() == chns); +} + /** Get the capacity (size) of the available buffers of the given type. * * All buffers of a certain type always have the same capacity. diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 32a1420bc4..efe72ddb4b 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -64,7 +64,7 @@ setup_enum_writer () DenormalModel _DenormalModel; CrossfadeModel _CrossfadeModel; LayerModel _LayerModel; - SoloModel _SoloModel; + ListenPosition _ListenPosition; SampleFormat _SampleFormat; CDMarkerFormat _CDMarkerFormat; HeaderFormat _HeaderFormat; @@ -229,10 +229,9 @@ setup_enum_writer () REGISTER_ENUM (AddHigher); REGISTER (_LayerModel); - REGISTER_ENUM (SoloInPlace); - REGISTER_ENUM (SoloAFL); - REGISTER_ENUM (SoloPFL); - REGISTER (_SoloModel); + REGISTER_ENUM (AfterFaderListen); + REGISTER_ENUM (PreFaderListen); + REGISTER (_ListenPosition); REGISTER_ENUM (AutoConnectPhysical); REGISTER_ENUM (AutoConnectMaster); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 0ce024c31e..26e2baca26 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -604,7 +604,7 @@ std::istream& operator>>(std::istream& o, AutoConnectOption& var) { return int_t std::istream& operator>>(std::istream& o, MonitorModel& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, RemoteModel& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, EditMode& var) { return int_to_type (o, var); } -std::istream& operator>>(std::istream& o, SoloModel& var) { return int_to_type (o, var); } +std::istream& operator>>(std::istream& o, ListenPosition& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, LayerModel& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, CrossfadeModel& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, SlaveSource& var) { return int_to_type (o, var); } diff --git a/libs/ardour/internal_return.cc b/libs/ardour/internal_return.cc index 0a45228c67..f3ab1dd901 100644 --- a/libs/ardour/internal_return.cc +++ b/libs/ardour/internal_return.cc @@ -60,7 +60,7 @@ bool InternalReturn::configure_io (ChanCount in, ChanCount out) { IOProcessor::configure_io (in, out); - allocate_buffers (_session.get_block_size()); + allocate_buffers (_session.engine().frames_per_cycle()); return true; } @@ -73,8 +73,8 @@ InternalReturn::set_block_size (nframes_t nframes) void InternalReturn::allocate_buffers (nframes_t nframes) { - buffers.ensure_buffers (DataType::AUDIO, _configured_input.n_audio(), nframes); - buffers.ensure_buffers (DataType::MIDI, _configured_input.n_midi(), nframes); + buffers.ensure_buffers (_configured_input, nframes); + buffers.set_count (_configured_input); } BufferSet* diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 575cad8e0b..a6af898f38 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -454,14 +454,26 @@ Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, } bufs.set_count (_input->n_ports()); - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - - BufferSet::iterator o = bufs.begin(*t); - PortSet& ports (_input->ports()); - for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) { - o->read_from (i->get_buffer(nframes), nframes); + if (is_control() && _session.listening()) { + + /* control/monitor bus ignores input ports when something is + feeding the listen "stream". data will "arrive" into the + route from the intreturn processor element. + */ + + bufs.silence (nframes, 0); + + } else { + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + + BufferSet::iterator o = bufs.begin(*t); + PortSet& ports (_input->ports()); + + for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) { + o->read_from (i->get_buffer(nframes), nframes); + } } } @@ -474,6 +486,32 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick); } +void +Route::set_listen (bool yn, void* src) +{ + if (_control_outs) { + if (yn != _control_outs->active()) { + if (yn) { + _control_outs->activate (); + } else { + _control_outs->deactivate (); + } + + listen_changed (src); /* EMIT SIGNAL */ + } + } +} + +bool +Route::listening () const +{ + if (_control_outs) { + return _control_outs->active (); + } else { + return false; + } +} + void Route::set_solo (bool yn, void *src) { @@ -506,33 +544,11 @@ Route::mod_solo_level (int32_t delta) _solo_level += delta; } - /* tell "special" delivery units what the solo situation is + /* tell main outs what the solo situation is */ - switch (Config->get_solo_model()) { - case SoloInPlace: - /* main outs are used for soloing */ - _main_outs->set_solo_level (_solo_level); - _main_outs->set_solo_isolated (_solo_isolated); - if (_control_outs) { - /* control outs just keep on playing */ - _control_outs->set_solo_level (0); - _control_outs->set_solo_isolated (true); - } - break; - - case SoloAFL: - case SoloPFL: - /* control outs are used for soloing */ - if (_control_outs) { - _control_outs->set_solo_level (_solo_level); - _control_outs->set_solo_isolated (_solo_isolated); - } - /* main outs just keep on playing */ - _main_outs->set_solo_level (0); - _main_outs->set_solo_isolated (true); - break; - } + _main_outs->set_solo_level (_solo_level); + _main_outs->set_solo_isolated (_solo_isolated); } void @@ -546,28 +562,11 @@ Route::set_solo_isolated (bool yn, void *src) if (yn != _solo_isolated) { _solo_isolated = yn; - /* tell "special" delivery units what the solo situation is + /* tell main outs what the solo situation is */ - switch (Config->get_solo_model()) { - case SoloInPlace: - _main_outs->set_solo_level (_solo_level); - _main_outs->set_solo_isolated (_solo_isolated); - if (_control_outs) { - _main_outs->set_solo_level (1); - _main_outs->set_solo_isolated (false); - } - break; - case SoloAFL: - case SoloPFL: - if (_control_outs) { - _control_outs->set_solo_level (_solo_level); - _control_outs->set_solo_isolated (_solo_isolated); - } - _main_outs->set_solo_level (1); - _main_outs->set_solo_isolated (false); - break; - } + _main_outs->set_solo_level (_solo_level); + _main_outs->set_solo_isolated (_solo_isolated); solo_isolated_changed (src); } @@ -711,7 +710,9 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } // XXX: do we want to emit the signal here ? change call order. - processor->activate (); + if (!boost::dynamic_pointer_cast(processor)) { + processor->activate (); + } processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false)); _output->set_user_latency (0); @@ -1862,7 +1863,8 @@ Route::get_return_buffer () const boost::shared_ptr d = boost::dynamic_pointer_cast(*x); if (d) { - return d->get_buffers (); + BufferSet* bs = d->get_buffers (); + return bs; } } @@ -1884,7 +1886,7 @@ Route::release_return_buffer () const } int -Route::listen_via (boost::shared_ptr route, const string& listen_name) +Route::listen_via (boost::shared_ptr route, bool active) { vector ports; vector::const_iterator i; @@ -1893,6 +1895,7 @@ Route::listen_via (boost::shared_ptr route, const string& listen_name) Glib::RWLock::ReaderLock rm (_processor_lock); for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) { + boost::shared_ptr d = boost::dynamic_pointer_cast(*x); if (d && d->target_route() == route) { @@ -1921,6 +1924,10 @@ Route::listen_via (boost::shared_ptr route, const string& listen_name) return -1; } + if (route == _session.control_out()) { + _control_outs = listener; + } + add_processor (listener, PreFader); return 0; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 24a40f4c31..e470c2623e 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -46,6 +46,7 @@ #include "ardour/analyser.h" #include "ardour/audio_buffer.h" #include "ardour/audio_diskstream.h" +#include "ardour/audio_port.h" #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" @@ -269,16 +270,6 @@ Session::Session (AudioEngine &eng, RouteList rl; int control_id = 1; - if (control_out_channels) { - ChanCount count(DataType::AUDIO, control_out_channels); - shared_ptr r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO)); - r->input()->ensure_io (count, false, this); - r->output()->ensure_io (count, false, this); - r->set_remote_control_id (control_id++); - - rl.push_back (r); - } - if (master_out_channels) { ChanCount count(DataType::AUDIO, master_out_channels); shared_ptr r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO)); @@ -292,6 +283,16 @@ Session::Session (AudioEngine &eng, output_ac = AutoConnectOption (output_ac & ~AutoConnectMaster); } + if (control_out_channels) { + ChanCount count(DataType::AUDIO, control_out_channels); + shared_ptr r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO)); + r->input()->ensure_io (count, false, this); + r->output()->ensure_io (count, false, this); + r->set_remote_control_id (control_id++); + + rl.push_back (r); + } + if (!rl.empty()) { add_routes (rl, false); } @@ -680,11 +681,46 @@ Session::when_engine_running () if (_control_out) { - uint32_t limit = _control_out->n_outputs().n_total(); + /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else + are undefined, at best. + */ + + /* control out listens to master bus (but ignores it + under some conditions) + */ + + uint32_t limit = _control_out->n_inputs().n_audio(); + if (_master_out) { + for (uint32_t n = 0; n < limit; ++n) { + AudioPort* p = _control_out->input()->ports().nth_audio_port (n); + AudioPort* o = _master_out->output()->ports().nth_audio_port (n); + + if (o) { + string connect_to = o->name(); + if (_control_out->input()->connect (p, connect_to, this)) { + error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to) + << endmsg; + break; + } + } + } + } + + /* connect control out to physical outs, but use ones after the master + if possible + */ + + /* XXX this logic is wrong for mixed port types */ + + uint32_t shift = _master_out->n_outputs().n_audio(); + uint32_t mod = _master_out->n_outputs().n_audio(); + limit = _control_out->n_outputs().n_audio(); + for (uint32_t n = 0; n < limit; ++n) { + Port* p = _control_out->output()->nth (n); - string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n); + string connect_to = _engine.get_nth_physical_output (DataType (p->type()), (n+shift) % mod); if (!connect_to.empty()) { if (_control_out->output()->connect (p, connect_to, this)) { @@ -764,7 +800,7 @@ Session::hookup_io () continue; } - (*x)->listen_via (_control_out, X_("listen")); + (*x)->listen_via (_control_out, false); } } @@ -780,9 +816,13 @@ Session::hookup_io () graph_reordered (); - /* update mixer solo state */ + /* update the full solo state, which can't be + correctly determined on a per-route basis, but + needs the global overview that only the session + has. + */ - catch_up_on_solo(); + update_route_solo_state (); } void @@ -2069,6 +2109,7 @@ Session::add_routes (RouteList& new_routes, bool save) boost::weak_ptr wpr (*x); + (*x)->listen_changed.connect (sigc::bind (mem_fun (*this, &Session::route_listen_changed), wpr)); (*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr)); (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed)); (*x)->output()->changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x)); @@ -2090,7 +2131,8 @@ Session::add_routes (RouteList& new_routes, bool save) if ((*x)->is_control() || (*x)->is_master()) { continue; } - (*x)->listen_via (_control_out, "control"); + cerr << "Add listen via control outs\n"; + (*x)->listen_via (_control_out, false); } resort_routes (); @@ -2139,7 +2181,7 @@ Session::add_internal_sends (boost::shared_ptr dest, boost::shared_ptrlisten_via (dest, "aux"); + (*i)->listen_via (dest, true); } } @@ -2253,6 +2295,22 @@ Session::route_mute_changed (void* src) set_dirty (); } +void +Session::route_listen_changed (void* src, boost::weak_ptr wpr) +{ + boost::shared_ptr route = wpr.lock(); + if (!route) { + error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg; + return; + } + + if (route->listening()) { + _listen_cnt++; + } else if (_listen_cnt > 0) { + _listen_cnt--; + } +} + void Session::route_solo_changed (void* src, boost::weak_ptr wpr) { @@ -2329,34 +2387,6 @@ Session::update_route_solo_state (boost::shared_ptr r) } } -void -Session::catch_up_on_solo () -{ - /* this is called after set_state() to catch the full solo - state, which can't be correctly determined on a per-route - basis, but needs the global overview that only the session - has. - */ - update_route_solo_state(); -} - -void -Session::catch_up_on_solo_mute_override () -{ - if (Config->get_solo_model() != SoloInPlace) { - return; - } - - /* this is called whenever the param solo-mute-override is - changed. - */ - shared_ptr r = routes.reader (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - // (*i)->catch_up_on_solo_mute_override (); - } -} - shared_ptr Session::route_by_name (string name) { @@ -3491,6 +3521,20 @@ Session::set_all_solo (bool yn) set_dirty(); } +void +Session::set_all_listen (bool yn) +{ + shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->is_hidden()) { + (*i)->set_listen (yn, this); + } + } + + set_dirty(); +} + void Session::set_all_mute (bool yn) { @@ -4257,19 +4301,16 @@ Session::update_have_rec_enabled_diskstream () } void -Session::solo_model_changed () +Session::listen_position_changed () { Placement p; - switch (Config->get_solo_model()) { - case SoloInPlace: - return; - - case SoloAFL: + switch (Config->get_listen_position()) { + case AfterFaderListen: p = PostFader; break; - case SoloPFL: + case PreFaderListen: p = PreFader; break; } @@ -4281,6 +4322,18 @@ Session::solo_model_changed () } } +void +Session::solo_control_mode_changed () +{ + /* cancel all solo or all listen when solo control mode changes */ + + if (Config->get_solo_control_is_listen_control()) { + set_all_solo (false); + } else { + set_all_listen (false); + } +} + void Session::route_group_changed () { diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 32e31580af..c05dda60cd 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -152,6 +152,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) _non_soloed_outs_muted = false; + _listen_cnt = 0; g_atomic_int_set (&processing_prohibited, 0); _transport_speed = 0; _last_transport_speed = 0; @@ -3152,10 +3153,13 @@ Session::config_changed (std::string p, bool ours) } } else if (p == "solo-mute-override") { // catch_up_on_solo_mute_override (); - } else if (p == "solo-model") { - solo_model_changed (); + } else if (p == "listen-position") { + listen_position_changed (); + } else if (p == "solo-control-is-listen-control") { + solo_control_mode_changed (); } + set_dirty (); }