the big Route structure refactor. !!!! THIS WILL ***NOT LOAD*** PRIOR 3.0 or 2.X SESSIONS !!!! BREAKAGE IS EXPECTED !!!! IF YOU HAVE AND NEED A WORKING 3.0 DO **NOT** UPDATE. !!!! otherwise, update and enjoy the steadily emerging joys of this major reworking of ardour internals

git-svn-id: svn://localhost/ardour2/branches/3.0@5137 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis
2009-06-09 20:21:19 +00:00
parent 9bd274bfde
commit e6eb059576
77 changed files with 2688 additions and 3801 deletions

View File

@@ -118,6 +118,7 @@ midi_stretch.cc
midi_track.cc
mix.cc
mtc_slave.cc
mute_master.cc
named_selection.cc
onset_detector.cc
panner.cc

View File

@@ -19,24 +19,31 @@
#include <cstring>
#include <cmath>
#include <algorithm>
#include "evoral/Curve.hpp"
#include "ardour/amp.h"
#include "ardour/audio_buffer.h"
#include "ardour/buffer_set.h"
#include "ardour/configuration.h"
#include "ardour/io.h"
#include "ardour/mute_master.h"
#include "ardour/session.h"
namespace ARDOUR {
#include "i18n.h"
Amp::Amp(Session& s, IO& io)
using namespace ARDOUR;
Amp::Amp(Session& s, boost::shared_ptr<MuteMaster> mm)
: Processor(s, "Amp")
, _io(io)
, _mute(false)
, _apply_gain(true)
, _apply_gain_automation(false)
, _current_gain(1.0)
, _desired_gain(1.0)
, _mute_master (mm)
{
boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(GainAutomation)));
_gain_control = boost::shared_ptr<GainControl>( new GainControl(X_("gaincontrol"), s, this, Evoral::Parameter(GainAutomation), gl ));
add_control(_gain_control);
}
bool
@@ -59,64 +66,92 @@ Amp::configure_io (ChanCount in, ChanCount out)
void
Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
gain_t* gab = _session.gain_automation_buffer();
gain_t mute_gain;
if (_mute && !bufs.is_silent()) {
Amp::apply_gain (bufs, nframes, _current_mute_gain, _desired_mute_gain, false);
if (_desired_mute_gain == 0.0f) {
bufs.is_silent(true);
}
if (_mute_master) {
mute_gain = _mute_master->mute_gain_at (MuteMaster::PreFader);
} else {
mute_gain = 1.0;
}
if (_apply_gain) {
if (_apply_gain_automation) {
if (_io.phase_invert()) {
gain_t* gab = _session.gain_automation_buffer ();
if (mute_gain == 0.0) {
/* absolute mute */
if (_current_gain == 0.0) {
/* already silent */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
i->clear ();
}
} else {
/* cut to silence */
Amp::apply_gain (bufs, nframes, _current_gain, 0.0);
_current_gain = 0.0;
}
} else if (mute_gain != 1.0) {
/* mute dimming */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
for (nframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] *= -gab[nx];
sp[nx] *= gab[nx] * mute_gain;
}
}
_current_gain = gab[nframes-1] * mute_gain;
} else {
/* no mute */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
for (nframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] *= gab[nx];
}
}
_current_gain = gab[nframes-1];
}
} else { /* manual (scalar) gain */
gain_t dg = _gain_control->user_float() * mute_gain;
if (_current_gain != _desired_gain) {
if (_current_gain != dg) {
Amp::apply_gain (bufs, nframes, _current_gain, _desired_gain, _io.phase_invert());
_current_gain = _desired_gain;
Amp::apply_gain (bufs, nframes, _current_gain, dg);
_current_gain = dg;
} else if (_current_gain != 0.0f && (_io.phase_invert() || _current_gain != 1.0f)) {
} else if ((_current_gain != 0.0f) && (_current_gain != 1.0f)) {
/* no need to interpolate current gain value,
but its non-unity, so apply it. if the gain
is zero, do nothing because we'll ship silence
below.
/* gain has not changed, but its non-unity, so apply it unless
its zero.
*/
gain_t this_gain;
if (_io.phase_invert()) {
this_gain = -_current_gain;
} else {
this_gain = _current_gain;
}
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
apply_gain_to_buffer(sp, nframes, this_gain);
apply_gain_to_buffer(sp, nframes, _current_gain);
}
} else if (_current_gain == 0.0f) {
/* silence! */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
i->clear();
}
@@ -125,30 +160,19 @@ Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame,
}
}
/** Apply a declicked gain to the audio buffers of @a bufs */
void
Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
gain_t initial, gain_t target, bool invert_polarity)
Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target)
{
if (nframes == 0) {
return;
}
if (bufs.count().n_audio() == 0) {
/** Apply a (potentially) declicked gain to the audio buffers of @a bufs
*/
if (nframes == 0 || bufs.count().n_audio() == 0) {
return;
}
// if we don't need to declick, defer to apply_simple_gain
if (initial == target) {
if (target == 0.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
memset (i->data(), 0, sizeof (Sample) * nframes);
}
} else if (target != 1.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
apply_gain_to_buffer (i->data(), nframes, target);
}
}
apply_simple_gain (bufs, nframes, target);
return;
}
@@ -156,7 +180,7 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
gain_t delta;
double fractional_shift = -1.0/declick;
double fractional_pos;
gain_t polscale = invert_polarity ? -1.0f : 1.0f;
gain_t polscale = 1.0f;
if (target < initial) {
/* fade out: remove more and more of delta from initial */
@@ -180,10 +204,6 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
if (declick != nframes) {
if (invert_polarity) {
target = -target;
}
if (target == 0.0) {
memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
} else if (target != 1.0) {
@@ -196,6 +216,62 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
void
Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target)
{
if (target == 0.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
memset (i->data(), 0, sizeof (Sample) * nframes);
}
} else if (target != 1.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
apply_gain_to_buffer (i->data(), nframes, target);
}
}
}
void
Amp::inc_gain (gain_t factor, void *src)
{
float desired_gain = _gain_control->user_float();
if (desired_gain == 0.0f) {
set_gain (0.000001f + (0.000001f * factor), src);
} else {
set_gain (desired_gain + (desired_gain * factor), src);
}
}
void
Amp::set_gain (gain_t val, void *src)
{
// max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
if (val > 1.99526231f) {
val = 1.99526231f;
}
//cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
if (src != _gain_control.get()) {
_gain_control->set_value(val);
// bit twisty, this will come back and call us again
// (this keeps control in sync with reality)
return;
}
{
// Glib::Mutex::Lock dm (declick_lock);
_gain_control->set_float(val, false);
}
if (_session.transport_stopped()) {
// _gain = val;
}
/*
if (_session.transport_stopped() && src != 0 && src != this && _gain_control->automation_write()) {
_gain_control->list()->add (_session.transport_frame(), val);
}
*/
_session.set_dirty();
}
XMLNode&
@@ -206,4 +282,33 @@ Amp::state (bool full_state)
return node;
}
} // namespace ARDOUR
void
Amp::GainControl::set_value (float val)
{
// max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
if (val > 1.99526231f)
val = 1.99526231f;
_amp->set_gain (val, this);
AutomationControl::set_value(val);
}
float
Amp::GainControl::get_value (void) const
{
return AutomationControl::get_value();
}
void
Amp::setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && _session.transport_rolling() && _gain_control->automation_playback()) {
_apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _session.gain_automation_buffer(), nframes);
} else {
_apply_gain_automation = false;
}
}

View File

@@ -22,19 +22,20 @@
#include "ardour/types.h"
#include "ardour/chan_count.h"
#include "ardour/processor.h"
#include "ardour/automation_control.h"
namespace ARDOUR {
class BufferSet;
class IO;
class MuteMaster;
/** Applies a declick operation to all audio inputs, passing the same number of
* audio outputs, and passing through any other types unchanged.
*/
class Amp : public Processor {
public:
Amp(Session& s, IO& io);
Amp(Session& s, boost::shared_ptr<MuteMaster> m);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
@@ -44,38 +45,54 @@ public:
bool apply_gain() const { return _apply_gain; }
void apply_gain(bool yn) { _apply_gain = yn; }
void setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool apply_gain_automation() const { return _apply_gain_automation; }
void apply_gain_automation(bool yn) { _apply_gain_automation = yn; }
void muute(bool yn) { _mute = yn; }
void set_gain(float current, float desired) {
_current_gain = current;
_desired_gain = desired;
}
void apply_mute(bool yn, float current=1.0, float desired=0.0) {
_mute = yn;
_current_mute_gain = current;
_desired_mute_gain = desired;
}
XMLNode& state (bool full);
static void apply_gain (BufferSet& bufs, nframes_t nframes,
gain_t initial, gain_t target, bool invert_polarity);
static void apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target);
static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target);
gain_t gain () const { return _gain_control->user_float(); }
virtual void set_gain (gain_t g, void *src);
void inc_gain (gain_t delta, void *src);
static void update_meters();
/* automation */
struct GainControl : public AutomationControl {
GainControl (std::string name, Session& session, Amp* a, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
: AutomationControl (session, param, al, name )
, _amp (a)
{}
void set_value (float val);
float get_value (void) const;
Amp* _amp;
};
boost::shared_ptr<GainControl> gain_control() {
return _gain_control;
}
boost::shared_ptr<const GainControl> gain_control() const {
return _gain_control;
}
private:
IO& _io;
bool _mute;
bool _apply_gain;
bool _apply_gain_automation;
float _current_gain;
float _desired_gain;
float _current_mute_gain;
float _desired_mute_gain;
bool _denormal_protection;
bool _apply_gain;
bool _apply_gain_automation;
float _current_gain;
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<MuteMaster> _mute_master;
};

View File

@@ -58,7 +58,7 @@ public:
virtual void add_control(boost::shared_ptr<Evoral::Control>);
virtual void automation_snapshot(nframes_t now, bool force);
virtual void transport_stopped(nframes_t now);
virtual void transport_stopped (sframes_t now);
virtual std::string describe_parameter(Evoral::Parameter param);

View File

