perhaps, just possibly, a working solo model. needs to be fixed so that connections to other JACK clients count as "physical" connections, so don't use this with ardour connected to other JACK apps just yet. Oh, this also invalidates existing a3 sessions again

git-svn-id: svn://localhost/ardour2/branches/3.0@7033 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-05-01 15:09:19 +00:00
parent e99cf351f5
commit 576cdb08b5
13 changed files with 273 additions and 53 deletions

View File

@ -838,7 +838,7 @@ RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
if (r->self_muted ()) {
/* full mute */
return 2;
} else if (r->muted_by_others()) {
} else if (r->muted_by_others() || r->path_muted_by_others()) {
return 1;
} else {
/* no mute at all */

View File

@ -108,7 +108,8 @@ class IO : public SessionObject, public Latent
int disconnect (void *src);
bool connected_to (boost::shared_ptr<const IO>) const;
bool connected () const;
bool physically_connected () const;
nframes_t signal_latency() const { return _own_latency; }
nframes_t latency() const;
void set_port_latency (nframes_t);

View File

@ -25,11 +25,13 @@
#include "pbd/stateful.h"
#include <string>
#include "ardour/session_handle.h"
namespace ARDOUR {
class Session;
class MuteMaster : public PBD::Stateful
class MuteMaster : public SessionHandleRef, public PBD::Stateful
{
public:
enum MutePoint {
@ -69,7 +71,7 @@ class MuteMaster : public PBD::Stateful
void set_mute_points (MutePoint);
MutePoint mute_points() const { return _mute_point; }
void set_solo_level (int32_t);
void set_solo_level (SoloLevel);
PBD::Signal0<void> MutePointChanged;
@ -80,7 +82,7 @@ class MuteMaster : public PBD::Stateful
volatile MutePoint _mute_point;
volatile bool _self_muted;
volatile uint32_t _muted_by_others;
volatile int32_t _solo_level;
volatile SoloLevel _solo_level;
};
} // namespace ARDOUR

View File

@ -116,6 +116,8 @@ public:
}
virtual void transport_stopped () {}
bool physically_connected () const;
static void set_engine (AudioEngine *);
PBD::Signal1<void,bool> MonitorInputChanged;
@ -128,7 +130,7 @@ protected:
static nframes_t _port_offset;
static nframes_t _buffer_size;
static AudioEngine* _engine; ///< the AudioEngine
private:

View File

@ -129,6 +129,9 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
bool self_muted () const;
bool muted_by_others () const;
bool path_muted_by_others() const { return _path_muted_by_others > 0; }
void mod_path_muted_by_others (int delta);
void set_mute (bool yn, void* src);
void mod_muted_by_others (int delta);
@ -138,7 +141,9 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
void set_solo (bool yn, void *src);
bool soloed () const { return self_soloed () || soloed_by_others (); }
bool soloed_by_others () const { return !_solo_isolated && _soloed_by_others; }
bool soloed_by_others () const { return _soloed_by_others_upstream||_soloed_by_others_downstream; }
bool soloed_by_others_upstream () const { return _soloed_by_others_upstream; }
bool soloed_by_others_downstream () const { return _soloed_by_others_downstream; }
bool self_soloed () const { return _self_solo; }
void set_solo_isolated (bool yn, void *src);
@ -372,8 +377,15 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
protected:
friend class Session;
void set_graph_level (int32_t);
int32_t graph_level() const { return _graph_level; }
void check_physical_connections ();
// this functions may ONLY be called during a route resort
bool physically_connected () const { return _physically_connected; }
void catch_up_on_solo_mute_override ();
void mod_solo_by_others (int32_t);
void mod_solo_by_others_upstream (int32_t);
void mod_solo_by_others_downstream (int32_t);
bool has_external_redirects() const;
void curve_reallocate ();
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
@ -411,7 +423,8 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
MeterPoint _meter_point;
uint32_t _phase_invert;
bool _self_solo;
uint32_t _soloed_by_others;
uint32_t _soloed_by_others_upstream;
uint32_t _soloed_by_others_downstream;
uint32_t _solo_isolated;
bool _denormal_protection;
@ -424,9 +437,12 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
boost::shared_ptr<MuteControllable> _mute_control;
boost::shared_ptr<MuteMaster> _mute_master;
MuteMaster::MutePoint _mute_points;
volatile uint32_t _path_muted_by_others;
std::string _comment;
bool _have_internal_generator;
bool _physically_connected; // valid ONLY during a route resort
int32_t _graph_level;
bool _solo_safe;
DataType _default_type;
FedBy _fed_by;

View File

@ -415,6 +415,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void remove_route (boost::shared_ptr<Route>);
void resort_routes ();
void resort_routes_using (boost::shared_ptr<RouteList>);
void find_route_levels (boost::shared_ptr<RouteList>);
void set_remote_control_ids();

View File

@ -306,6 +306,13 @@ namespace ARDOUR {
PreFaderListen
};
enum SoloLevel {
NotSoloed,
DownstreamSoloed,
UpstreamSoloed,
SelfSoloed
};
enum AutoConnectOption {
ManualConnect = 0x0,
AutoConnectPhysical = 0x1,

View File

@ -500,6 +500,7 @@ Delivery::target_gain ()
break;
}
// cerr << name() << ' ';
desired_gain = _mute_master->mute_gain_at (mp);
if (_role == Listen && _session.monitor_out() && !_session.listening()) {

View File

@ -1553,3 +1553,15 @@ IO::port_by_name (const std::string& str) const
return 0;
}
bool
IO::physically_connected () const
{
for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
if (i->physically_connected()) {
return true;
}
}
return false;
}

