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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ¶m,
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 ();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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 ¶m,
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
77
libs/ardour/ardour/mute_master.h
Normal file
77
libs/ardour/ardour/mute_master.h
Normal 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__ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
2012
libs/ardour/io.cc
2012
libs/ardour/io.cc
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
109
libs/ardour/mute_master.cc
Normal 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")));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
1027
libs/ardour/route.cc
1027
libs/ardour/route.cc
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
#include <gtkmm/drawingarea.h>
|
||||
#include <gtkmm2ext/binding_proxy.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
class Controllable;
|
||||
}
|
||||
|
||||
namespace Gtkmm2ext {
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user