@@ -27,7 +27,7 @@ namespace ARDOUR {
class ClickIO : public IO
{
public:
ClickIO (Session& s, const std::string& name) : IO (s, name) {}
ClickIO (Session& s, const std::string& name) : IO (s, name, IO::Output) {}
~ClickIO() {}
protected:

View File

@@ -28,48 +28,91 @@ namespace ARDOUR {
class BufferSet;
class IO;
class MuteMaster;
class Panner;
class Delivery : public IOProcessor {
public:
enum Role {
Send = 0x1,
Solo = 0x2,
Insert = 0x1,
Send = 0x2,
Listen = 0x4,
Main = 0x8
};
Delivery (Session& s, IO* io, const std::string& name, Role);
Delivery (Session& s, const std::string& name, Role);
Delivery (Session&, const XMLNode&);
Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
bool set_name (const std::string& name);
bool visible() const;
Role role() const { return _role; }
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void set_metering (bool yn);
bool muted_by_self() const { return _muted_by_self; }
bool muted_by_others() const { return _muted_by_others; }
/* supplemental method use with MIDI */
void set_self_mute (bool);
void set_nonself_mute (bool);
sigc::signal<void> SelfMuteChange;
sigc::signal<void> OtherMuteChange;
void flush (nframes_t nframes);
void no_outs_cuz_we_no_monitor(bool);
void mod_solo_level (int32_t);
uint32_t solo_level() const { return _solo_level; }
bool soloed () const { return (bool) _solo_level; }
bool solo_isolated() const { return _solo_isolated; }
void set_solo_isolated (bool);
void cycle_start (nframes_t);
void increment_output_offset (nframes_t);
void transport_stopped (sframes_t frame);
BufferSet& output_buffers() { return *_output_buffers; }
sigc::signal<void> MuteChange;
static sigc::signal<void,nframes_t> CycleStart;
XMLNode& state (bool full);
int set_state (const XMLNode&);
private:
Role _role;
bool _metering;
bool _muted_by_self;
bool _muted_by_others;
/* Panning */
static int disable_panners (void);
static int reset_panners (void);
boost::shared_ptr<Panner> panner() const { return _panner; }
void reset_panner ();
void defer_pan_reset ();
void allow_pan_reset ();
uint32_t pans_required() const { return _configured_input.n_audio(); }
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
protected:
Role _role;
BufferSet* _output_buffers;
gain_t _current_gain;
nframes_t _output_offset;
bool _no_outs_cuz_we_no_monitor;
uint32_t _solo_level;
bool _solo_isolated;
boost::shared_ptr<MuteMaster> _mute_master;
bool no_panner_reset;
boost::shared_ptr<Panner> _panner;
static bool panners_legal;
static sigc::signal<int> PannersLegal;
int panners_became_legal ();
sigc::connection panner_legal_c;
void output_changed (IOChange, void*);
gain_t target_gain ();
};

View File

@@ -55,134 +55,83 @@ class AudioPort;
class BufferSet;
class Bundle;
class MidiPort;
class Panner;
class PeakMeter;
class Port;
class Processor;
class Session;
class UserBundle;
/** A collection of input and output ports with connections.
/** A collection of ports (all input or all output) with connections.
*
* An IO can contain ports of varying types, making routes/inserts/etc with
* varied combinations of types (eg MIDI and audio) possible.
*/
class IO : public SessionObject, public AutomatableControls, public Latent
class IO : public SessionObject, public Latent
{
public:
static const std::string state_node_name;
IO (Session&, const std::string& name, DataType default_type = DataType::AUDIO);
enum Direction {
Input,
Output
};
IO (Session&, const std::string& name, Direction, DataType default_type = DataType::AUDIO);
IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~IO();
bool active() const { return _active; }
void set_active (bool yn);
Direction direction() const { return _direction; }
DataType default_type() const { return _default_type; }
void set_default_type(DataType t) { _default_type = t; }
bool active() const { return _active; }
void set_active(bool yn) { _active = yn; }
bool set_name (const std::string& str);
virtual void silence (nframes_t);
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
void deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
int ensure_io (ChanCount cnt, bool clear, void *src);
BufferSet& output_buffers() { return *_output_buffers; }
int connect_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
gain_t gain () const { return _gain_control->user_float(); }
virtual gain_t effective_gain () const;
BundleList bundles_connected ();
boost::shared_ptr<Bundle> bundle () { return _bundle; }
void set_denormal_protection (bool yn, void *src);
bool denormal_protection() const { return _denormal_protection; }
void set_phase_invert (bool yn, void *src);
bool phase_invert() const { return _phase_invert; }
void reset_panner ();
boost::shared_ptr<Amp> amp() const { return _amp; }
PeakMeter& peak_meter() { return *_meter.get(); }
const PeakMeter& peak_meter() const { return *_meter.get(); }
boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
boost::shared_ptr<Panner> panner() const { return _panner; }
int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
int connect_input_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_input_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
int connect_output_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_output_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
BundleList bundles_connected_to_inputs ();
BundleList bundles_connected_to_outputs ();
boost::shared_ptr<Bundle> bundle_for_inputs () { return _bundle_for_inputs; }
boost::shared_ptr<Bundle> bundle_for_outputs () { return _bundle_for_outputs; }
int add_input_port (std::string source, void *src, DataType type = DataType::NIL);
int add_output_port (std::string destination, void *src, DataType type = DataType::NIL);
int remove_input_port (Port *, void *src);
int remove_output_port (Port *, void *src);
int set_input (Port *, void *src);
int connect_input (Port *our_port, std::string other_port, void *src);
int connect_output (Port *our_port, std::string other_port, void *src);
int disconnect_input (Port *our_port, std::string other_port, void *src);
int disconnect_output (Port *our_port, std::string other_port, void *src);
int disconnect_inputs (void *src);
int disconnect_outputs (void *src);
int add_port (std::string connection, void *src, DataType type = DataType::NIL);
int remove_port (Port *, void *src);
int connect (Port *our_port, std::string other_port, void *src);
int disconnect (Port *our_port, std::string other_port, void *src);
int disconnect (void *src);
bool connected_to (boost::shared_ptr<const IO>) const;
nframes_t signal_latency() const { return _own_latency; }
nframes_t output_latency() const;
nframes_t input_latency() const;
nframes_t latency() const;
void set_port_latency (nframes_t);
void update_port_total_latencies ();
const PortSet& inputs() const { return _inputs; }
const PortSet& outputs() const { return _outputs; }
PortSet& ports() { return _ports; }
const PortSet& ports() const { return _ports; }
Port *output (uint32_t n) const {
if (n < _outputs.num_ports()) {
return _outputs.port(n);
Port *nth (uint32_t n) const {
if (n < _ports.num_ports()) {
return _ports.port(n);
} else {
return 0;
}
}
Port *input (uint32_t n) const {
if (n < _inputs.num_ports()) {
return _inputs.port(n);
} else {
return 0;
}
}
AudioPort* audio(uint32_t n) const;
MidiPort* midi(uint32_t n) const;
AudioPort* audio_input(uint32_t n) const;
AudioPort* audio_output(uint32_t n) const;
MidiPort* midi_input(uint32_t n) const;
MidiPort* midi_output(uint32_t n) const;
const ChanCount& n_ports () const { return _ports.count(); }
const ChanCount& n_inputs () const { return _inputs.count(); }
const ChanCount& n_outputs () const { return _outputs.count(); }
void attach_buffers(ChanCount ignored);
sigc::signal<void> active_changed;
sigc::signal<void,IOChange,void*> input_changed;
sigc::signal<void,IOChange,void*> output_changed;
sigc::signal<void,IOChange,void*> changed;
virtual XMLNode& state (bool full);
XMLNode& get_state (void);
@@ -192,130 +141,45 @@ class IO : public SessionObject, public AutomatableControls, public Latent
static int enable_connecting (void);
static int disable_ports (void);
static int enable_ports (void);
static int disable_panners (void);
static int reset_panners (void);
static sigc::signal<int> PortsLegal;
static sigc::signal<int> PannersLegal;
static sigc::signal<int> ConnectingLegal;
/// raised when the number of input or output ports changes
static sigc::signal<void,ChanCount> PortCountChanged;
static sigc::signal<void,nframes_t> CycleStart;
static sigc::signal<void,ChanCount> PortCountChanged; // emitted when the number of ports changes
static void update_meters();
static std::string name_from_state (const XMLNode&);
static void set_name_in_state (XMLNode&, const std::string&);
private:
static sigc::signal<void> Meter;
static Glib::StaticMutex m_meter_signal_lock;
sigc::connection m_meter_connection;
public:
/* automation */
struct GainControl : public AutomationControl {
GainControl (std::string name, IO* i, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
: AutomationControl (i->_session, param, al, name )
, _io (i)
{}
void set_value (float val);
float get_value (void) const;
IO* _io;
};
boost::shared_ptr<GainControl> gain_control() {
return _gain_control;
}
boost::shared_ptr<const GainControl> gain_control() const {
return _gain_control;
}
void clear_automation ();
void set_parameter_automation_state (Evoral::Parameter, AutoState);
virtual void transport_stopped (nframes_t now);
virtual void automation_snapshot (nframes_t now, bool force);
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
void defer_pan_reset ();
void allow_pan_reset ();
/* the session calls this for master outs before
anyone else. controls outs too, at some point.
/* we have to defer/order port connection. this is how we do it.
*/
static sigc::signal<int> ConnectingLegal;
static bool connecting_legal;
XMLNode *pending_state_node;
int ports_became_legal ();
/* three utility functions - this just seems to be simplest place to put them */
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset);
void process_input (boost::shared_ptr<Processor>, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_ports (const std::string& str);
private:
mutable Glib::Mutex io_lock;
protected:
BufferSet* _output_buffers; //< Set directly to output port buffers
bool _active;
gain_t _gain;
Glib::Mutex declick_lock;
PortSet _outputs;
PortSet _inputs;
bool no_panner_reset;
bool _phase_invert;
bool _denormal_protection;
XMLNode* deferred_state;
DataType _default_type;
nframes_t _output_offset;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<Panner> _panner;
virtual void prepare_inputs (nframes_t nframes);
virtual void flush_outputs (nframes_t nframes);
virtual void set_deferred_state() {}
virtual uint32_t pans_required() const
{ return _inputs.count().n_audio(); }
boost::shared_ptr<GainControl> _gain_control;
virtual void set_gain (gain_t g, void *src);
void inc_gain (gain_t delta, void *src);
virtual int load_automation (std::string path);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_inputs (const std::string& str);
int set_outputs (const std::string& str);
void increment_output_offset (nframes_t);
void cycle_start (nframes_t);
static bool connecting_legal;
static bool ports_legal;
PortSet _ports;
Direction _direction;
DataType _default_type;
bool _active;
private:
static bool panners_legal;
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes);
int connecting_became_legal ();
int panners_became_legal ();
sigc::connection connection_legal_c;
sigc::connection port_legal_c;
sigc::connection panner_legal_c;
boost::shared_ptr<Bundle> _bundle_for_inputs; ///< a bundle representing our inputs
boost::shared_ptr<Bundle> _bundle_for_outputs; ///< a bundle representing our outputs
boost::shared_ptr<Bundle> _bundle; ///< a bundle representing our ports
struct UserBundleInfo {
UserBundleInfo (IO*, boost::shared_ptr<UserBundle> b);
@@ -324,45 +188,31 @@ class IO : public SessionObject, public AutomatableControls, public Latent
sigc::connection changed;
};
std::vector<UserBundleInfo> _bundles_connected_to_outputs; ///< user bundles connected to our outputs
std::vector<UserBundleInfo> _bundles_connected_to_inputs; ///< user bundles connected to our inputs
std::vector<UserBundleInfo> _bundles_connected; ///< user bundles connected to our ports
static int parse_io_string (const std::string&, std::vector<std::string>& chns);
static int parse_gain_string (const std::string&, std::vector<std::string>& chns);
int set_sources (std::vector<std::string>&, void *src, bool add);
int set_destinations (std::vector<std::string>&, void *src, bool add);
int ensure_ports (ChanCount, bool clear, bool lockit, void *src);
int ensure_inputs (ChanCount, bool clear, bool lockit, void *src);
int ensure_outputs (ChanCount, bool clear, bool lockit, void *src);
void check_bundles_connected_to_inputs ();
void check_bundles_connected_to_outputs ();
void check_bundles_connected ();
void check_bundles (std::vector<UserBundleInfo>&, const PortSet&);
void bundle_changed (Bundle::Change);
int get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out,
boost::shared_ptr<Bundle>& ic, boost::shared_ptr<Bundle>& oc);
int get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr<Bundle>& c);
int create_ports (const XMLNode&);
int make_connections (const XMLNode&);
boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name, const std::string &default_name, const std::string &connection_type_name);
virtual void setup_peak_meters ();
void meter ();
boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name);
bool ensure_inputs_locked (ChanCount, bool clear, void *src);
bool ensure_outputs_locked (ChanCount, bool clear, void *src);
bool ensure_ports_locked (ChanCount, bool clear, void *src);
std::string build_legal_port_name (DataType type, bool for_input);
int32_t find_input_port_hole (const char* base);
int32_t find_output_port_hole (const char* base);
std::string build_legal_port_name (DataType type);
int32_t find_port_hole (const char* base);
void setup_bundles_for_inputs_and_outputs ();
void setup_bundle_for_inputs ();
void setup_bundle_for_outputs ();
void setup_bundles ();
std::string bundle_channel_name (uint32_t, uint32_t) const;
};

View File

@@ -38,15 +38,16 @@ namespace ARDOUR {
class Session;
class IO;
/** A mixer strip element (Processor) with Jack ports (IO).
/** A mixer strip element (Processor) with 1 or 2 IO elements.
*/
class IOProcessor : public Processor
{
public:
IOProcessor (Session&, const std::string& proc_name, const std::string io_name="",
ARDOUR::DataType default_type = DataType::AUDIO);
IOProcessor (Session&, IO* io, const std::string& proc_name,
IOProcessor (Session&, bool with_input, bool with_output,
const std::string& proc_name, const std::string io_name="",
ARDOUR::DataType default_type = DataType::AUDIO);
IOProcessor (Session&, boost::shared_ptr<IO> input, boost::shared_ptr<IO> output,
const std::string& proc_name, ARDOUR::DataType default_type = DataType::AUDIO);
virtual ~IOProcessor ();
bool set_name (const std::string& str);
@@ -56,13 +57,14 @@ class IOProcessor : public Processor
virtual ChanCount natural_output_streams() const;
virtual ChanCount natural_input_streams () const;
boost::shared_ptr<IO> io() { return _io; }
boost::shared_ptr<const IO> io() const { return _io; }
void set_io (boost::shared_ptr<IO>);
boost::shared_ptr<IO> input() { return _input; }
boost::shared_ptr<const IO> input() const { return _input; }
boost::shared_ptr<IO> output() { return _output; }
boost::shared_ptr<const IO> output() const { return _output; }
void set_input (boost::shared_ptr<IO>);
void set_output (boost::shared_ptr<IO>);
virtual void automation_snapshot (nframes_t now, bool force);
virtual void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
void silence (nframes_t nframes);
sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged;
@@ -72,12 +74,14 @@ class IOProcessor : public Processor
int set_state (const XMLNode&);
protected:
boost::shared_ptr<IO> _io;
boost::shared_ptr<IO> _input;
boost::shared_ptr<IO> _output;
private:
/* disallow copy construction */
IOProcessor (const IOProcessor&);
bool _own_io;
bool _own_input;
bool _own_output;
};

View File

@@ -20,6 +20,7 @@
#define __ardour_meter_h__
#include <vector>
#include <sigc++/slot.h>
#include "ardour/types.h"
#include "ardour/processor.h"
#include "pbd/fastlog.h"
@@ -30,6 +31,20 @@ class BufferSet;
class ChanCount;
class Session;
class Metering {
public:
static void update_meters ();
static sigc::signal<void> Meter;
static sigc::connection connect (sigc::slot<void> the_slot);
static void disconnect (sigc::connection& c);
private:
/* this object is not meant to be instantiated */
virtual void foo() = 0;
static Glib::StaticMutex m_meter_signal_lock;
};
/** Meters peaks on the input and stores them for access.
*/
@@ -37,6 +52,8 @@ class PeakMeter : public Processor {
public:
PeakMeter(Session& s) : Processor(s, "Meter") {}
void meter();
void reset ();
void reset_max ();
@@ -66,7 +83,6 @@ public:
private:
friend class IO;
void meter();
std::vector<float> _peak_power;
std::vector<float> _visible_peak_power;

View File

@@ -0,0 +1,77 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_mute_master_h__
#define __ardour_mute_master_h__
#include "evoral/Parameter.hpp"
#include "ardour/automation_control.h"
#include "ardour/automation_list.h"
namespace ARDOUR {
class Session;
class MuteMaster : public AutomationControl
{
public:
enum MutePoint {
PreFader = 0x1,
PostFader = 0x2,
Listen = 0x4,
Main = 0x8
};
MuteMaster (Session& s, const std::string& name);
~MuteMaster() {}
bool muted_pre_fader() const { return _mute_point & PreFader; }
bool muted_post_fader() const { return _mute_point & PostFader; }
bool muted_listen() const { return _mute_point & Listen; }
bool muted_main () const { return _mute_point & Main; }
bool muted_at (MutePoint mp) const { return _mute_point & mp; }
bool muted() const { return _mute_point != MutePoint (0) && get_value() != 0.0; }
gain_t mute_gain_at (MutePoint) const;
void clear_mute ();
void mute_at (MutePoint);
void unmute_at (MutePoint);
void mute (bool yn);
/* Controllable interface */
void set_value (float); /* note: float is used as a bitfield of MutePoints */
float get_value () const;
sigc::signal<void> MutePointChanged;
XMLNode& get_state();
int set_state(const XMLNode& node);
private:
AutomationList* _automation;
MutePoint _mute_point;
};
} // namespace ARDOUR
#endif /*__ardour_mute_master_h__ */

View File

@@ -183,7 +183,7 @@ class Multi2dPanner : public StreamPanner
};
class Panner : public Processor
class Panner : public SessionObject, public AutomatableControls
{
public:
struct Output {
@@ -204,18 +204,16 @@ class Panner : public Processor
void clear_panners ();
bool empty() const { return _streampanners.empty(); }
/// The fundamental Panner function
void set_automation_state (AutoState);
AutoState automation_state() const;
void set_automation_style (AutoStyle);
AutoStyle automation_style() const;
bool touching() const;
bool is_in_place () const { return false; }
bool is_out_of_place () const { return true; }
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; };
void run_out_of_place(BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes);
/// The fundamental Panner function
void run (BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes);
//void* get_inline_gui() const = 0;
//void* get_full_gui() const = 0;

View File

@@ -34,25 +34,28 @@ class XMLNode;
namespace ARDOUR {
class Session;
class IO;
class Delivery;
class MuteMaster;
/** Port inserts: send output to a Jack port, pick up input at a Jack port
*/
class PortInsert : public IOProcessor
{
public:
PortInsert (Session&);
PortInsert (Session&, const XMLNode&);
PortInsert (Session&, boost::shared_ptr<MuteMaster> mm);
PortInsert (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
~PortInsert ();
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode&);
void init ();
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
nframes_t signal_latency() const;
bool set_name (const std::string& name);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
@@ -62,6 +65,8 @@ class PortInsert : public IOProcessor
private:
/* disallow copy construction */
PortInsert (const PortInsert&);
boost::shared_ptr<Delivery> _out;
uint32_t bitslot;
};

View File

@@ -53,24 +53,26 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
virtual ~Processor() { }
/** Configuration of a processor on a bus
* (i.e. how to apply to a BufferSet)
*/
struct Mapping {
ChanCount in;
ChanCount out;
};
virtual bool visible() const { return true; }
bool active () const { return _active; }
/* we keep loose tabs on the "placement" of a Processor. Ultimately,
they are all executed as a single list, but there are some
semantics that require knowing whether a Processor is before
or after the fader, or panner etc. See Route::reorder_processors()
to see where this gets set.
*/
Placement placement() const { return _placement; }
void set_placement (Placement p) { _placement = p; }
bool get_next_ab_is_active () const { return _next_ab_is_active; }
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
virtual nframes_t signal_latency() const { return 0; }
virtual void transport_stopped (nframes_t frame) {}
virtual void transport_stopped (sframes_t frame) {}
virtual void set_block_size (nframes_t nframes) {}
@@ -127,7 +129,7 @@ protected:
ChanCount _configured_input;
ChanCount _configured_output;
void* _gui; /* generic, we don't know or care what this is */
Mapping _mapping;
Placement _placement;
};
} // namespace ARDOUR

View File

@@ -84,6 +84,7 @@ CONFIG_VARIABLE (bool, all_safe, "all-safe", false)
CONFIG_VARIABLE (bool, show_solo_mutes, "show-solo-mutes", false)
CONFIG_VARIABLE (bool, solo_mute_override, "solo-mute-override", false)
CONFIG_VARIABLE (bool, tape_machine_mode, "tape-machine-mode", false)
CONFIG_VARIABLE (gain_t, solo_mute_gain, "solo_mute-gain", 0.0)
/* click */

View File

@@ -32,6 +32,9 @@
namespace ARDOUR {
class Amp;
class PeakMeter;
class Return : public IOProcessor
{
public:
@@ -43,9 +46,12 @@ public:
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void activate() {}
void deactivate () {}
boost::shared_ptr<Amp> amp() const { return _amp; }
boost::shared_ptr<PeakMeter> meter() const { return _meter; }
bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; }
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
@@ -55,14 +61,22 @@ public:
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
static uint32_t how_many_sends();
static uint32_t how_many_returns();
static void make_unique (XMLNode &, Session &);
protected:
bool _metering;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
private:
/* disallow copy construction */
Return (const Return&);
uint32_t _bitslot;
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
};
} // namespace ARDOUR

View File

@@ -41,24 +41,19 @@
#include "ardour/ardour.h"
#include "ardour/io.h"
#include "ardour/types.h"
#include "ardour/mute_master.h"
namespace ARDOUR {
class Amp;
class Delivery;
class IOProcessor;
class Panner;
class Processor;
class RouteGroup;
class Send;
enum mute_type {
PRE_FADER = 0x1,
POST_FADER = 0x2,
CONTROL_OUTS = 0x4,
MAIN_OUTS = 0x8
};
class Route : public IO
class Route : public SessionObject, public AutomatableControls
{
public:
@@ -75,6 +70,16 @@ class Route : public IO
Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~Route();
boost::shared_ptr<IO> input() const { return _input; }
boost::shared_ptr<IO> output() const { return _output; }
ChanCount n_inputs() const { return _input->n_ports(); }
ChanCount n_outputs() const { return _output->n_ports(); }
bool active() const { return _active; }
void set_active (bool yn);
static std::string ensure_track_or_route_name(std::string, Session &);
std::string comment() { return _comment; }
@@ -102,6 +107,7 @@ class Route : public IO
virtual void toggle_monitor_input ();
virtual bool can_record() { return false; }
virtual void set_record_enable (bool yn, void *src) {}
virtual bool record_enabled() const { return false; }
virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
@@ -110,38 +116,44 @@ class Route : public IO
/* end of vfunc-based API */
void shift (nframes64_t, nframes64_t);
/* override IO::set_gain() to provide group control */
void set_gain (gain_t val, void *src);
void inc_gain (gain_t delta, void *src);
void set_mute (bool yn, void* src);
bool muted () const;
void set_solo (bool yn, void *src);
bool soloed() const { return _soloed; }
bool soloed() const;
void set_solo_safe (bool yn, void *src);
bool solo_safe() const { return _solo_safe; }
void set_solo_isolated (bool yn, void *src);
bool solo_isolated() const;
void set_mute (bool yn, void *src);
bool muted() const { return _muted; }
bool solo_muted() const { return desired_solo_gain == 0.0; }
void set_phase_invert (bool yn, void* src);
bool phase_invert() const;
void set_mute_config (mute_type, bool, void *src);
bool get_mute_config (mute_type);
void set_denormal_protection (bool yn, void* src);
bool denormal_protection() const;
void set_edit_group (RouteGroup *, void *);
void drop_edit_group (void *);
RouteGroup *edit_group () { return _edit_group; }
RouteGroup *edit_group () const { return _edit_group; }
void set_mix_group (RouteGroup *, void *);
void drop_mix_group (void *);
RouteGroup *mix_group () { return _mix_group; }
RouteGroup *mix_group () const { return _mix_group; }
virtual void set_meter_point (MeterPoint, void *src);
MeterPoint meter_point() const { return _meter_point; }
void meter ();
/* Processors */
boost::shared_ptr<Amp> amp() const { return _amp; }
PeakMeter& peak_meter() { return *_meter.get(); }
const PeakMeter& peak_meter() const { return *_meter.get(); }
boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
void flush_processors ();
void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) {
@@ -180,7 +192,7 @@ class Route : public IO
boost::shared_ptr<Delivery> control_outs() const { return _control_outs; }
boost::shared_ptr<Delivery> main_outs() const { return _main_outs; }
boost::shared_ptr<Send> send_for (boost::shared_ptr<const IO> target) const;
/** A record of the stream configuration at some point in the processor list.
@@ -213,8 +225,10 @@ class Route : public IO
void set_user_latency (nframes_t);
nframes_t initial_delay() const { return _initial_delay; }
sigc::signal<void> active_changed;
sigc::signal<void,void*> solo_changed;
sigc::signal<void,void*> solo_safe_changed;
sigc::signal<void,void*> solo_isolated_changed;
sigc::signal<void,void*> comment_changed;
sigc::signal<void,void*> mute_changed;
sigc::signal<void,void*> pre_fader_changed;
@@ -240,8 +254,8 @@ class Route : public IO
virtual XMLNode& get_template();
XMLNode& get_processor_state ();
int set_processor_state (const XMLNode&);
virtual void set_processor_state (const XMLNode&);
int save_as_template (const std::string& path, const std::string& name);
sigc::signal<void,void*> SelectedChanged;
@@ -252,28 +266,38 @@ class Route : public IO
bool feeds (boost::shared_ptr<IO>);
std::set<boost::shared_ptr<Route> > fed_by;
struct ToggleControllable : public PBD::Controllable {
enum ToggleType {
MuteControl = 0,
SoloControl
};
ToggleControllable (std::string name, Route&, ToggleType);
void set_value (float);
float get_value (void) const;
/* Controls (not all directly owned by the Route */
Route& route;
ToggleType type;
boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
struct SoloControllable : public AutomationControl {
SoloControllable (std::string name, Route&);
void set_value (float);
float get_value (void) const;
Route& route;
};
boost::shared_ptr<PBD::Controllable> solo_control() {
boost::shared_ptr<AutomationControl> solo_control() const {
return _solo_control;
}
boost::shared_ptr<PBD::Controllable> mute_control() {
return _mute_control;
boost::shared_ptr<AutomationControl> mute_control() const {
return _mute_master;
}
boost::shared_ptr<MuteMaster> mute_master() const {
return _mute_master;
}
/* Route doesn't own these items, but sub-objects that it does own have them
and to make UI code a bit simpler, we provide direct access to them
here.
*/
boost::shared_ptr<Panner> panner() const;
boost::shared_ptr<AutomationControl> gain_control() const;
void automation_snapshot (nframes_t now, bool force=false);
void protect_automation ();
@@ -288,10 +312,11 @@ class Route : public IO
friend class Session;
void catch_up_on_solo_mute_override ();
void set_solo_mute (bool yn);
void mod_solo_level (int32_t);
void set_block_size (nframes_t nframes);
bool has_external_redirects() const;
void curve_reallocate ();
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
protected:
nframes_t check_initial_delay (nframes_t, nframes_t&);
@@ -303,44 +328,38 @@ class Route : public IO
sframes_t start_frame, sframes_t end_frame,
nframes_t nframes, bool with_processors, int declick);
Flag _flags;
int _pending_declick;
MeterPoint _meter_point;
boost::shared_ptr<IO> _input;
boost::shared_ptr<IO> _output;
gain_t solo_gain;
gain_t mute_gain;
gain_t desired_solo_gain;
gain_t desired_mute_gain;
bool _active;
nframes_t _initial_delay;
nframes_t _roll_delay;
ProcessorList _processors;
mutable Glib::RWLock _processor_lock;
boost::shared_ptr<Delivery> _main_outs;
boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points
RouteGroup *_edit_group;
RouteGroup *_mix_group;
std::string _comment;
bool _have_internal_generator;
Flag _flags;
int _pending_declick;
MeterPoint _meter_point;
uint32_t _phase_invert;
bool _denormal_protection;
boost::shared_ptr<ToggleControllable> _solo_control;
boost::shared_ptr<ToggleControllable> _mute_control;
/* tight cache-line access here is more important than sheer speed of access.
keep these after things that should be aligned
*/
bool _muted : 1;
bool _soloed : 1;
bool _solo_safe : 1;
bool _recordable : 1;
bool _mute_affects_pre_fader : 1;
bool _mute_affects_post_fader : 1;
bool _mute_affects_control_outs : 1;
bool _mute_affects_main_outs : 1;
bool _silent : 1;
bool _declickable : 1;
boost::shared_ptr<SoloControllable> _solo_control;
boost::shared_ptr<MuteMaster> _mute_master;
RouteGroup* _edit_group;
RouteGroup* _mix_group;
std::string _comment;
bool _have_internal_generator;
bool _solo_safe;
DataType _default_type;
protected:
virtual XMLNode& state(bool);
@@ -358,13 +377,14 @@ class Route : public IO
uint32_t pans_required() const;
ChanCount n_process_buffers ();
void setup_peak_meters ();
virtual int _set_state (const XMLNode&, bool call_base);
virtual void _set_processor_states (const XMLNodeList&);
boost::shared_ptr<Delivery> add_listener (boost::shared_ptr<IO>, const std::string&);
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
sigc::connection _meter_connection;
private:
void init ();
@@ -386,8 +406,7 @@ class Route : public IO
int configure_processors (ProcessorStreams*);
int configure_processors_unlocked (ProcessorStreams*);
void set_deferred_state ();
bool add_processor_from_xml (const XMLNode&, Placement);
bool add_processor_from_xml (const XMLNode&, ProcessorList::iterator iter);

View File

@@ -23,40 +23,52 @@
#include <sigc++/signal.h>
#include <string>
#include "pbd/stateful.h"
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
#include "ardour/delivery.h"
namespace ARDOUR {
class PeakMeter;
class Amp;
class Send : public Delivery
{
public:
Send (Session&);
Send (Session&, const XMLNode&);
Send (Session&, boost::shared_ptr<MuteMaster>);
Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&);
virtual ~Send ();
uint32_t bit_slot() const { return _bitslot; }
void activate() {}
void deactivate () {}
boost::shared_ptr<Amp> amp() const { return _amp; }
boost::shared_ptr<PeakMeter> meter() const { return _meter; }
bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; }
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
uint32_t pans_required() const { return _configured_input.n_audio(); }
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
bool set_name (const std::string& str);
static uint32_t how_many_sends();
static void make_unique (XMLNode &, Session &);
protected:
bool _metering;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
private:
/* disallow copy construction */
Send (const Send&);

View File

@@ -730,8 +730,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* session-wide solo/mute/rec-enable */
bool soloing() const { return currently_soloing; }
bool soloing() const { return _non_soloed_outs_muted; }
void set_all_solo (bool);
void set_all_mute (bool);
@@ -743,8 +743,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* control/master out */
boost::shared_ptr<IO> control_out() const { return _control_out; }
boost::shared_ptr<IO> master_out() const { return _master_out; }
boost::shared_ptr<Route> control_out() const { return _control_out; }
boost::shared_ptr<Route> master_out() const { return _master_out; }
/* insert/send management */
@@ -1040,6 +1040,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
bool _have_captured;
float _meter_hold;
float _meter_falloff;
bool _non_soloed_outs_muted;
void set_worst_io_latencies ();
void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) {
@@ -1688,8 +1689,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* main outs */
uint32_t main_outs;
boost::shared_ptr<IO> _master_out;
boost::shared_ptr<IO> _control_out;
boost::shared_ptr<Route> _master_out;
boost::shared_ptr<Route> _control_out;
gain_t* _gain_automation_buffer;
pan_t** _pan_automation_buffer;

View File

@@ -160,6 +160,8 @@ AudioDiskstream::free_working_buffers()
void
AudioDiskstream::non_realtime_input_change ()
{
cerr << "AD::NRIC ... " << name() << endl;
{
Glib::Mutex::Lock lm (state_lock);
@@ -173,10 +175,10 @@ AudioDiskstream::non_realtime_input_change ()
_n_channels.set(DataType::AUDIO, c->size());
if (_io->n_inputs().n_audio() > _n_channels.n_audio()) {
add_channel_to (c, _io->n_inputs().n_audio() - _n_channels.n_audio());
} else if (_io->n_inputs().n_audio() < _n_channels.n_audio()) {
remove_channel_from (c, _n_channels.n_audio() - _io->n_inputs().n_audio());
if (_io->n_ports().n_audio() > _n_channels.n_audio()) {
add_channel_to (c, _io->n_ports().n_audio() - _n_channels.n_audio());
} else if (_io->n_ports().n_audio() < _n_channels.n_audio()) {
remove_channel_from (c, _n_channels.n_audio() - _io->n_ports().n_audio());
}
}
@@ -227,14 +229,14 @@ AudioDiskstream::get_input_sources ()
uint32_t n;
ChannelList::iterator chan;
uint32_t ni = _io->n_inputs().n_audio();
uint32_t ni = _io->n_ports().n_audio();
vector<string> connections;
for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) {
connections.clear ();
if (_io->input(n)->get_connections (connections) == 0) {
if (_io->nth (n)->get_connections (connections) == 0) {
if ((*chan)->source) {
// _source->disable_metering ();
@@ -633,7 +635,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
if (nominally_recording || rec_nframes) {
uint32_t limit = _io->n_inputs ().n_audio();
uint32_t limit = _io->n_ports ().n_audio();
/* one or more ports could already have been removed from _io, but our
channel setup hasn't yet been updated. prevent us from trying to
@@ -656,7 +658,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
for recording, and use rec_offset
*/
AudioPort* const ap = _io->audio_input(n);
AudioPort* const ap = _io->audio (n);
assert(ap);
assert(rec_nframes <= ap->get_audio_buffer(nframes).capacity());
memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (rec_nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
@@ -671,7 +673,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
goto out;
}
AudioPort* const ap = _io->audio_input(n);
AudioPort* const ap = _io->audio (n);
assert(ap);
Sample* buf = ap->get_audio_buffer(nframes).data();
@@ -1822,7 +1824,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<Chan
void
AudioDiskstream::set_record_enabled (bool yn)
{
if (!recordable() || !_session.record_enabling_legal() || _io->n_inputs().n_audio() == 0) {
if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) {
return;
}
@@ -2110,6 +2112,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n;
cerr << _name << " RWS!!!\n";
if (!recordable()) {
return;
}

View File

@@ -36,6 +36,7 @@
#include "ardour/buffer_set.h"
#include "ardour/io_processor.h"
#include "ardour/panner.h"
#include "ardour/meter.h"
#include "ardour/playlist_factory.h"
#include "ardour/plugin_insert.h"
#include "ardour/processor.h"
@@ -140,8 +141,7 @@ AudioTrack::deprecated_use_diskstream_connections ()
diskstream->deprecated_io_node = 0;
if ((prop = node.property ("gain")) != 0) {
set_gain (atof (prop->value().c_str()), this);
_gain = _gain_control->user_float();
_amp->set_gain (atof (prop->value().c_str()), this);
}
if ((prop = node.property ("input-connection")) != 0) {
@@ -160,10 +160,10 @@ AudioTrack::deprecated_use_diskstream_connections ()
}
}
connect_input_ports_to_bundle (c, this);
_input->connect_ports_to_bundle (c, this);
} else if ((prop = node.property ("inputs")) != 0) {
if (set_inputs (prop->value())) {
if (_input->set_ports (prop->value())) {
error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
return -1;
}
@@ -176,14 +176,14 @@ int
AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
{
_diskstream = ds;
_diskstream->set_io (*this);
_diskstream->set_io (*(_input.get()));
_diskstream->set_destructive (_mode == Destructive);
_diskstream->set_non_layered (_mode == NonLayered);
if (audio_diskstream()->deprecated_io_node) {
if (!connecting_legal) {
ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
if (!IO::connecting_legal) {
IO::ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
} else {
deprecated_use_diskstream_connections ();
}
@@ -193,7 +193,7 @@ AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
_diskstream->monitor_input (false);
ic_connection.disconnect();
ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
ic_connection = _input->changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
DiskstreamChanged (); /* EMIT SIGNAL */
@@ -479,8 +479,6 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
transport_frame = _session.transport_frame();
prepare_inputs (nframes);
if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
/* need to do this so that the diskstream sets its
@@ -501,7 +499,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* special condition applies */
if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes);
_input->process_input (_meter, start_frame, end_frame, nframes);
}
if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@@ -599,6 +597,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
if (!diskstream->record_enabled() && _session.transport_rolling()) {
#ifdef XXX_MOVE_THIS_TO_AMP
Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && gain_control()->automation_playback()) {
@@ -606,6 +605,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
gain_control()->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _session.gain_automation_buffer(), nframes));
}
#endif
}
process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
@@ -759,9 +759,9 @@ AudioTrack::freeze (InterThreadInfo& itt)
new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
_freeze_record.gain = _gain;
_freeze_record.gain_automation_state = _gain_control->automation_state();
_freeze_record.pan_automation_state = _panner->automation_state();
_freeze_record.gain = _amp->gain();
_freeze_record.gain_automation_state = _amp->gain_control()->automation_state();
/* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */
region_name = new_playlist_name;
@@ -784,8 +784,8 @@ AudioTrack::freeze (InterThreadInfo& itt)
/* reset stuff that has already been accounted for in the freeze process */
set_gain (1.0, this);
_gain_control->set_automation_state (Off);
_panner->set_automation_state (Off);
_amp->gain_control()->set_automation_state (Off);
/* XXX need to use _main_outs _panner->set_automation_state (Off); */
_freeze_record.state = Frozen;
FreezeChange(); /* EMIT SIGNAL */
@@ -811,8 +811,8 @@ AudioTrack::unfreeze ()
_freeze_record.playlist.reset ();
set_gain (_freeze_record.gain, this);
_gain_control->set_automation_state (_freeze_record.gain_automation_state);
_panner->set_automation_state (_freeze_record.pan_automation_state);
_amp->gain_control()->set_automation_state (_freeze_record.gain_automation_state);
/* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */
}
_freeze_record.state = UnFrozen;

View File

@@ -33,9 +33,11 @@
#include "ardour/audioengine.h"
#include "ardour/buffer.h"
#include "ardour/delivery.h"
#include "ardour/port.h"
#include "ardour/audio_port.h"
#include "ardour/midi_port.h"
#include "ardour/meter.h"
#include "ardour/session.h"
#include "ardour/cycle_timer.h"
#include "ardour/utils.h"
@@ -358,9 +360,9 @@ AudioEngine::process_callback (nframes_t nframes)
return 0;
}
/* tell all IO objects that we're starting a new cycle */
/* tell all relevant objects that we're starting a new cycle */
IO::CycleStart (nframes);
Delivery::CycleStart (nframes);
Port::set_port_offset (0);
/* tell all Ports that we're starting a new cycle */
@@ -519,7 +521,7 @@ AudioEngine::meter_thread ()
if (g_atomic_int_get(&m_meter_exit)) {
break;
}
IO::update_meters ();
Metering::update_meters ();
}
}

View File

@@ -24,6 +24,7 @@
#include "ardour/audio_diskstream.h"
#include "ardour/audioregion.h"
#include "ardour/audioengine.h"
#include "ardour/delivery.h"
#include "ardour/route.h"
#include "ardour/session.h"
#include "ardour/auditioner.h"
@@ -57,22 +58,21 @@ Auditioner::Auditioner (Session& s)
return;
}
defer_pan_reset ();
_main_outs->defer_pan_reset ();
if (left.length()) {
add_output_port (left, this, DataType::AUDIO);
_output->add_port (left, this, DataType::AUDIO);
}
if (right.length()) {
audio_diskstream()->add_channel (1);
add_output_port (right, this, DataType::AUDIO);
_output->add_port (right, this, DataType::AUDIO);
}
allow_pan_reset ();
reset_panner ();
_main_outs->allow_pan_reset ();
_main_outs->reset_panner ();
IO::output_changed.connect (mem_fun (*this, &Auditioner::output_changed));
_output->changed.connect (mem_fun (*this, &Auditioner::output_changed));
the_region.reset ((AudioRegion*) 0);
g_atomic_int_set (&_active, 0);
@@ -110,7 +110,7 @@ Auditioner::audition_current_playlist ()
/* force a panner reset now that we have all channels */
_panner->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio());
_main_outs->panner()->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio());
g_atomic_int_set (&_active, 1);
}
@@ -148,7 +148,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
/* force a panner reset now that we have all channels */
reset_panner();
_main_outs->reset_panner();
length = the_region->length();
@@ -206,7 +206,7 @@ Auditioner::output_changed (IOChange change, void* src)
if (change & ConnectionsChanged) {
vector<string> connections;
if (output (0)->get_connections (connections)) {
if (_output->nth (0)->get_connections (connections)) {
phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0);
if (phys != connections[0]) {
_session.config.set_auditioner_output_left (connections[0]);
@@ -219,7 +219,7 @@ Auditioner::output_changed (IOChange change, void* src)
connections.clear ();
if (output (1)->get_connections (connections)) {
if (_output->nth (1)->get_connections (connections)) {
phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 1);
if (phys != connections[0]) {
_session.config.set_auditioner_output_right (connections[0]);

View File

@@ -24,8 +24,11 @@
#include <errno.h>
#include "pbd/error.h"
#include "pbd/enumwriter.h"
#include "midi++/names.h"
#include "ardour/automatable.h"
#include "ardour/amp.h"
#include "ardour/event_type_map.h"
#include "ardour/midi_track.h"
#include "ardour/panner.h"
@@ -382,7 +385,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
}
void
Automatable::transport_stopped (nframes_t now)
Automatable::transport_stopped (sframes_t now)
{
for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
@@ -409,7 +412,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
} else if (param.type() == PluginAutomation) {
control = new PluginInsert::PluginControl((PluginInsert*)this, param);
} else if (param.type() == GainAutomation) {
control = new IO::GainControl( X_("gaincontrol"), (IO*)this, param);
control = new Amp::GainControl( X_("gaincontrol"), _a_session, (Amp*)this, param);
} else if (param.type() == PanAutomation) {
Panner* me = dynamic_cast<Panner*>(this);
if (me) {

View File

@@ -20,58 +20,102 @@
#include <algorithm>
#include "pbd/enumwriter.h"
#include "pbd/convert.h"
#include "ardour/delivery.h"
#include "ardour/audio_buffer.h"
#include "ardour/amp.h"
#include "ardour/buffer_set.h"
#include "ardour/configuration.h"
#include "ardour/io.h"
#include "ardour/meter.h"
#include "ardour/mute_master.h"
#include "ardour/panner.h"
#include "ardour/port.h"
#include "ardour/session.h"
#include "i18n.h"
using namespace std;
using namespace PBD;
using namespace ARDOUR;
sigc::signal<void,nframes_t> Delivery::CycleStart;
sigc::signal<int> Delivery::PannersLegal;
bool Delivery::panners_legal = false;
/* deliver to an existing IO object */
Delivery::Delivery (Session& s, IO* io, const string& name, Role r)
: IOProcessor(s, io, name)
Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
: IOProcessor(s, boost::shared_ptr<IO>(), io, name)
, _role (r)
, _metering (false)
, _muted_by_self (false)
, _muted_by_others (false)
, _output_buffers (new BufferSet())
, _solo_level (0)
, _solo_isolated (false)
, _mute_master (mm)
{
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
/* deliver to a new IO object */
Delivery::Delivery (Session& s, const string& name, Role r)
: IOProcessor(s, name)
Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
: IOProcessor(s, false, true, name)
, _role (r)
, _metering (false)
, _muted_by_self (false)
, _muted_by_others (false)
, _output_buffers (new BufferSet())
, _solo_level (0)
, _solo_isolated (false)
, _mute_master (mm)
{
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
/* reconstruct from XML */
/* deliver to a new IO object, reconstruct from XML */
Delivery::Delivery (Session& s, const XMLNode& node)
: IOProcessor (s, "reset")
Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: IOProcessor (s, false, true, "reset")
, _role (Role (0))
, _metering (false)
, _muted_by_self (false)
, _muted_by_others (false)
, _output_buffers (new BufferSet())
, _solo_level (0)
, _solo_isolated (false)
, _mute_master (mm)
{
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
if (set_state (node)) {
throw failed_constructor ();
}
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
void
Delivery::cycle_start (nframes_t nframes)
{
_output_offset = 0;
_no_outs_cuz_we_no_monitor = false;
}
void
Delivery::increment_output_offset (nframes_t n)
{
_output_offset += n;
}
bool
Delivery::visible () const
{
if (_role & (Main|Solo)) {
if (_role & Main) {
return false;
}
@@ -91,6 +135,8 @@ Delivery::configure_io (ChanCount in, ChanCount out)
if (out != in) { // always 1:1
return false;
}
reset_panner ();
return Processor::configure_io (in, out);
}
@@ -98,64 +144,46 @@ Delivery::configure_io (ChanCount in, ChanCount out)
void
Delivery::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (_io->n_outputs().get (_io->default_type()) == 0) {
if (_output->n_ports ().get (_output->default_type()) == 0) {
return;
}
if (!active() || _muted_by_self || _muted_by_others) {
silence (nframes);
if (_metering) {
_io->peak_meter().reset();
}
} else {
// this Delivery processor is not a derived type, and thus we assume
// we really can modify the buffers passed in (it is almost certainly
// the main output stage of a Route). Contrast with Send::run_in_place()
// which cannot do this.
// we have to copy the input, because IO::deliver_output may alter the buffers
// in-place, which a send must never do.
BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
sendbufs.read_from(bufs, nframes);
assert(sendbufs.count() == bufs.count());
_io->deliver_output (sendbufs, start_frame, end_frame, nframes);
if (_metering) {
if (_io->effective_gain() == 0) {
_io->peak_meter().reset();
} else {
_io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes);
}
}
}
}
void
Delivery::set_metering (bool yn)
{
_metering = yn;
gain_t tgain = target_gain ();
if (!_metering) {
/* XXX possible thread hazard here */
_io->peak_meter().reset();
if (tgain != _current_gain) {
Amp::apply_gain (bufs, nframes, _current_gain, tgain);
_current_gain = tgain;
}
}
void
Delivery::set_self_mute (bool yn)
{
if (yn != _muted_by_self) {
_muted_by_self = yn;
SelfMuteChange (); // emit signal
// Attach output buffers to port buffers
PortSet& ports (_output->ports());
output_buffers().attach_buffers (ports, nframes, _output_offset);
if (_panner && _panner->npanners() && !_panner->bypassed()) {
// Use the panner to distribute audio to output port buffers
_panner->run (bufs, output_buffers(), start_frame, end_frame, nframes);
} else {
// Do a 1:1 copy of data to output ports
if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) {
_output->copy_to_outputs (bufs, DataType::AUDIO, nframes, _output_offset);
}
if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
_output->copy_to_outputs (bufs, DataType::MIDI, nframes, _output_offset);
}
}
}
void
Delivery::set_nonself_mute (bool yn)
{
if (yn != _muted_by_others) {
_muted_by_others = yn;
OtherMuteChange (); // emit signal
}
}
XMLNode&
Delivery::state (bool full_state)
@@ -170,10 +198,8 @@ Delivery::state (bool full_state)
node.add_property("type", "delivery");
}
node.add_property("metering", (_metering ? "yes" : "no"));
node.add_property("self-muted", (_muted_by_self ? "yes" : "no"));
node.add_property("other-muted", (_muted_by_others ? "yes" : "no"));
node.add_property("role", enum_2_string(_role));
node.add_child_nocopy (_panner->state (full_state));
return node;
}
@@ -182,22 +208,236 @@ int
Delivery::set_state (const XMLNode& node)
{
const XMLProperty* prop;
if (IOProcessor::set_state (node)) {
return -1;
}
if ((prop = node.property ("role")) != 0) {
_role = Role (string_2_enum (prop->value(), _role));
}
if ((prop = node.property ("metering")) != 0) {
set_metering (prop->value() == "yes");
if ((prop = node.property ("solo_level")) != 0) {
_solo_level = 0; // needed for the reset to work
mod_solo_level (atoi (prop->value()));
}
if ((prop = node.property ("self-muted")) != 0) {
set_self_mute (prop->value() == "yes");
if ((prop = node.property ("solo-isolated")) != 0) {
set_solo_isolated (prop->value() == "yes");
}
if ((prop = node.property ("other-muted")) != 0) {
set_nonself_mute (prop->value() == "yes");
}
XMLNode* pan_node = node.child (X_("Panner"));
if (pan_node) {
cerr << _name << " reset pan state from XML\n";
_panner->set_state (*pan_node);
}
reset_panner ();
return 0;
}
void
Delivery::reset_panner ()
{
cerr << _name << " reset panner - plegal ? " << panners_legal << endl;
if (panners_legal) {
if (!no_panner_reset) {
cerr << "\treset panner with " << _output->name() << " = " << _output->n_ports()
<< " vs. " << pans_required () << endl;
_panner->reset (_output->n_ports().n_audio(), pans_required());
}
} else {
cerr << "\tdefer pan reset till later\n";
panner_legal_c.disconnect ();
panner_legal_c = PannersLegal.connect (mem_fun (*this, &Delivery::panners_became_legal));
}
}
int
Delivery::panners_became_legal ()
{
cerr << _name << " panners now legal, outputs @ " << _output << " on " << _output->name()
<< " = " << _output->n_ports() << " vs. " << pans_required() << endl;
_panner->reset (_output->n_ports().n_audio(), pans_required());
_panner->load (); // automation
panner_legal_c.disconnect ();
return 0;
}
void
Delivery::defer_pan_reset ()
{
no_panner_reset = true;
}
void
Delivery::allow_pan_reset ()
{
no_panner_reset = false;
reset_panner ();
}
int
Delivery::disable_panners (void)
{
panners_legal = false;
return 0;
}
int
Delivery::reset_panners ()
{
panners_legal = true;
return PannersLegal ();
}
void
Delivery::start_pan_touch (uint32_t which)
{
if (which < _panner->npanners()) {
_panner->pan_control(which)->start_touch();
}
}
void
Delivery::end_pan_touch (uint32_t which)
{
if (which < _panner->npanners()) {
_panner->pan_control(which)->stop_touch();
}
}
void
Delivery::transport_stopped (sframes_t frame)
{
_panner->transport_stopped (frame);
}
void
Delivery::flush (nframes_t nframes)
{
/* io_lock, not taken: function must be called from Session::process() calltree */
PortSet& ports (_output->ports());
for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
(*i).flush_buffers (nframes, _output_offset);
}
}
gain_t
Delivery::target_gain ()
{
/* if we've been told not to output because its a monitoring situation and
we're not monitoring, then be quiet.
*/
if (_no_outs_cuz_we_no_monitor) {
return 0.0;
}
gain_t desired_gain;
MuteMaster::MutePoint mp;
if (_solo_level) {
desired_gain = 1.0;
} else {
if (_solo_isolated) {
switch (_role) {
case Main:
mp = MuteMaster::Main;
break;
case Listen:
mp = MuteMaster::Listen;
break;
case Send:
case Insert:
if (_placement == PreFader) {
mp = MuteMaster::PreFader;
} else {
mp = MuteMaster::PostFader;
}
break;
}
desired_gain = _mute_master->mute_gain_at (mp);
} else if (_session.soloing()) {
switch (_role) {
case Main:
mp = MuteMaster::Main;
break;
case Listen:
mp = MuteMaster::Listen;
break;
case Send:
case Insert:
if (_placement == PreFader) {
mp = MuteMaster::PreFader;
} else {
mp = MuteMaster::PostFader;
}
break;
}
desired_gain = min (Config->get_solo_mute_gain(), _mute_master->mute_gain_at (mp));
} else {
desired_gain = 1.0;
}
}
return desired_gain;
}
void
Delivery::mod_solo_level (int32_t delta)
{
if (delta < 0) {
if (_solo_level >= (uint32_t) delta) {
_solo_level += delta;
} else {
_solo_level = 0;
}
} else {
_solo_level += delta;
}
}
void
Delivery::set_solo_isolated (bool yn)
{
_solo_isolated = yn;
}
void
Delivery::no_outs_cuz_we_no_monitor (bool yn)
{
_no_outs_cuz_we_no_monitor = yn;
}
bool
Delivery::set_name (const std::string& name)
{
bool ret = IOProcessor::set_name (name);
if (ret) {
ret = _panner->set_name (name);
}
return ret;
}
void
Delivery::output_changed (IOChange change, void* src)
{
if (change & ARDOUR::ConfigurationChanged) {
reset_panner ();
}
}

View File

@@ -138,6 +138,8 @@ void
Diskstream::set_io (IO& io)
{
_io = &io;
input_change_pending = ConfigurationChanged;
non_realtime_input_change ();
set_align_style_from_io ();
}
@@ -233,7 +235,7 @@ Diskstream::set_capture_offset ()
return;
}
_capture_offset = _io->input_latency();
_capture_offset = _io->latency();
}
void
@@ -420,6 +422,11 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
void
Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{
#if 0
XXX THIS HAS TO BE FIXED FOR 3.0
if (Config->get_automation_follows_regions () == false) {
return;
}
@@ -431,7 +438,7 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
}
/* move gain automation */
boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->list();
XMLNode & before = gain_alist->get_state ();
gain_alist->move_ranges (movements);
_session.add_command (
@@ -458,11 +465,12 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
if (route) {
route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames));
}
#endif
}
void
Diskstream::move_processor_automation (boost::weak_ptr<Processor> p,
list< Evoral::RangeMove<nframes_t> > const & movements_frames)
list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{
boost::shared_ptr<Processor> processor (p.lock ());
if (!processor) {

View File

@@ -19,20 +19,21 @@
#include "pbd/enumwriter.h"
#include "ardour/types.h"
#include "ardour/delivery.h"
#include "ardour/session.h"
#include "ardour/location.h"
#include "ardour/audiofilesource.h"
#include "ardour/diskstream.h"
#include "ardour/audioregion.h"
#include "ardour/route_group.h"
#include "ardour/panner.h"
#include "ardour/track.h"
#include "ardour/midi_track.h"
#include "ardour/delivery.h"
#include "ardour/diskstream.h"
#include "ardour/export_filename.h"
#include "ardour/export_format_base.h"
#include "ardour/export_profile_manager.h"
#include "ardour/io.h"
#include "ardour/location.h"
#include "ardour/midi_track.h"
#include "ardour/panner.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
#include "ardour/track.h"
#include "ardour/types.h"
using namespace std;
using namespace PBD;
@@ -70,7 +71,6 @@ setup_enum_writer ()
SlaveSource _SlaveSource;
ShuttleBehaviour _ShuttleBehaviour;
ShuttleUnits _ShuttleUnits;
mute_type _mute_type;
Session::RecordState _Session_RecordState;
Session::Event::Type _Session_Event_Type;
SmpteFormat _Session_SmpteFormat;
@@ -105,6 +105,7 @@ setup_enum_writer ()
ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality;
ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat;
Delivery::Role _Delivery_Role;
IO::Direction _IO_Direction;
#define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@@ -328,12 +329,6 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
REGISTER (_Session_PullupFormat);
REGISTER_ENUM (PRE_FADER);
REGISTER_ENUM (POST_FADER);
REGISTER_ENUM (CONTROL_OUTS);
REGISTER_ENUM (MAIN_OUTS);
REGISTER (_mute_type);
REGISTER_CLASS_ENUM (Route, Hidden);
REGISTER_CLASS_ENUM (Route, MasterOut);
REGISTER_CLASS_ENUM (Route, ControlOut);
@@ -502,9 +497,13 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (ExportProfileManager, Off);
REGISTER (_ExportProfileManager_TimeFormat);
REGISTER_CLASS_ENUM (Delivery, Solo);
REGISTER_CLASS_ENUM (Delivery, Insert);
REGISTER_CLASS_ENUM (Delivery, Send);
REGISTER_CLASS_ENUM (Delivery, Listen);
REGISTER_CLASS_ENUM (Delivery, Main);
REGISTER_BITS (_Delivery_Role);
REGISTER_CLASS_ENUM (IO, Input);
REGISTER_CLASS_ENUM (IO, Output);
REGISTER (_IO_Direction);
}

File diff suppressed because it is too large Load Diff

View File

@@ -46,20 +46,36 @@ using namespace PBD;
/* create an IOProcessor that proxies to a new IO object */
IOProcessor::IOProcessor (Session& s, const string& proc_name, const string io_name, DataType dtype)
IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
const string& proc_name, const string io_name, DataType dtype)
: Processor(s, proc_name)
, _io (new IO(s, io_name.empty() ? proc_name : io_name, dtype))
{
_own_io = true;
/* these are true in this constructor whether we actually create the associated
IO objects or not.
*/
_own_input = true;
_own_output = true;
if (with_input) {
_input.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Input, dtype));
}
if (with_output) {
_output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype));
}
}
/* create an IOProcessor that proxies to an existing IO object */
IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype)
IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_ptr<IO> out,
const string& proc_name, DataType dtype)
: Processor(s, proc_name)
, _io (io)
, _input (in)
, _output (out)
{
_own_io = false;
_own_input = false;
_own_output = false;
}
IOProcessor::~IOProcessor ()
@@ -68,12 +84,21 @@ IOProcessor::~IOProcessor ()
}
void
IOProcessor::set_io (boost::shared_ptr<IO> io)
IOProcessor::set_input (boost::shared_ptr<IO> io)
{
/* CALLER MUST HOLD PROCESS LOCK */
_io = io;
_own_io = false;
_input = io;
_own_input = false;
}
void
IOProcessor::set_output (boost::shared_ptr<IO> io)
{
/* CALLER MUST HOLD PROCESS LOCK */
_output = io;
_own_output = false;
}
XMLNode&
@@ -81,12 +106,28 @@ IOProcessor::state (bool full_state)
{
XMLNode& node (Processor::state (full_state));
if (_own_io) {
node.add_child_nocopy (_io->state (full_state));
node.add_property ("own-io", "yes");
if (_own_input) {
XMLNode& i (_input->state (full_state));
// i.name() = X_("output");
node.add_child_nocopy (i);
node.add_property ("own-input", "yes");
} else {
node.add_property ("own-io", "no");
node.add_property ("io", _io->name());
node.add_property ("own-input", "no");
if (_input) {
node.add_property ("input", _input->name());
}
}
if (_own_output) {
XMLNode& o (_output->state (full_state));
// o.name() = X_("output");
node.add_child_nocopy (o);
node.add_property ("own-output", "yes");
} else {
node.add_property ("own-output", "no");
if (_output) {
node.add_property ("output", _output->name());
}
}
return node;
@@ -100,67 +141,59 @@ IOProcessor::set_state (const XMLNode& node)
Processor::set_state(node);
if ((prop = node.property ("own-io")) != 0) {
_own_io = prop->value() == "yes";
if ((prop = node.property ("own-input")) != 0) {
_own_input = (prop->value() == "yes");
}
if ((prop = node.property ("own-output")) != 0) {
_own_output = (prop->value() == "yes");
}
cerr << _name << " own input = " << _own_input << " output = " << _own_output << endl;
/* don't attempt to set state for a proxied IO that we don't own */
if (!_own_io) {
/* look up the IO object we're supposed to proxy to */
if ((prop = node.property ("io")) == 0) {
fatal << "IOProcessor has no named IO object" << endmsg;
/*NOTREACHED*/
}
boost::shared_ptr<Route> r = _session.route_by_name (prop->value());
if (!r) {
fatal << string_compose ("IOProcessor uses an unknown IO object called %1", prop->value()) << endmsg;
/*NOTREACHED*/
}
/* gotcha */
_io = boost::static_pointer_cast<IO> (r);
return 0;
}
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == IO::state_node_name) {
io_node = (*niter);
break;
} else if ((*niter)->name() == "Redirect") {
XMLNodeList rlist = (*niter)->children();
XMLNodeIterator riter;
for (riter = rlist.begin(); riter != rlist.end(); ++riter) {
if ( (*riter)->name() == IO::state_node_name) {
warning << _("Found legacy IO in a redirect") << endmsg;
io_node = (*riter);
break;
}
if (_own_input) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "input") {
io_node = (*niter);
break;
}
}
}
if (io_node) {
_io->set_state(*io_node);
// legacy sessions: use IO name
if ((prop = node.property ("name")) == 0) {
set_name (_io->name());
if (io_node) {
_input->set_state(*io_node);
// legacy sessions: use IO name
if ((prop = node.property ("name")) == 0) {
set_name (_input->name());
}
} else {
error << _("XML node describing an IOProcessor is missing an IO node") << endmsg;
return -1;
}
} else {
error << _("XML node describing a redirect is missing an IO node") << endmsg;
return -1;
}
if (_own_output) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "output") {
io_node = (*niter);
break;
}
}
if (io_node) {
_output->set_state(*io_node);
// legacy sessions: use IO name
if ((prop = node.property ("name")) == 0) {
set_name (_output->name());
}
}
}
return 0;
@@ -169,41 +202,33 @@ IOProcessor::set_state (const XMLNode& node)
void
IOProcessor::silence (nframes_t nframes)
{
if (_own_io) {
_io->silence (nframes);
if (_own_output && _output) {
_output->silence (nframes);
}
}
ChanCount
IOProcessor::output_streams() const
{
return _io->n_outputs();
return _output ? _output->n_ports() : ChanCount::ZERO;
}
ChanCount
IOProcessor::input_streams () const
{
return _io->n_inputs();
return _input ? _input->n_ports() : ChanCount::ZERO;
}
ChanCount
IOProcessor::natural_output_streams() const
{
return _io->n_outputs();
return _output ? _output->n_ports() : ChanCount::ZERO;
}
ChanCount
IOProcessor::natural_input_streams () const
{
return _io->n_inputs();
}
void
IOProcessor::automation_snapshot (nframes_t now, bool force)
{
if (_own_io) {
_io->automation_snapshot(now, force);
}
return _input ? _input->n_ports() : ChanCount::ZERO;
}
bool
@@ -211,8 +236,12 @@ IOProcessor::set_name (const std::string& name)
{
bool ret = SessionObject::set_name (name);
if (ret && _own_io) {
ret = _io->set_name (name);
if (ret && _own_input && _input) {
ret = _input->set_name (name);
}
if (ret && _own_output && _output) {
ret = _output->set_name (name);
}
return ret;

View File

@@ -29,8 +29,41 @@
using namespace std;
namespace ARDOUR {
using namespace ARDOUR;
sigc::signal<void> Metering::Meter;
Glib::StaticMutex Metering::m_meter_signal_lock;
sigc::connection
Metering::connect (sigc::slot<void> the_slot)
{
// SignalProcessor::Meter is emitted from another thread so the
// Meter signal must be protected.
Glib::Mutex::Lock guard (m_meter_signal_lock);
return Meter.connect (the_slot);
}
void
Metering::disconnect (sigc::connection& c)
{
Glib::Mutex::Lock guard (m_meter_signal_lock);
c.disconnect ();
}
/**
Update the meters.
The meter signal lock is taken to prevent modification of the
Meter signal while updating the meters, taking the meter signal
lock prior to taking the io_lock ensures that all IO will remain
valid while metering.
*/
void
Metering::update_meters()
{
Glib::Mutex::Lock guard (m_meter_signal_lock);
Meter(); /* EMIT SIGNAL */
}
/** Get peaks from @a bufs
* Input acceptance is lenient - the first n buffers from @a bufs will
@@ -128,8 +161,10 @@ PeakMeter::configure_io (ChanCount in, ChanCount out)
}
/** To be driven by the Meter signal from IO.
* Caller MUST hold io_lock!
* Caller MUST hold its own processor_lock to prevent reconfiguration
* of meter size during this call.
*/
void
PeakMeter::meter ()
{
@@ -139,12 +174,10 @@ PeakMeter::meter ()
for (size_t n = 0; n < limit; ++n) {
/* XXX we should use atomic exchange here */
/* grab peak since last read */
float new_peak = _peak_power[n];
_peak_power[n] = 0;
float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */
_peak_power[n] = 0; /* ... to here */
/* compute new visible value using falloff */
@@ -176,4 +209,3 @@ PeakMeter::state (bool full_state)
return node;
}
} // namespace ARDOUR

View File

@@ -159,8 +159,8 @@ MidiDiskstream::non_realtime_input_change ()
}
if (input_change_pending & ConfigurationChanged) {
if (_io->n_inputs().n_midi() != _n_channels.n_midi()) {
error << "Can not feed IO " << _io->n_inputs()
if (_io->n_ports().n_midi() != _n_channels.n_midi()) {
error << "Can not feed IO " << _io->n_ports()
<< " with diskstream " << _n_channels << endl;
}
}
@@ -199,7 +199,7 @@ MidiDiskstream::non_realtime_input_change ()
void
MidiDiskstream::get_input_sources ()
{
uint32_t ni = _io->n_inputs().n_midi();
uint32_t ni = _io->n_ports().n_midi();
if (ni == 0) {
return;
@@ -208,7 +208,7 @@ MidiDiskstream::get_input_sources ()
// This is all we do for now at least
assert(ni == 1);
_source_port = _io->midi_input(0);
_source_port = _io->midi(0);
// do... stuff?
}
@@ -421,6 +421,7 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe
last_possibly_recording = possibly_recording;
}
#if 0
static void
trace_midi (ostream& o, MIDI::byte *msg, size_t len)
{
@@ -587,6 +588,7 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len)
break;
}
}
#endif
int
MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)

View File

@@ -27,6 +27,7 @@
#include "ardour/amp.h"
#include "ardour/buffer_set.h"
#include "ardour/delivery.h"
#include "ardour/io_processor.h"
#include "ardour/meter.h"
#include "ardour/midi_diskstream.h"
@@ -94,14 +95,14 @@ int
MidiTrack::set_diskstream (boost::shared_ptr<MidiDiskstream> ds)
{
_diskstream = ds;
_diskstream->set_io (*this);
_diskstream->set_io (*(_input.get()));
_diskstream->set_destructive (_mode == Destructive);
_diskstream->set_record_enabled (false);
//_diskstream->monitor_input (false);
ic_connection.disconnect();
ic_connection = input_changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
ic_connection = _input->changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
DiskstreamChanged (); /* EMIT SIGNAL */
@@ -113,11 +114,14 @@ MidiTrack::use_diskstream (string name)
{
boost::shared_ptr<MidiDiskstream> dstream;
cerr << "\n\n\nMIDI use diskstream\n";
if ((dstream = boost::dynamic_pointer_cast<MidiDiskstream>(_session.diskstream_by_name (name))) == 0) {
error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg;
return -1;
}
cerr << "\n\n\nMIDI found DS\n";
return set_diskstream (dstream);
}
@@ -191,6 +195,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
that means "you should create a new diskstream here, not look for
an old one.
*/
cerr << "\n\n\n\n MIDI track " << name() << " found DS id " << id << endl;
if (id == zero) {
use_new_diskstream ();
@@ -363,8 +369,6 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
int dret;
boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
prepare_inputs (nframes);
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (lm.locked()) {
@@ -405,7 +409,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* special condition applies */
if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes);
_input->process_input (_meter, start_frame, end_frame, nframes);
}
if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@@ -438,7 +442,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
}
flush_outputs (nframes);
_main_outs->flush (nframes);
return 0;
}

