summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-07-01 13:36:50 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-07-01 13:36:50 +0000
commit0d6515a24349be9add8d3919d4c6c4d509bac687 (patch)
treeeca75aee7588424eddd30b558098321acf686c65
parent4df4574be472b599e149af2ef161ed505088e71a (diff)
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
-rw-r--r--gtk2_ardour/mixer_strip.cc38
-rw-r--r--gtk2_ardour/processor_box.cc4
-rw-r--r--gtk2_ardour/rc_option_editor.cc26
-rw-r--r--gtk2_ardour/route_time_axis.cc8
-rw-r--r--gtk2_ardour/route_ui.cc214
-rw-r--r--gtk2_ardour/route_ui.h1
-rw-r--r--libs/ardour/ardour/buffer_set.h1
-rw-r--r--libs/ardour/ardour/internal_return.h2
-rw-r--r--libs/ardour/ardour/rc_configuration_vars.h4
-rw-r--r--libs/ardour/ardour/route.h7
-rw-r--r--libs/ardour/ardour/session.h16
-rw-r--r--libs/ardour/ardour/types.h9
-rw-r--r--libs/ardour/buffer_set.cc71
-rw-r--r--libs/ardour/enums.cc9
-rw-r--r--libs/ardour/globals.cc2
-rw-r--r--libs/ardour/internal_return.cc6
-rw-r--r--libs/ardour/route.cc115
-rw-r--r--libs/ardour/session.cc157
-rw-r--r--libs/ardour/session_state.cc8
19 files changed, 444 insertions, 254 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<SoloModel>* sm = new ComboOption<SoloModel> (
- "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<ListenPosition>* lp = new ComboOption<ListenPosition> (
+ "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<Route> 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 (solo_menu == 0) {
- build_solo_menu ();
- }
- solo_menu->popup (1, ev->time);
+ if (Config->get_solo_control_is_listen_control()) {
- } else {
+ _route->set_listen (!_route->listening(), this);
- if (Keyboard::is_button2_event (ev)) {
+ } else {
- // 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)) {
+
+ // 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)) {
- } 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 (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 {
- _route->set_solo_isolated (!_route->solo_isolated(), this);
- wait_for_release = false;
- }
-
- } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+
+ } 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;
+ }
- /* Primary-button1: solo mix group.
- NOTE: Primary-button2 is MIDI learn.
- */
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- if (ev->button == 1) {
- set_route_group_solo (_route, !_route->soloed());
- }
+ /* Primary-button1: solo mix group.
+ NOTE: Primary-button2 is MIDI learn.
+ */
- } else {
+ if (ev->button == 1) {
+ set_route_group_solo (_route, !_route->soloed());
+ }
- /* 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<Gdk::Color> 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<void> active_changed;
sigc::signal<void> phase_invert_changed;
sigc::signal<void> denormal_protection_changed;
+ sigc::signal<void,void*> listen_changed;
sigc::signal<void,void*> solo_changed;
sigc::signal<void,void*> solo_safe_changed;
sigc::signal<void,void*> solo_isolated_changed;
@@ -262,7 +267,7 @@ class Route : public SessionObject, public AutomatableControls
sigc::signal<void,void*> SelectedChanged;
- int listen_via (boost::shared_ptr<Route>, const std::string& name);
+ int listen_via (boost::shared_ptr<Route>, bool);
void drop_listen (boost::shared_ptr<Route>);
bool feeds (boost::shared_ptr<Route>);
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<void,bool> SoloActive;
sigc::signal<void> 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<Route>);
void route_mute_changed (void *src);
void route_solo_changed (void *src, boost::weak_ptr<Route>);
- void catch_up_on_solo ();
- void catch_up_on_solo_mute_override ();
- void solo_model_changed ();
void update_route_solo_state (boost::shared_ptr<RouteList> r = boost::shared_ptr<RouteList>());
- 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<MonitorModel> (o, var); }
std::istream& operator>>(std::istream& o, RemoteModel& var) { return int_to_type<RemoteModel> (o, var); }
std::istream& operator>>(std::istream& o, EditMode& var) { return int_to_type<EditMode> (o, var); }
-std::istream& operator>>(std::istream& o, SoloModel& var) { return int_to_type<SoloModel> (o, var); }
+std::istream& operator>>(std::istream& o, ListenPosition& var) { return int_to_type<ListenPosition> (o, var); }
std::istream& operator>>(std::istream& o, LayerModel& var) { return int_to_type<LayerModel> (o, var); }
std::istream& operator>>(std::istream& o, CrossfadeModel& var) { return int_to_type<CrossfadeModel> (o, var); }
std::istream& operator>>(std::istream& o, SlaveSource& var) { return int_to_type<SlaveSource> (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) {
+
+ if (is_control() && _session.listening()) {
- BufferSet::iterator o = bufs.begin(*t);
- PortSet& ports (_input->ports());
+ /* 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);
- for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
- o->read_from (i->get_buffer(nframes), nframes);
+ } 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);
+ }
}
}
@@ -475,6 +487,32 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n
}
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)
{
if (_solo_safe || _solo_isolated) {
@@ -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> processor, ProcessorList::ite
}
// XXX: do we want to emit the signal here ? change call order.
- processor->activate ();
+ if (!boost::dynamic_pointer_cast<InternalSend>(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<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*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> route, const string& listen_name)
+Route::listen_via (boost::shared_ptr<Route> route, bool active)
{
vector<string> ports;
vector<string>::const_iterator i;
@@ -1893,6 +1895,7 @@ Route::listen_via (boost::shared_ptr<Route> route, const string& listen_name)
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
+
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
if (d && d->target_route() == route) {
@@ -1921,6 +1924,10 @@ Route::listen_via (boost::shared_ptr<Route> 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<Route> 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<Route> 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<Route> 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<Route> 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<Route> dest, boost::shared_ptr<Ro
continue;
}
- (*i)->listen_via (dest, "aux");
+ (*i)->listen_via (dest, true);
}
}
@@ -2254,6 +2296,22 @@ Session::route_mute_changed (void* src)
}
void
+Session::route_listen_changed (void* src, boost::weak_ptr<Route> wpr)
+{
+ boost::shared_ptr<Route> 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<Route> wpr)
{
if (solo_update_disabled) {
@@ -2329,34 +2387,6 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> 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<RouteList> r = routes.reader ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- // (*i)->catch_up_on_solo_mute_override ();
- }
-}
-
shared_ptr<Route>
Session::route_by_name (string name)
{
@@ -3492,6 +3522,20 @@ Session::set_all_solo (bool yn)
}
void
+Session::set_all_listen (bool yn)
+{
+ shared_ptr<RouteList> 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)
{
shared_ptr<RouteList> r = routes.reader ();
@@ -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;
}
@@ -4282,6 +4323,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 ()
{
RouteGroupChanged (); /* EMIT SIGNAL */
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 ();
}