View File

@ -23,7 +23,7 @@
#include "ardour/types.h"
#include "ardour/mute_master.h"
#include "ardour/rc_configuration.h"
#include "ardour/session.h"
#include "i18n.h"
@ -35,8 +35,9 @@ const MuteMaster::MutePoint MuteMaster::AllPoints = MutePoint (MuteMaster::PreFa
MuteMaster::Listen|
MuteMaster::Main);
MuteMaster::MuteMaster (Session&, const std::string&)
: _mute_point (AllPoints)
MuteMaster::MuteMaster (Session& s, const std::string&)
: SessionHandleRef (s)
, _mute_point (AllPoints)
, _self_muted (false)
, _muted_by_others (0)
{
@ -83,7 +84,7 @@ MuteMaster::mod_muted_by_others (int32_t delta)
}
void
MuteMaster::set_solo_level (int32_t l)
MuteMaster::set_solo_level (SoloLevel l)
{
_solo_level = l;
}
@ -92,14 +93,16 @@ gain_t
MuteMaster::mute_gain_at (MutePoint mp) const
{
gain_t gain;
int32_t l = _solo_level;
const SoloLevel l = _solo_level;
// cerr << "solo level = " << _solo_level << " selfmuted " << self_muted_at (mp) << " omute " << muted_by_others_at (mp) << endl;
if (Config->get_solo_mute_override()) {
if (l == 2) { // self-soloed
if ((l == SelfSoloed) || (l == DownstreamSoloed)) {
gain = 1.0;
} else if (self_muted_at (mp)) { // self-muted
gain = Config->get_solo_mute_gain ();
} else if (l == 1) { // soloed by others
} else if (l == UpstreamSoloed) {
gain = 1.0;
} else if (muted_by_others_at (mp)) { // muted by others
gain = Config->get_solo_mute_gain ();
@ -109,17 +112,19 @@ MuteMaster::mute_gain_at (MutePoint mp) const
} else {
if (self_muted_at (mp)) { // self-muted
gain = Config->get_solo_mute_gain ();
} else if (l == 2) { // self-soloed
} else if ((l == SelfSoloed) || (l == DownstreamSoloed)) {
gain = 1.0;
} else if (muted_by_others_at (mp)) { // muted by others
gain = Config->get_solo_mute_gain ();
} else if (l == 1) { // soloed by others
} else if (l == UpstreamSoloed) { // soloed by others
gain = 1.0;
} else {
gain = 1.0;
}
}
// cerr << "\tgain = " << gain << endl;
return gain;
}
@ -130,7 +135,7 @@ MuteMaster::set_mute_points (const std::string& mute_point)
_mute_point = (MutePoint) string_2_enum (mute_point, _mute_point);
cerr << "Mute point set from string, now " << _mute_point << endl;
if (old != _mute_point) {
MutePointChanged(); /* EMIT SIGNAL */
}
@ -152,7 +157,7 @@ MuteMaster::set_state (const XMLNode& node, int /*version*/)
const XMLProperty* prop;
if ((prop = node.property ("mute-point")) != 0) {
//_mute_point = (MutePoint) string_2_enum (prop->value(), _mute_point);
_mute_point = (MutePoint) string_2_enum (prop->value(), _mute_point);
cerr << "Mute point set from STATE string, now " << _mute_point << endl;
}

View File

@ -99,7 +99,8 @@ Port::get_connections (std::vector<std::string> & c) const
c.push_back (jc[i]);
++n;
}
free (jc);
jack_free (jc);
}
return n;
@ -148,7 +149,7 @@ Port::disconnect (std::string const & other)
_connections.erase (other);
}
return r;
return r;
}
@ -290,3 +291,24 @@ Port::set_latency (nframes_t n)
jack_port_set_latency (_jack_port, n);
}
bool
Port::physically_connected () const
{
const char** jc = jack_port_get_connections (_jack_port);
if (jc) {
for (int i = 0; jc[i]; ++i) {
jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]);
if (port && (jack_port_flags (port) & JackPortIsPhysical)) {
jack_free (jc);
return true;
}
}
jack_free (jc);
}
return false;
}