109
libs/ardour/mute_master.cc Normal file
View File

@@ -0,0 +1,109 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ardour/mute_master.h"
#include "ardour/rc_configuration.h"
#include "i18n.h"
using namespace ARDOUR;
MuteMaster::MuteMaster (Session& s, const std::string& name)
: AutomationControl (s, Evoral::Parameter (MuteAutomation), boost::shared_ptr<AutomationList>(), name)
, _mute_point (MutePoint (0))
{
// default range for parameter is fine
_automation = new AutomationList (MuteAutomation);
set_list (boost::shared_ptr<AutomationList>(_automation));
}
void
MuteMaster::clear_mute ()
{
if (_mute_point != MutePoint (0)) {
_mute_point = MutePoint (0);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::mute_at (MutePoint mp)
{
if ((_mute_point & mp) != mp) {
_mute_point = MutePoint (_mute_point | mp);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::unmute_at (MutePoint mp)
{
if ((_mute_point & mp) == mp) {
_mute_point = MutePoint (_mute_point & ~mp);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::mute (bool yn)
{
/* convenience wrapper around AutomationControl method */
if (yn) {
set_value (1.0f);
} else {
set_value (0.0f);
}
}
gain_t
MuteMaster::mute_gain_at (MutePoint mp) const
{
if (_mute_point & mp) {
return Config->get_solo_mute_gain ();
} else {
return 1.0;
}
}
void
MuteMaster::set_value (float f)
{
mute_at ((MutePoint) ((int) rint (f)));
}
float
MuteMaster::get_value () const
{
return (float) _mute_point;
}
int
MuteMaster::set_state (const XMLNode& node)
{
return 0;
}
XMLNode&
MuteMaster::get_state()
{
return *(new XMLNode (X_("MuteMaster")));
}

View File

@@ -703,7 +703,8 @@ Multi2dPanner::set_state (const XMLNode& node)
/*---------------------------------------------------------------------- */
Panner::Panner (string name, Session& s)
: Processor(s, name)
: SessionObject (s, name)
, AutomatableControls (s)
{
//set_name_old_auto (name);
set_name (name);
@@ -829,6 +830,8 @@ Panner::reset (uint32_t nouts, uint32_t npans)
bool changed = false;
bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2));
cerr << "panner " << _name << " reset to " << nouts << " / " << npans << endl;
/* if new and old config don't need panning, or if
the config hasn't changed, we're done.
*/
@@ -1058,15 +1061,13 @@ Panner::get_state (void)
XMLNode&
Panner::state (bool full)
{
XMLNode& node = Processor::state(full);
node.add_property ("type", "panner");
XMLNode* node = new XMLNode ("Panner");
char buf[32];
node.add_property (X_("linked"), (_linked ? "yes" : "no"));
node.add_property (X_("link_direction"), enum_2_string (_link_direction));
node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
node->add_property (X_("linked"), (_linked ? "yes" : "no"));
node->add_property (X_("link_direction"), enum_2_string (_link_direction));
node->add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
XMLNode* onode = new XMLNode (X_("Output"));
@@ -1074,15 +1075,15 @@ Panner::state (bool full)
onode->add_property (X_("x"), buf);
snprintf (buf, sizeof (buf), "%.12g", (*o).y);
onode->add_property (X_("y"), buf);
node.add_child_nocopy (*onode);
node->add_child_nocopy (*onode);
}
for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
node.add_child_nocopy ((*i)->state (full));
node->add_child_nocopy ((*i)->state (full));
}
return node;
return *node;
}
int
@@ -1098,8 +1099,6 @@ Panner::set_state (const XMLNode& node)
clear_panners ();
Processor::set_state(node);
ChanCount ins = ChanCount::ZERO;
ChanCount outs = ChanCount::ZERO;
@@ -1419,7 +1418,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes
}
void
Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (outbufs.count().n_audio() == 0) {
// Failing to deliver audio we were asked to deliver is a bug
@@ -1432,16 +1431,16 @@ Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start
assert(!empty());
// If we shouldn't play automation defer to distribute_no_automation
if ( !( automation_state() & Play ||
((automation_state() & Touch) && !touching()) ) ) {
if (!(automation_state() & Play || ((automation_state() & Touch) && !touching()))) {
// Speed quietning
gain_t gain_coeff = 1.0;
if (fabsf(_session.transport_speed()) > 1.5f) {
gain_coeff = speed_quietning;
}
distribute_no_automation(inbufs, outbufs, nframes, gain_coeff);
distribute_no_automation (inbufs, outbufs, nframes, gain_coeff);
return;
}

View File

@@ -24,6 +24,7 @@
#include "pbd/failed_constructor.h"
#include "pbd/xml++.h"
#include "ardour/delivery.h"
#include "ardour/port_insert.h"
#include "ardour/plugin.h"
#include "ardour/port.h"
@@ -40,15 +41,17 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
PortInsert::PortInsert (Session& s)
: IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm)
: IOProcessor (s, true, true, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
, _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
{
init ();
ProcessorCreated (this); /* EMIT SIGNAL */
}
PortInsert::PortInsert (Session& s, const XMLNode& node)
: IOProcessor (s, "unnamed port insert")
PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: IOProcessor (s, true, true, "unnamed port insert")
, _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
{
if (set_state (node)) {
throw failed_constructor();
@@ -62,30 +65,21 @@ PortInsert::~PortInsert ()
GoingAway ();
}
void
PortInsert::init ()
{
if (_io->ensure_io(output_streams(), input_streams(), false, this)) { // sic
error << _("PortInsert: cannot create ports") << endmsg;
throw failed_constructor();
}
}
void
PortInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (_io->n_outputs().n_total() == 0) {
if (_output->n_ports().n_total() == 0) {
return;
}
if (!active()) {
/* deliver silence */
_io->silence (nframes);
silence (nframes);
return;
}
_io->deliver_output (bufs, start_frame, end_frame, nframes);
_io->collect_input (bufs, nframes);
_out->run_in_place (bufs, start_frame, end_frame, nframes);
_input->collect_input (bufs, nframes, ChanCount::ZERO);
}
XMLNode&
@@ -97,7 +91,7 @@ PortInsert::get_state(void)
XMLNode&
PortInsert::state (bool full)
{
XMLNode& node = IOProcessor::state(full);
XMLNode& node = Processor::state(full);
char buf[32];
node.add_property ("type", "port");
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
@@ -141,7 +135,7 @@ PortInsert::set_state(const XMLNode& node)
}
}
IOProcessor::set_state (*insert_node);
Processor::set_state (*insert_node);
return 0;
}
@@ -156,7 +150,7 @@ PortInsert::signal_latency() const
need to take that into account too.
*/
return _session.engine().frames_per_cycle() + _io->input_latency();
return _session.engine().frames_per_cycle() + _input->signal_latency();
}
bool
@@ -164,7 +158,11 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
{
/* for an insert, processor input corresponds to IO output, and vice versa */
if (_io->ensure_io (out, in, false, this) != 0) {
if (_input->ensure_io (in, false, this) != 0) {
return false;
}
if (_output->ensure_io (out, false, this) != 0) {
return false;
}
@@ -178,3 +176,12 @@ PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) c
return true;
}
bool
PortInsert::set_name (const std::string& name)
{
bool ret = Processor::set_name (name);
ret = (_input->set_name (name) || _output->set_name (name));
return ret;
}

View File

@@ -211,7 +211,8 @@ Processor::configure_io (ChanCount in, ChanCount out)
{
/* This class assumes 1:1 input:output.static output stream count.
Derived classes must override and set _configured_output appropriately
if this is not the case */
if this is not the case
*/
_configured_input = in;
_configured_output = out;

View File

@@ -21,14 +21,15 @@
#include "pbd/xml++.h"
#include "ardour/return.h"
#include "ardour/session.h"
#include "ardour/port.h"
#include "ardour/amp.h"
#include "ardour/audio_port.h"
#include "ardour/buffer_set.h"
#include "ardour/io.h"
#include "ardour/meter.h"
#include "ardour/panner.h"
#include "ardour/io.h"
#include "ardour/port.h"
#include "ardour/return.h"
#include "ardour/session.h"
#include "i18n.h"
@@ -36,14 +37,26 @@ using namespace ARDOUR;
using namespace PBD;
Return::Return (Session& s)
: IOProcessor (s, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
: IOProcessor (s, true, false, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
, _metering (false)
{
/* never muted */
_amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
_meter.reset (new PeakMeter (_session));
ProcessorCreated (this); /* EMIT SIGNAL */
}
Return::Return (Session& s, const XMLNode& node)
: IOProcessor (s, "return")
: IOProcessor (s, true, false, "return")
, _metering (false)
{
/* never muted */
_amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
_meter.reset (new PeakMeter (_session));
if (set_state (node)) {
throw failed_constructor();
}
@@ -108,23 +121,38 @@ Return::set_state(const XMLNode& node)
void
Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (active()) {
_io->collect_input (bufs, nframes, _configured_input);
bufs.set_count(_configured_output);
if (!active() || _input->n_ports() == ChanCount::ZERO) {
return;
}
_input->collect_input (bufs, nframes, _configured_input);
bufs.set_count(_configured_output);
// Can't automate gain for sends or returns yet because we need different buffers
// so that we don't overwrite the main automation data for the route amp
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
_amp->run_in_place (bufs, start_frame, end_frame, nframes);
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run_in_place (bufs, start_frame, end_frame, nframes);
}
}
}
bool
Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
out = in + _io->n_inputs();
out = in + _input->n_ports();
return true;
}
bool
Return::configure_io (ChanCount in, ChanCount out)
{
if (out != in + _io->n_inputs()) {
if (out != in + _input->n_ports()) {
return false;
}
@@ -162,3 +190,4 @@ Return::make_unique (XMLNode &state, Session &session)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include "pbd/error.h"
#include "pbd/enumwriter.h"
#include "ardour/amp.h"
#include "ardour/route_group.h"
#include "ardour/audio_track.h"
#include "ardour/audio_diskstream.h"
@@ -87,7 +88,7 @@ RouteGroup::get_min_factor(gain_t factor)
gain_t g;
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
g = (*i)->gain();
g = (*i)->amp()->gain();
if ( (g+g*factor) >= 0.0f)
continue;
@@ -106,7 +107,7 @@ RouteGroup::get_max_factor(gain_t factor)
gain_t g;
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
g = (*i)->gain();
g = (*i)->amp()->gain();
// if the current factor woulnd't raise this route above maximum
if ( (g+g*factor) <= 1.99526231f)

View File

@@ -21,6 +21,7 @@
#include "pbd/xml++.h"
#include "ardour/amp.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour/port.h"
@@ -35,15 +36,23 @@
using namespace ARDOUR;
using namespace PBD;
Send::Send (Session& s)
: Delivery (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
: Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
, _metering (false)
{
_amp.reset (new Amp (_session, _mute_master));
_meter.reset (new PeakMeter (_session));
ProcessorCreated (this); /* EMIT SIGNAL */
}
Send::Send (Session& s, const XMLNode& node)
: Delivery (s, "send", Delivery::Send)
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: Delivery (s, mm, "send", Delivery::Send)
, _metering (false)
{
_amp.reset (new Amp (_session, _mute_master));
_meter.reset (new PeakMeter (_session));
if (set_state (node)) {
throw failed_constructor();
}
@@ -56,6 +65,43 @@ Send::~Send ()
GoingAway ();
}
void
Send::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (!_active || _output->n_ports() == ChanCount::ZERO) {
_meter->reset ();
return;
}
// we have to copy the input, because deliver_output() may alter the buffers
// in-place, which a send must never do.
BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
sendbufs.read_from (bufs, nframes);
assert(sendbufs.count() == bufs.count());
/* gain control */
// Can't automate gain for sends or returns yet because we need different buffers
// so that we don't overwrite the main automation data for the route amp
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
_amp->run_in_place (sendbufs, start_frame, end_frame, nframes);
/* deliver to outputs */
Delivery::run_in_place (sendbufs, start_frame, end_frame, nframes);
/* consider metering */
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run_in_place (*_output_buffers, start_frame, end_frame, nframes);
}
}
}
XMLNode&
Send::get_state(void)
{
@@ -90,17 +136,9 @@ Send::set_state(const XMLNode& node)
const XMLNode* insert_node = &node;
/* Send has regular IO automation (gain, pan) */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == IOProcessor::state_node_name) {
insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) {
// _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
}
}
/* XXX need to load automation state & data for amp */
IOProcessor::set_state (*insert_node);
Delivery::set_state (*insert_node);
return 0;
}
@@ -108,7 +146,7 @@ Send::set_state(const XMLNode& node)
bool
Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
if (_io->n_inputs() == ChanCount::ZERO && _io->n_outputs() == ChanCount::ZERO) {
if (_output->n_ports() == ChanCount::ZERO) {
/* not configured yet, we can support anything */
@@ -126,25 +164,6 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
return false;
}
bool
Send::configure_io (ChanCount in, ChanCount out)
{
/* we're transparent no matter what. fight the power. */
if (out != in) {
return false;
}
if (_io->ensure_io (ChanCount::ZERO, in, false, this) != 0) {
return false;
}
Processor::configure_io(in, out);
_io->reset_panner();
return true;
}
/** Set up the XML description of a send so that its name is unique.
* @param state XML send state.
* @param session Session.

View File

@@ -272,7 +272,8 @@ Session::Session (AudioEngine &eng,
if (control_out_channels) {
ChanCount count(DataType::AUDIO, control_out_channels);
shared_ptr<Route> r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO));
r->ensure_io (count, count, false, this);
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);
@@ -280,9 +281,9 @@ Session::Session (AudioEngine &eng,
if (master_out_channels) {
ChanCount count(DataType::AUDIO, master_out_channels);
cerr << "new MO with " << count << endl;
shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
r->ensure_io (count, count, false, this);
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);
@@ -516,8 +517,8 @@ Session::set_worst_io_latencies ()
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
_worst_output_latency = max (_worst_output_latency, (*i)->output_latency());
_worst_input_latency = max (_worst_input_latency, (*i)->input_latency());
_worst_output_latency = max (_worst_output_latency, (*i)->output()->latency());
_worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
}
}
@@ -574,15 +575,15 @@ Session::when_engine_running ()
for (int physport = 0; physport < 2; ++physport) {
string physical_output = _engine.get_nth_physical_output (DataType::AUDIO, physport);
if (physical_output.length()) {
if (_click_io->add_output_port (physical_output, this)) {
if (_click_io->add_port (physical_output, this)) {
// relax, even though its an error
}
}
}
if (_click_io->n_outputs () > ChanCount::ZERO) {
if (_click_io->n_ports () > ChanCount::ZERO) {
_clicking = Config->get_clicking ();
}
}
@@ -665,12 +666,6 @@ Session::when_engine_running ()
if (_master_out) {
/* force the master to ignore any later call to this
*/
if (_master_out->pending_state_node) {
_master_out->ports_became_legal();
}
/* if requested auto-connect the outputs to the first N physical ports.
*/
@@ -678,11 +673,11 @@ Session::when_engine_running ()
uint32_t limit = _master_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) {
Port* p = _master_out->output (n);
Port* p = _master_out->output()->nth (n);
string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n);
if (!connect_to.empty()) {
if (_master_out->connect_output (p, connect_to, this)) {
if (_master_out->output()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
<< endmsg;
break;
@@ -760,10 +755,6 @@ Session::hookup_io ()
}
}
/* Tell all IO objects to create their ports */
IO::enable_ports ();
/* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */
if (_control_out) {
@@ -777,7 +768,7 @@ Session::hookup_io ()
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x);
if (t) {
t->listen_via (_control_out, X_("listen"));
t->listen_via (_control_out->input(), X_("listen"));
}
}
}
@@ -794,7 +785,7 @@ Session::hookup_io ()
/* Now reset all panners */
IO::reset_panners ();
Delivery::reset_panners ();
/* Anyone who cares about input state, wake up and do something */
@@ -1468,7 +1459,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
continue;
}
if ((*j)->feeds (*i)) {
if ((*j)->feeds ((*i)->input())) {
(*i)->fed_by.insert (*j);
}
}
@@ -1553,7 +1544,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
try {
track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) {
if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
@@ -1711,7 +1708,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
try {
track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
@@ -1729,7 +1733,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = physinputs[(channels_used+x)%nphysical_in];
}
if (port.length() && track->connect_input (track->input (x), port, this)) {
if (port.length() && track->input()->connect (track->input()->nth(x), port, this)) {
break;
}
}
@@ -1745,11 +1749,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = physoutputs[(channels_used+x)%nphysical_out];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
if (_master_out && _master_out->n_inputs().n_audio() > 0) {
port = _master_out->input (x % _master_out->n_inputs().n_audio())->name();
port = _master_out->input()->nth (x % _master_out->input()->n_ports().n_audio())->name();
}
}
if (port.length() && track->connect_output (track->output (x), port, this)) {
if (port.length() && track->output()->connect (track->output()->nth(x), port, this)) {
break;
}
}
@@ -1889,7 +1893,15 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
try {
shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
@@ -1920,11 +1932,11 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
port = physoutputs[((n+x)%n_physical_outputs)];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
if (_master_out) {
port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
port = _master_out->input()->nth (x%_master_out->input()->n_ports().n_audio())->name();
}
}
if (port.length() && bus->connect_output (bus->output (x), port, this)) {
if (port.length() && bus->output()->connect (bus->output()->nth(x), port, this)) {
break;
}
}
@@ -2023,8 +2035,8 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
picks up the configuration of the route. During session
loading this normally happens in a different way.
*/
route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
route->input()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
route->output()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
}
route->set_remote_control_id (control_id);
@@ -2070,7 +2082,7 @@ Session::add_routes (RouteList& new_routes, bool save)
(*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));
(*x)->output()->changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
(*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
if ((*x)->is_master()) {
@@ -2085,7 +2097,7 @@ Session::add_routes (RouteList& new_routes, bool save)
if (_control_out && IO::connecting_legal) {
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
(*x)->listen_via (_control_out, "control");
(*x)->listen_via (_control_out->input(), "control");
}
}
@@ -2145,7 +2157,7 @@ Session::remove_route (shared_ptr<Route> route)
/* cancel control outs for all routes */
for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
(*r)->drop_listen (_control_out);
(*r)->drop_listen (_control_out->input());
}
_control_out = shared_ptr<Route> ();
@@ -2176,8 +2188,8 @@ Session::remove_route (shared_ptr<Route> route)
// We need to disconnect the routes inputs and outputs
route->disconnect_inputs (0);
route->disconnect_outputs (0);
route->input()->disconnect (0);
route->output()->disconnect (0);
update_latency_compensation (false, false);
set_dirty();
@@ -2215,7 +2227,6 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
return;
}
bool is_track;
boost::shared_ptr<Route> route = wpr.lock ();
if (!route) {
@@ -2224,86 +2235,39 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
return;
}
is_track = (boost::dynamic_pointer_cast<AudioTrack>(route) != 0);
shared_ptr<RouteList> r = routes.reader ();
int32_t delta;
if (route->soloed()) {
delta = 1;
} else {
delta = -1;
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
/* soloing a track mutes all other tracks, soloing a bus mutes all other busses */
if (is_track) {
/* don't mess with busses */
if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
continue;
}
} else {
/* don't mess with tracks */
if (boost::dynamic_pointer_cast<Track>(*i) != 0) {
continue;
}
}
if ((*i) != route &&
((*i)->mix_group () == 0 ||
(*i)->mix_group () != route->mix_group () ||
!route->mix_group ()->is_active())) {
if ((*i)->soloed()) {
/* if its already soloed, and solo latching is enabled,
then leave it as it is.
*/
if (Config->get_solo_latched()) {
continue;
}
}
if ((*i)->feeds (route->input())) {
/* do it */
solo_update_disabled = true;
(*i)->set_solo (false, src);
(*i)->main_outs()->mod_solo_level (delta);
solo_update_disabled = false;
}
}
bool something_soloed = false;
bool same_thing_soloed = false;
bool signal = false;
/* now figure out if anything is soloed */
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
bool something_soloed = false;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->soloed()) {
something_soloed = true;
if (boost::dynamic_pointer_cast<Track>(*i)) {
if (is_track) {
same_thing_soloed = true;
break;
}
} else {
if (!is_track) {
same_thing_soloed = true;
break;
}
}
break;
}
}
if (something_soloed != currently_soloing) {
signal = true;
currently_soloing = something_soloed;
}
modify_solo_mute (is_track, same_thing_soloed);
if (signal) {
SoloActive (currently_soloing); /* EMIT SIGNAL */
if (something_soloed != _non_soloed_outs_muted) {
_non_soloed_outs_muted = something_soloed;
SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
}
SoloChanged (); /* EMIT SIGNAL */
@@ -2343,70 +2307,18 @@ Session::update_route_solo_state ()
/* nothing is soloed */
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_solo_mute (false);
}
if (signal) {
SoloActive (false);
}
return;
}
modify_solo_mute (is_track, mute);
if (signal) {
SoloActive (currently_soloing);
}
}
void
Session::modify_solo_mute (bool is_track, bool mute)
{
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (is_track) {
/* only alter track solo mute */
if (boost::dynamic_pointer_cast<Track>(*i)) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (!mute);
} else {
(*i)->set_solo_mute (mute);
}
}
} else {
/* only alter bus solo mute */
if (!boost::dynamic_pointer_cast<Track>(*i)) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (false);
} else {
/* don't mute master or control outs
in response to another bus solo
*/
if ((*i) != _master_out &&
(*i) != _control_out) {
(*i)->set_solo_mute (mute);
}
}
}
}
}
}
void
Session::catch_up_on_solo ()
@@ -2432,7 +2344,7 @@ Session::catch_up_on_solo_mute_override ()
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->catch_up_on_solo_mute_override ();
// (*i)->catch_up_on_solo_mute_override ();
}
}

View File

@@ -127,7 +127,7 @@ Session::click (nframes_t start, nframes_t nframes)
i = next;
}
_click_io->deliver_output (bufs, start, end, nframes);
_click_io->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
}
void

View File

@@ -151,7 +151,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
_non_soloed_outs_muted = false;
g_atomic_int_set (&processing_prohibited, 0);
insert_cnt = 0;
_transport_speed = 0;
@@ -272,8 +272,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
/* stop IO objects from doing stuff until we're ready for them */
IO::disable_panners ();
IO::disable_ports ();
Delivery::disable_panners ();
IO::disable_connecting ();
}
@@ -1155,7 +1154,6 @@ Session::set_state (const XMLNode& node)
}
IO::disable_ports ();
IO::disable_connecting ();
/* Object loading order:
@@ -3215,7 +3213,7 @@ Session::config_changed (std::string p, bool ours)
// deliver_midi (_mmc_port, buf, 2);
}
} else if (p == "solo-mute-override") {
catch_up_on_solo_mute_override ();
// catch_up_on_solo_mute_override ();
}
set_dirty ();

View File

@@ -1335,11 +1335,12 @@ Session::update_latency_compensation (bool with_stop, bool abort)
(!(post_transport_work & PostTransportLocate) || pending_locate_flush));
}
nframes_t old_latency = (*i)->signal_latency ();
nframes_t old_latency = (*i)->output()->signal_latency ();
nframes_t track_latency = (*i)->update_total_latency ();
if (old_latency != track_latency) {
(*i)->update_port_total_latencies ();
(*i)->input()->update_port_total_latencies ();
(*i)->output()->update_port_total_latencies ();
update_jack = true;
}

View File

@@ -26,7 +26,7 @@
#include "ardour/audiosource.h"
#include "ardour/diskstream.h"
#include "ardour/io_processor.h"
#include "ardour/panner.h"
#include "ardour/meter.h"
#include "ardour/port.h"
#include "ardour/processor.h"
#include "ardour/route_group_specialized.h"
@@ -84,7 +84,7 @@ Track::get_template ()
void
Track::toggle_monitor_input ()
{
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) {
i->ensure_monitor_input(!i->monitoring_input());
}
}
@@ -92,32 +92,28 @@ Track::toggle_monitor_input ()
ARDOUR::nframes_t
Track::update_total_latency ()
{
nframes_t old = _own_latency;
if (_user_latency) {
_own_latency = _user_latency;
} else {
_own_latency = 0;
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->active ()) {
_own_latency += (*i)->signal_latency ();
}
nframes_t old = _output->effective_latency();
nframes_t own_latency = _output->user_latency();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->active ()) {
own_latency += (*i)->signal_latency ();
}
}
#undef DEBUG_LATENCY
#ifdef DEBUG_LATENCY
cerr << _name << ": internal redirect (final) latency = " << _own_latency << endl;
cerr << _name << ": internal redirect (final) latency = " << own_latency << endl;
#endif
set_port_latency (_own_latency);
if (old != _own_latency) {
_output->set_port_latency (own_latency);
if (old != own_latency) {
_output->set_latency_delay (own_latency);
signal_latency_changed (); /* EMIT SIGNAL */
}
return _own_latency;
return _output->effective_latency();
}
Track::FreezeRecord::~FreezeRecord ()
@@ -155,14 +151,14 @@ Track::RecEnableControllable::get_value (void) const
bool
Track::record_enabled () const
{
return _diskstream->record_enabled ();
return _diskstream && _diskstream->record_enabled ();
}
bool
Track::can_record()
{
bool will_record = true;
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end() && will_record; ++i) {
for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end() && will_record; ++i) {
if (!i->connected())
will_record = false;
}
@@ -307,7 +303,7 @@ Track::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
passthru_silence (start_frame, end_frame, nframes, 0);
} else {
if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes);
_input->process_input (_meter, start_frame, end_frame, nframes);
}
passthru_silence (start_frame, end_frame, nframes, 0);
}