View File

@ -80,7 +80,8 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
, _meter_point (MeterPostFader)
, _phase_invert (0)
, _self_solo (false)
, _soloed_by_others (0)
, _soloed_by_others_upstream (0)
, _soloed_by_others_downstream (0)
, _solo_isolated (0)
, _denormal_protection (false)
, _recordable (true)
@ -90,7 +91,10 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
, _mute_control (new MuteControllable (X_("mute"), *this))
, _mute_master (new MuteMaster (sess, name))
, _mute_points (MuteMaster::AllPoints)
, _path_muted_by_others (false)
, _have_internal_generator (false)
, _physically_connected (false)
, _graph_level (-1)
, _solo_safe (false)
, _default_type (default_type)
, _remote_control_id (0)
@ -447,6 +451,10 @@ Route::process_output_buffers (BufferSet& bufs,
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
if (rm.locked()) {
//cerr << name() << " upstream solo " << _soloed_by_others_upstream
// << " downstream solo " << _soloed_by_others_downstream
// << " self " << _self_solo
//<< endl;
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (bufs.count() != (*i)->input_streams()) {
@ -589,20 +597,41 @@ Route::set_self_solo (bool yn)
}
void
Route::mod_solo_by_others (int32_t delta)
Route::mod_solo_by_others_upstream (int32_t delta)
{
if (_solo_safe) {
return;
}
if (delta < 0) {
if (_soloed_by_others >= (uint32_t) abs (delta)) {
_soloed_by_others += delta;
if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
_soloed_by_others_upstream += delta;
} else {
_soloed_by_others = 0;
_soloed_by_others_upstream = 0;
}
} else {
_soloed_by_others += delta;
_soloed_by_others_upstream += delta;
}
set_mute_master_solo ();
solo_changed (false, this);
}
void
Route::mod_solo_by_others_downstream (int32_t delta)
{
if (_solo_safe) {
return;
}
if (delta < 0) {
if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
_soloed_by_others_downstream += delta;
} else {
_soloed_by_others_downstream = 0;
}
} else {
_soloed_by_others_downstream += delta;
}
set_mute_master_solo ();
@ -612,14 +641,16 @@ Route::mod_solo_by_others (int32_t delta)
void
Route::set_mute_master_solo ()
{
int32_t level;
SoloLevel level;
if (self_soloed()) {
level = 2;
} else if (soloed_by_others()) {
level = 1;
level = SelfSoloed;
} else if (soloed_by_others_upstream()) {
level = UpstreamSoloed;
} else if (soloed_by_others_downstream()) {
level = DownstreamSoloed;
} else {
level = 0;
level = NotSoloed;
}
_mute_master->set_solo_level (level);
@ -722,19 +753,31 @@ Route::muted_by_others() const
void
Route::mod_muted_by_others (int delta)
{
bool old = muted ();
if (_solo_isolated) {
return;
}
bool old = muted ();
_mute_master->mod_muted_by_others (delta);
if (old != muted()) {
mute_changed (this);
}
}
void
Route::mod_path_muted_by_others (int32_t delta)
{
if (delta < 0) {
if (_path_muted_by_others >= (uint32_t) abs (delta)) {
_path_muted_by_others += delta;
} else {
_path_muted_by_others = 0;
}
} else {
_path_muted_by_others += delta;
}
}
#if 0
static void
dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
@ -1683,8 +1726,10 @@ Route::state(bool full_state)
}
node->add_property ("order-keys", order_string);
node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
snprintf (buf, sizeof (buf), "%d", _soloed_by_others);
node->add_property ("soloed-by-others", buf);
snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
node->add_property ("soloed-by-upstream", buf);
snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
node->add_property ("soloed-by-downstream", buf);
node->add_child_nocopy (_input->state (full_state));
node->add_child_nocopy (_output->state (full_state));
@ -1782,9 +1827,14 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
set_self_solo (string_is_affirmative (prop->value()));
}
if ((prop = node.property ("soloed-by-others")) != 0) {
_soloed_by_others = 0; // needed for mod_solo_by_others () to work
mod_solo_by_others (atoi (prop->value()));
if ((prop = node.property ("soloed-by-upstream")) != 0) {
_soloed_by_others_upstream = 0; // needed for mod_.... () to work
mod_solo_by_others_upstream (atoi (prop->value()));
}
if ((prop = node.property ("soloed-by-downstream")) != 0) {
_soloed_by_others_downstream = 0; // needed for mod_.... () to work
mod_solo_by_others_downstream (atoi (prop->value()));
}
if ((prop = node.property ("solo-isolated")) != 0) {
@ -2531,6 +2581,12 @@ Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
return false;
}
void
Route::check_physical_connections ()
{
_physically_connected = _output->physically_connected ();
}
void
Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
{
@ -3301,3 +3357,9 @@ Route::has_io_processor_named (const string& name)
return false;
}
void
Route::set_graph_level (int32_t l)
{
_graph_level = l;
}

View File

@ -17,6 +17,9 @@
*/
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>
@ -1350,6 +1353,10 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
{
RouteList::iterator i, j;
for (i = r->begin(); i != r->end(); ++i) {
(*i)->check_physical_connections ();
}
for (i = r->begin(); i != r->end(); ++i) {
(*i)->clear_fed_by ();
@ -1381,15 +1388,102 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
RouteSorter cmp;
r->sort (cmp);
find_route_levels (r);
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n", (*i)->name(), (*i)->order_key ("signal")));
DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2 level %3\n",
(*i)->name(), (*i)->order_key ("signal"),
(*i)->graph_level()));
}
#endif
}
void
Session::find_route_levels (shared_ptr<RouteList> rl)
{
uint32_t setcnt = 0;
uint32_t limit = rl->size();
RouteList last_level;
RouteList this_level;
for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
/* find routes with direct physical connections,
or routes with no connections at all. Mark them
with "special" level values, and push them into
the "last_level" set.
All other routes get marked with a graph level
of -1, which indicates that it needs to be set.
*/
if ((*r)->physically_connected()) {
last_level.push_back (*r);
(*r)->set_graph_level (0);
setcnt++;
} else if (!(*r)->output()->connected()) {
last_level.push_back (*r);
(*r)->set_graph_level (INT32_MAX/2);
setcnt++;
} else {
(*r)->set_graph_level (-1);
}
}
// until we've set the graph level for every route ...
while (setcnt < limit) {
for (RouteList::reverse_iterator r = rl->rbegin(); r != rl->rend(); ++r) {
int32_t l = INT32_MAX;
bool found = false;
if ((*r)->graph_level() != -1) {
// we already have the graph level for this route
continue;
}
/* check if this route (r) has a direction connection to anything in
the set of routes we processed last time. On the first pass
through this, last_level will contain routes with either
no connections or direct "physical" connections. If there is
at least 1 connection, store the lowest graph level of whatever
r is connected to.
*/
for (RouteList::iterator o = last_level.begin(); o != last_level.end(); ++o) {
bool sends_only;
if ((*r)->direct_feeds (*o, &sends_only)) {
if (!sends_only) {
l = min (l, (*o)->graph_level());
found = true;
}
}
}
/* if we found any connections, then mark the graph level of r, and push
it into the "this_level" set that will become "last_level" next time
around the while() loop.
*/
if (found) {
(*r)->set_graph_level (l + 1);
this_level.push_back (*r);
setcnt++;
}
}
last_level = this_level;
this_level.clear ();
}
}
/** Find the route name starting with \a base with the lowest \a id.
*
* Names are constructed like e.g. "Audio 3" for base="Audio" and id=3.
@ -2185,13 +2279,14 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
bool via_sends_only;
bool in_signal_flow;
if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
continue;
}
in_signal_flow = false;
if ((*i)->graph_level () == route->graph_level()) {
(*i)->mod_muted_by_others (delta);
}
/* feed-backwards (other route to solo change route):
@ -2204,8 +2299,7 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
if ((*i)->feeds (route, &via_sends_only)) {
if (!via_sends_only) {
(*i)->mod_solo_by_others (delta);
in_signal_flow = true;
(*i)->mod_solo_by_others_upstream (delta);
}
}
@ -2218,12 +2312,7 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
*/
if (route->feeds (*i, &via_sends_only)) {
(*i)->mod_solo_by_others (delta);
in_signal_flow = true;
}
if (!in_signal_flow) {
(*i)->mod_muted_by_others (delta);
(*i)->mod_solo_by_others_downstream (delta);
}
}