View File

@@ -135,7 +135,7 @@ def build(bld):
gdither.cc
globals.cc
import.cc
io.cc
io.cc
io_processor.cc
jack_slave.cc
ladspa_plugin.cc
@@ -157,6 +157,7 @@ def build(bld):
midi_track.cc
mix.cc
mtc_slave.cc
mute_master.cc
named_selection.cc
onset_detector.cc
panner.cc
@@ -178,7 +179,7 @@ def build(bld):
resampled_source.cc
return.cc
reverse.cc
route.cc
route.cc
route_group.cc
send.cc
session.cc

View File

@@ -23,9 +23,6 @@
#include <gtkmm/drawingarea.h>
#include <gtkmm2ext/binding_proxy.h>
namespace ARDOUR {
class Controllable;
}
namespace Gtkmm2ext {

View File

@@ -158,7 +158,7 @@ MIDI::byte
MIDI::decode_controller_name (const char *name)
{
char *lparen;
const char *lparen;
size_t len;
if ((lparen = strrchr (name, '(')) != 0) {

View File

@@ -18,11 +18,12 @@
*/
#include <ardour/session.h>
#include <ardour/route.h>
#include <ardour/audio_track.h>
#include <ardour/meter.h>
#include <control_protocol/control_protocol.h>
#include "ardour/session.h"
#include "ardour/route.h"
#include "ardour/audio_track.h"
#include "ardour/meter.h"
#include "ardour/amp.h"
#include "control_protocol/control_protocol.h"
using namespace ARDOUR;
using namespace std;
@@ -212,7 +213,7 @@ ControlProtocol::route_get_gain (uint32_t table_index)
return 0.0f;
}
return r->gain ();
return r->amp()->gain ();
}
void
@@ -242,7 +243,7 @@ ControlProtocol::route_get_effective_gain (uint32_t table_index)
return 0.0f;
}
return r->effective_gain ();
return r->amp()->gain_control()->get_value();
}