first pass (ok, third really) at internal send+return - audio routing inside ardour without JACK. lots still to do, but at least the obvious works

git-svn-id: svn://localhost/ardour2/branches/3.0@5202 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-06-16 14:58:33 +00:00
parent 9c8ee46c76
commit 86f24d20e1
43 changed files with 992 additions and 360 deletions

View file

@ -1,4 +1,5 @@
#!/bin/sh
. `dirname "$0"`/../build/default/gtk2_ardour/ardev_common_waf.sh
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
exec valgrind --num-callers=50 --tool=memcheck $TOP/$EXECUTABLE --novst "$@"

View file

@ -497,8 +497,9 @@ AudioStreamView::setup_rec_box ()
}
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion>
(RegionFactory::create (sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false)));
(RegionFactory::create (sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags), false)));
assert(region);
region->block_property_changes ();
region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (make_pair(region, (RegionView*)0));
}

View file

@ -415,8 +415,9 @@ MidiStreamView::setup_rec_box ()
}
boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion>
(RegionFactory::create (sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false)));
(RegionFactory::create (sources, start, 1 , "", 0, Region::DefaultFlags, false)));
assert(region);
region->block_property_changes ();
region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (make_pair(region, (RegionView*)0));

View file

@ -1438,7 +1438,7 @@ MixerStrip::switch_io (boost::shared_ptr<Route> target)
send->set_metering (false);
}
_current_delivery = _route->send_for (target->input());
_current_delivery = _route->internal_send_for (target);
if (_current_delivery) {
send = boost::dynamic_pointer_cast<Send>(_current_delivery);

View file

@ -1143,6 +1143,14 @@ RCOptionEditor::RCOptionEditor ()
add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
add_option (_("Audio"),
new BoolOption (
"auto-connect-standard-busses",
_("Auto-connect master/monitor busses"),
mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
));
ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
"input-auto-connect",
_("Connect track and bus inputs"),

View file

@ -47,6 +47,7 @@ namespace ARDOUR {
int init (bool with_vst, bool try_optimization);
int cleanup ();
bool no_auto_connect ();
std::string get_ardour_revision ();

View file

@ -57,6 +57,13 @@ public:
_written = true;
}
/** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
void merge_from (const Buffer& src, nframes_t len, nframes_t dst_offset = 0, nframes_t src_offset = 0) {
const AudioBuffer* ab = dynamic_cast<const AudioBuffer*>(&src);
assert (ab);
accumulate_from (*ab, len, dst_offset, src_offset);
}
/** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
void accumulate_from (const AudioBuffer& src, nframes_t len, nframes_t dst_offset = 0, nframes_t src_offset = 0) {
assert(_capacity > 0);

View file

@ -76,6 +76,7 @@ public:
virtual void clear() { silence(_capacity, 0); }
virtual void read_from (const Buffer& src, nframes_t len, nframes_t dst_offset = 0, nframes_t src_offset = 0) = 0;
virtual void merge_from (const Buffer& src, nframes_t len, nframes_t dst_offset = 0, nframes_t src_offset = 0) = 0;
protected:
Buffer(DataType type, size_t capacity)

View file

@ -68,6 +68,7 @@ public:
void is_silent(bool yn) { _is_silent = yn; }
bool is_silent() const { return _is_silent; }
void silence (nframes_t nframes, nframes_t offset);
void set_count(const ChanCount& count) { assert(count <= _available); _count = count; }
@ -94,6 +95,7 @@ public:
#endif
void read_from(BufferSet& in, nframes_t nframes);
void merge_from(BufferSet& in, nframes_t nframes);
// ITERATORS
// FIXME: possible to combine these? templates?

View file

@ -40,7 +40,13 @@ public:
Main = 0x8
};
/* Delivery to an existing output */
Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
/* Delivery to a new output owned by this object */
Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);

View file

@ -0,0 +1,60 @@
/*
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_internal_return_h__
#define __ardour_internal_return_h__
#include <sigc++/signal.h>
#include "ardour/ardour.h"
#include "ardour/return.h"
#include "ardour/buffer_set.h"
namespace ARDOUR {
class InternalReturn : public Return
{
public:
InternalReturn (Session&);
InternalReturn (Session&, const XMLNode&);
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool configure_io (ChanCount in, ChanCount out);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
void set_block_size (nframes_t);
BufferSet* get_buffers();
void release_buffers();
static sigc::signal<void,nframes_t> CycleStart;
private:
BufferSet buffers;
uint32_t user_count;
void allocate_buffers (nframes_t);
void cycle_start (nframes_t);
};
} // namespace ARDOUR
#endif /* __ardour_internal_return_h__ */

View file

@ -0,0 +1,57 @@
/*
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_internal_send_h__
#define __ardour_internal_send_h__
#include "ardour/ardour.h"
#include "ardour/send.h"
namespace ARDOUR {
class InternalSend : public Send
{
public:
InternalSend (Session&, boost::shared_ptr<MuteMaster>, boost::shared_ptr<Route> send_to);
InternalSend (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&);
virtual ~InternalSend ();
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool feeds (boost::shared_ptr<Route> other) const;
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
boost::shared_ptr<Route> target_route() const { return _send_to; }
private:
BufferSet* target;
boost::shared_ptr<Route> _send_to;
PBD::ID _send_to_id;
sigc::connection connect_c;
void send_to_going_away ();
int connect_when_legal ();
};
} // namespace ARDOUR
#endif /* __ardour_send_h__ */

View file

@ -37,6 +37,7 @@ namespace ARDOUR {
class Session;
class IO;
class Route;
/** A mixer strip element (Processor) with 1 or 2 IO elements.
*/
@ -66,6 +67,8 @@ class IOProcessor : public Processor
void silence (nframes_t nframes);
virtual bool feeds (boost::shared_ptr<Route> other) const;
sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged;
sigc::signal<void,IOProcessor*,uint32_t> AutomationChanged;

View file

@ -51,6 +51,7 @@ class Metering {
class PeakMeter : public Processor {
public:
PeakMeter(Session& s) : Processor(s, "Meter") {}
PeakMeter(Session&s, const XMLNode& node);
void meter();

View file

@ -39,6 +39,7 @@ public:
void silence (nframes_t nframes, nframes_t offset = 0);
void read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offset = 0, nframes_t src_offset = 0);
void merge_from (const Buffer& src, nframes_t nframes, nframes_t dst_offset = 0, nframes_t src_offset = 0);
void copy(const MidiBuffer& copy);

View file

@ -50,6 +50,7 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
static const std::string state_node_name;
Processor(Session&, const std::string& name);
Processor(Session&, const XMLNode& node);
virtual ~Processor() { }

View file

@ -19,7 +19,7 @@
/* IO connection */
CONFIG_VARIABLE (bool, auto_connect_master, "auto-connect-master", true)
CONFIG_VARIABLE (bool, auto_connect_standard_busses, "auto-connect-standard-busses", true)
CONFIG_VARIABLE (AutoConnectOption, output_auto_connect, "output-auto-connect", AutoConnectOption (0))
CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-auto-connect", AutoConnectOption (0))

View file

@ -74,7 +74,7 @@ class Region
LeftOfSplit = 0x4000,
RightOfSplit = 0x8000,
Hidden = 0x10000,
DoNotSaveState = 0x20000,
DoNotSendPropertyChanges = 0x20000,
PositionLocked = 0x40000,
//
range_guarantoor = USHRT_MAX
@ -97,6 +97,8 @@ class Region
sigc::signal<void,Change> StateChanged;
static sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > RegionPropertyChanged;
void unlock_property_changes () { _flags = Flag (_flags & ~DoNotSendPropertyChanges); }
void block_property_changes () { _flags = Flag (_flags | DoNotSendPropertyChanges); }
virtual ~Region();
@ -160,8 +162,6 @@ class Region
void set_position_lock_style (PositionLockStyle ps);
void recompute_position_from_lock_style ();
virtual bool should_save_state () const { return !(_flags & DoNotSaveState); };
void freeze ();
void thaw (const std::string& why);

View file

@ -38,8 +38,8 @@ class PeakMeter;
class Return : public IOProcessor
{
public:
Return (Session&);
Return (Session&, const XMLNode&);
Return (Session&, bool internal = false);
Return (Session&, const XMLNode&, bool internal = false);
virtual ~Return ();
uint32_t bit_slot() const { return _bitslot; }

View file

@ -52,6 +52,7 @@ class Panner;
class Processor;
class RouteGroup;
class Send;
class InternalReturn;
class Route : public SessionObject, public AutomatableControls
{
@ -183,17 +184,16 @@ class Route : public SessionObject, public AutomatableControls
}
}
ProcessorList::iterator prefader_iterator();
ChanCount max_processor_streams () const { return processor_max_streams; }
ChanCount pre_fader_streams() const;
/* special processors */
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;
boost::shared_ptr<InternalReturn> internal_return() const { return _intreturn; }
boost::shared_ptr<Send> internal_send_for (boost::shared_ptr<const Route> target) const;
BufferSet* get_return_buffer () const;
void release_return_buffer () const;
/** A record of the stream configuration at some point in the processor list.
* Used to return where and why an processor list configuration request failed.
@ -262,10 +262,10 @@ class Route : public SessionObject, public AutomatableControls
sigc::signal<void,void*> SelectedChanged;
int listen_via (boost::shared_ptr<IO>, const std::string& name);
void drop_listen (boost::shared_ptr<IO>);
int listen_via (boost::shared_ptr<Route>, const std::string& name);
void drop_listen (boost::shared_ptr<Route>);
bool feeds (boost::shared_ptr<IO>);
bool feeds (boost::shared_ptr<Route>);
std::set<boost::shared_ptr<Route> > fed_by;
/* Controls (not all directly owned by the Route */
@ -341,6 +341,7 @@ class Route : public SessionObject, public AutomatableControls
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
boost::shared_ptr<InternalReturn> _intreturn;
Flag _flags;
int _pending_declick;
@ -381,8 +382,6 @@ class Route : public SessionObject, public AutomatableControls
virtual int _set_state (const XMLNode&, bool call_base);
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;

View file

@ -37,8 +37,8 @@ class Amp;
class Send : public Delivery
{
public:
Send (Session&, boost::shared_ptr<MuteMaster>);
Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&);
Send (Session&, boost::shared_ptr<MuteMaster>, bool internal = false);
Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&, bool internal = false);
virtual ~Send ();
uint32_t bit_slot() const { return _bitslot; }

View file

@ -747,12 +747,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
boost::shared_ptr<Route> control_out() const { return _control_out; }
boost::shared_ptr<Route> master_out() const { return _master_out; }
/* insert/send management */
uint32_t n_port_inserts() const { return _port_inserts.size(); }
uint32_t n_plugin_inserts() const { return _plugin_inserts.size(); }
uint32_t n_sends() const { return _sends.size(); }
static void set_disable_all_loaded_plugins (bool yn) {
_disable_all_loaded_plugins = yn;
}
@ -1558,16 +1552,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* INSERT AND SEND MANAGEMENT */
std::list<PortInsert *> _port_inserts;
std::list<PluginInsert *> _plugin_inserts;
std::list<Send *> _sends;
std::list<Return *> _returns;
boost::dynamic_bitset<uint32_t> send_bitset;
boost::dynamic_bitset<uint32_t> return_bitset;
boost::dynamic_bitset<uint32_t> insert_bitset;
uint32_t send_cnt;
uint32_t insert_cnt;
void add_processor (Processor *);
void remove_processor (Processor *);

View file

@ -31,23 +31,23 @@
#include "midi++/jack.h"
#include "ardour/amp.h"
#include "ardour/audio_port.h"
#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"
#include "ardour/event_type_map.h"
#include "ardour/io.h"
#include "ardour/amp.h"
#include "ardour/port_set.h"
#include "ardour/buffer_set.h"
#include "ardour/cycle_timer.h"
#include "ardour/delivery.h"
#include "ardour/event_type_map.h"
#include "ardour/internal_return.h"
#include "ardour/io.h"
#include "ardour/meter.h"
#include "ardour/midi_port.h"
#include "ardour/port.h"
#include "ardour/port_set.h"
#include "ardour/session.h"
#include "ardour/timestamps.h"
#include "ardour/utils.h"
#include "i18n.h"
@ -364,6 +364,7 @@ AudioEngine::process_callback (nframes_t nframes)
Delivery::CycleStart (nframes);
Port::set_port_offset (0);
InternalReturn::CycleStart (nframes);
/* tell all Ports that we're starting a new cycle */
@ -822,10 +823,15 @@ AudioEngine::frames_per_cycle ()
Port *
AudioEngine::get_port_by_name (const string& portname)
{
assert (portname.find_first_of (':') != string::npos);
string s;
if (portname.find_first_of (':') == string::npos) {
s = make_port_name_non_relative (portname);
} else {
s = portname;
}
Glib::Mutex::Lock lm (_process_lock);
return get_port_by_name_locked (portname);
return get_port_by_name_locked (s);
}
Port *

View file

@ -655,6 +655,14 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
_flags = Flag (_flags & ~Region::RightOfSplit);
}
/* leave this flag setting in place, no matter what */
if ((old_flags & DoNotSendPropertyChanges)) {
_flags = Flag (_flags | DoNotSendPropertyChanges);
}
/* find out if any flags changed that we signal about */
if ((old_flags ^ _flags) & Muted) {
what_changed = Change (what_changed|MuteChanged);
}

View file

@ -225,5 +225,32 @@ BufferSet::read_from (BufferSet& in, nframes_t nframes)
set_count(in.count());
}
// FIXME: make 'in' const
void
BufferSet::merge_from (BufferSet& in, nframes_t nframes)
{
assert(available() >= in.count());
/* merge all input buffers into out existing buffers */
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
BufferSet::iterator o = begin(*t);
for (BufferSet::iterator i = in.begin(*t); i != in.end(*t); ++i, ++o) {
o->merge_from (*i, nframes);
}
}
set_count (in.count());
}
void
BufferSet::silence (nframes_t nframes, nframes_t offset)
{
for (std::vector<BufferVec>::iterator i = _buffers.begin(); i != _buffers.end(); ++i) {
for (BufferVec::iterator b = i->begin(); b != i->end(); ++b) {
(*b)->silence (nframes, offset);
}
}
}
} // namespace ARDOUR

View file

@ -47,7 +47,7 @@ bool Delivery::panners_legal = false;
/* deliver to an existing IO object */
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)
: IOProcessor(s, boost::shared_ptr<IO>(), (r == Listen ? boost::shared_ptr<IO>() : io), name)
, _role (r)
, _output_buffers (new BufferSet())
, _solo_level (0)
@ -58,13 +58,15 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Mute
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
if (_output) {
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
}
/* deliver to a new IO object */
Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
: IOProcessor(s, false, true, name)
: IOProcessor(s, false, (r == Listen ? false : true), name)
, _role (r)
, _output_buffers (new BufferSet())
, _solo_level (0)
@ -75,8 +77,10 @@ Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string&
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
if (_output) {
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
}
/* deliver to a new IO object, reconstruct from XML */
@ -96,8 +100,33 @@ Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode&
throw failed_constructor ();
}
if (_output) {
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
}
/* deliver to an existing IO object, reconstruct from XML */
Delivery::Delivery (Session& s, boost::shared_ptr<IO> out, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: IOProcessor (s, boost::shared_ptr<IO>(), out, "reset")
, _role (Role (0))
, _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 ();
}
if (_output) {
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
}
}
void
Delivery::cycle_start (nframes_t nframes)
@ -265,7 +294,16 @@ Delivery::reset_panner ()
{
if (panners_legal) {
if (!no_panner_reset) {
_panner->reset (_output->n_ports().n_audio(), pans_required());
uint32_t ntargets;
if (_output) {
ntargets = _output->n_ports().n_audio();
} else {
ntargets = _configured_output.n_audio();
}
_panner->reset (ntargets, pans_required());
}
} else {
panner_legal_c.disconnect ();
@ -276,7 +314,15 @@ Delivery::reset_panner ()
int
Delivery::panners_became_legal ()
{
_panner->reset (_output->n_ports().n_audio(), pans_required());
uint32_t ntargets;
if (_output) {
ntargets = _output->n_ports().n_audio();
} else {
ntargets = _configured_output.n_audio();
}
_panner->reset (ntargets, pans_required());
_panner->load (); // automation
panner_legal_c.disconnect ();
return 0;
@ -441,3 +487,4 @@ Delivery::output_changed (IOChange change, void* src)
reset_panner ();
}
}

View file

@ -396,7 +396,7 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Region, LeftOfSplit);
REGISTER_CLASS_ENUM (Region, RightOfSplit);
REGISTER_CLASS_ENUM (Region, Hidden);
REGISTER_CLASS_ENUM (Region, DoNotSaveState);
REGISTER_CLASS_ENUM (Region, DoNotSendPropertyChanges);
REGISTER_BITS (_Region_Flag);
REGISTER_CLASS_ENUM (Region, AudioTime);

View file

@ -430,6 +430,12 @@ ARDOUR::find_bindings_files (map<string,string>& files)
}
}
bool
ARDOUR::no_auto_connect()
{
return getenv ("ARDOUR_NO_AUTOCONNECT") != 0;
}
ARDOUR::LocaleGuard::LocaleGuard (const char* str)
{
old = strdup (setlocale (LC_NUMERIC, NULL));

View file

@ -0,0 +1,136 @@
/*
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 <glibmm/thread.h>
#include "pbd/failed_constructor.h"
#include "ardour/internal_return.h"
#include "ardour/mute_master.h"
#include "ardour/session.h"
using namespace std;
using namespace ARDOUR;
sigc::signal<void,nframes_t> InternalReturn::CycleStart;
InternalReturn::InternalReturn (Session& s)
: Return (s, true)
, user_count (0)
{
CycleStart.connect (mem_fun (*this, &InternalReturn::cycle_start));
}
InternalReturn::InternalReturn (Session& s, const XMLNode& node)
: Return (s, node, true)
, user_count (0)
{
CycleStart.connect (mem_fun (*this, &InternalReturn::cycle_start));
}
void
InternalReturn::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (user_count == 0) {
/* nothing to do - nobody is feeding us anything */
return;
}
/* XXX this should be merge() */
bufs.merge_from (buffers, nframes);
}
bool
InternalReturn::configure_io (ChanCount in, ChanCount out)
{
IOProcessor::configure_io (in, out);
allocate_buffers (_session.get_block_size());
return true;
}
void
InternalReturn::set_block_size (nframes_t nframes)
{
allocate_buffers (nframes);
}
void
InternalReturn::allocate_buffers (nframes_t nframes)
{
buffers.ensure_buffers (DataType::AUDIO, _configured_input.n_audio(), nframes);
buffers.ensure_buffers (DataType::MIDI, _configured_input.n_midi(), nframes);
}
BufferSet*
InternalReturn::get_buffers ()
{
Glib::Mutex::Lock lm (_session.engine().process_lock());
user_count++;
return &buffers;
}
void
InternalReturn::release_buffers ()
{
Glib::Mutex::Lock lm (_session.engine().process_lock());
if (user_count) {
user_count--;
}
}
void
InternalReturn::cycle_start (nframes_t nframes)
{
/* called from process cycle - no lock necessary */
if (user_count) {
/* don't bother with this if nobody is going to feed us anything */
buffers.silence (nframes, 0);
}
}
XMLNode&
InternalReturn::state (bool full)
{
XMLNode& node (Return::state (full));
/* override type */
node.add_property("type", "intreturn");
return node;
}
XMLNode&
InternalReturn::get_state()
{
return state (true);
}
int
InternalReturn::set_state (const XMLNode& node)
{
return Return::set_state (node);
}
bool
InternalReturn::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
out = in;
return true;
}

View file

@ -0,0 +1,192 @@
/*
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 <iostream>
#include "pbd/error.h"
#include "pbd/failed_constructor.h"
#include "ardour/amp.h"
#include "ardour/internal_send.h"
#include "ardour/meter.h"
#include "ardour/route.h"
#include "ardour/session.h"
#include "i18n.h"
using namespace PBD;
using namespace ARDOUR;
InternalSend::InternalSend (Session& s, boost::shared_ptr<MuteMaster> mm, boost::shared_ptr<Route> sendto)
: Send (s, mm, true)
, _send_to (sendto)
{
if ((target = _send_to->get_return_buffer ()) == 0) {
throw failed_constructor();
}
_send_to->GoingAway.connect (mem_fun (*this, &InternalSend::send_to_going_away));
}
InternalSend::InternalSend (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: Send (s, mm, node, true)
{
set_state (node);
}
InternalSend::~InternalSend ()
{
if (_send_to) {
_send_to->release_return_buffer ();
}
connect_c.disconnect ();
}
void
InternalSend::send_to_going_away ()
{
target = 0;
_send_to.reset ();
_send_to_id = "0";
}
void
InternalSend::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (!_active || !target || !_send_to) {
_meter->reset ();
return;
}
// we have to copy the input, because we may alter the buffers with the amp
// 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 (sendbufs, start_frame, end_frame, nframes);
/* consider metering */
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run (sendbufs, start_frame, end_frame, nframes);
}
}
/* deliver to target */
target->merge_from (sendbufs, nframes);
}
bool
InternalSend::feeds (boost::shared_ptr<Route> other) const
{
return _send_to == other;
}
XMLNode&
InternalSend::state (bool full)
{
XMLNode& node (Send::state (full));
/* this replaces any existing property */
node.add_property ("type", "intsend");
if (_send_to) {
node.add_property ("target", _send_to->id().to_s());
}
return node;
}
XMLNode&
InternalSend::get_state()
{
return state (true);
}
int
InternalSend::set_state (const XMLNode& node)
{
const XMLProperty* prop;
if ((prop = node.property ("target")) != 0) {
_send_to_id = prop->value();
/* if we're loading a session, the target route may not have been
create yet. make sure we defer till we are sure that it should
exist.
*/
if (!IO::connecting_legal) {
connect_c = IO::ConnectingLegal.connect (mem_fun (*this, &InternalSend::connect_when_legal));
std::cerr << "connect later!\n";
} else {
std::cerr << "connect NOW!\n";
connect_when_legal ();
}
}
return 0;
}
int
InternalSend::connect_when_legal ()
{
std::cerr << "IOP/send connecting now that its legal\n";
connect_c.disconnect ();
if (_send_to_id == "0") {
/* it vanished before we could connect */
return 0;
}
if ((_send_to = _session.route_by_id (_send_to_id)) == 0) {
error << X_("cannot find route to connect to") << endmsg;
std::cerr << "cannot find route with ID " << _send_to_id << std::endl;
} else {
std::cerr << "got target send as " << _send_to << std::endl;
}
if ((target = _send_to->get_return_buffer ()) == 0) {
error << X_("target for internal send has no return buffer") << endmsg;
}
return 0;
}
bool
InternalSend::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
out = in;
return true;
}

View file

@ -64,6 +64,8 @@ IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
if (with_output) {
_output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype));
}
cerr << "fresh create IOP name = " << proc_name << " in = " << _input << " out = " << _output << endl;
}
/* create an IOProcessor that proxies to an existing IO object */
@ -74,8 +76,18 @@ IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_pt
, _input (in)
, _output (out)
{
cerr << "XML create IOP name = " << proc_name << " in = " << in << " out = " << out << endl;
if (in) {
_own_input = false;
} else {
_own_input = true;
}
if (out) {
_own_output = false;
} else {
_own_output = true;
}
}
IOProcessor::~IOProcessor ()
@ -107,10 +119,12 @@ IOProcessor::state (bool full_state)
XMLNode& node (Processor::state (full_state));
if (_own_input) {
node.add_property ("own-input", "yes");
if (_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-input", "no");
if (_input) {
@ -119,10 +133,12 @@ IOProcessor::state (bool full_state)
}
if (_own_output) {
node.add_property ("own-output", "yes");
if (_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) {
@ -173,9 +189,9 @@ IOProcessor::set_state (const XMLNode& node)
}
} else {
error << _("XML node describing an IOProcessor is missing an IO node") << endmsg;
return -1;
/* no input */
}
}
if (_own_output) {
@ -193,6 +209,8 @@ IOProcessor::set_state (const XMLNode& node)
if ((prop = node.property ("name")) == 0) {
set_name (_output->name());
}
} else {
/* no output */
}
}
@ -246,3 +264,9 @@ IOProcessor::set_name (const std::string& name)
return ret;
}
bool
IOProcessor::feeds (boost::shared_ptr<Route> other) const
{
return _output && _output->connected_to (other->input());
}

View file

@ -109,6 +109,11 @@ PeakMeter::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nfr
}
}
PeakMeter::PeakMeter (Session& s, const XMLNode& node)
: Processor (s, node)
{
}
void
PeakMeter::reset ()
{

View file

@ -99,6 +99,17 @@ MidiBuffer::read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offse
_silent = src.silent();
}
void
MidiBuffer::merge_from (const Buffer& src, nframes_t nframes, nframes_t dst_offset, nframes_t src_offset)
{
const MidiBuffer* mbuf = dynamic_cast<const MidiBuffer*>(&src);
assert (mbuf);
assert (mbuf != this);
/* XXX use nframes, and possible offsets */
merge_in_place (*mbuf);
}
/** Push an event into the buffer.
*
* Note that the raw MIDI pointed to by ev will be COPIED and unmodified.

View file

@ -1379,7 +1379,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes
if (inbufs.count().n_audio() > 0) {
BufferSet::audio_iterator i = inbufs.audio_begin();
for (++i; i != inbufs.audio_end(); ++i) {
dst.accumulate_from(*i, nframes);
dst.merge_from(*i, nframes);
}
}
@ -1456,7 +1456,7 @@ Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sfram
// accumulate starting with the second
BufferSet::audio_iterator i = inbufs.audio_begin();
for (++i; i != inbufs.audio_end(); ++i) {
dst.accumulate_from(*i, nframes);
dst.merge_from(*i, nframes);
}
return;

View file

@ -68,6 +68,17 @@ Processor::Processor(Session& session, const string& name)
{
}
Processor::Processor (Session& session, const XMLNode& node)
: SessionObject(session, "renameMe")
, AutomatableControls(session)
, _active(false)
, _next_ab_is_active(false)
, _configured(false)
, _gui(0)
{
set_state (node);
}
XMLNode&
Processor::get_state (void)
{
@ -141,6 +152,9 @@ Processor::set_state (const XMLNode& node)
// may not exist for legacy 3.0 sessions
if ((prop = node.property ("id")) != 0) {
_id = prop->value();
cerr << "---------------- ID for processor " << name() << " = " << _id << endl;
} else {
cerr << "---------------- NO ID for processor " << name() << endl;
}
XMLNodeList nlist = node.children();

View file

@ -61,7 +61,7 @@ sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChan
Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: SessionObject(s, name)
, _type(type)
, _flags(flags)
, _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start)
, _length(length)
, _position(0)
@ -86,7 +86,7 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: SessionObject(src->session(), name)
, _type(type)
, _flags(flags)
, _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start)
, _length(length)
, _position(0)
@ -119,7 +119,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: SessionObject(srcs.front()->session(), name)
, _type(type)
, _flags(flags)
, _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start)
, _length(length)
, _position(0)
@ -150,6 +150,8 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
_start = other->_start + offset;
copy_stuff (other, offset, length, name, layer, flags);
_flags = Flag (_flags | DoNotSendPropertyChanges);
/* if the other region had a distinct sync point
set, then continue to use it as best we can.
otherwise, reset sync point back to start.
@ -188,6 +190,8 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const s
_start = 0;
copy_stuff (other, 0, length, name, layer, flags);
_flags = Flag (_flags | DoNotSendPropertyChanges);
/* sync pos is relative to start of file. our start-in-file is now zero,
so set our sync position to whatever the the difference between
_start and _sync_pos was in the other region.
@ -253,6 +257,8 @@ Region::Region (boost::shared_ptr<const Region> other)
, _pending_changed(Change(0))
, _last_layer_op(other->_last_layer_op)
{
_flags = Flag (_flags | DoNotSendPropertyChanges);
other->_first_edit = EditChangesName;
if (other->_extra_xml) {
@ -268,7 +274,7 @@ Region::Region (boost::shared_ptr<const Region> other)
Region::Region (const SourceList& srcs, const XMLNode& node)
: SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL) // to be loaded from XML
, _flags(Flag(0))
, _flags(DoNotSendPropertyChanges)
, _start(0)
, _length(0)
, _position(0)
@ -297,7 +303,7 @@ Region::Region (const SourceList& srcs, const XMLNode& node)
Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
: SessionObject(src->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL)
, _flags(Flag(0))
, _flags(DoNotSendPropertyChanges)
, _start(0)
, _length(0)
, _position(0)
@ -1400,7 +1406,7 @@ Region::send_change (Change what_changed)
StateChanged (what_changed);
if (!(_flags & DoNotSaveState)) {
if (!(_flags & DoNotSendPropertyChanges)) {
/* Try and send a shared_pointer unless this is part of the constructor.
If so, do nothing.

View file

@ -47,6 +47,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
AudioRegion* ar = new AudioRegion (other_a, start, length, name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
@ -55,6 +56,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
MidiRegion* ar = new MidiRegion (other_m, start, length, name, layer, flags);
boost::shared_ptr<MidiRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
@ -75,10 +77,12 @@ RegionFactory::create (boost::shared_ptr<const Region> region)
if ((ar = boost::dynamic_pointer_cast<const AudioRegion>(region)) != 0) {
boost::shared_ptr<Region> ret (new AudioRegion (ar));
ret->unlock_property_changes ();
/* pure copy constructor - no CheckNewRegion emitted */
return ret;
} else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) {
boost::shared_ptr<Region> ret (new MidiRegion (mr));
ret->unlock_property_changes ();
/* pure copy constructor - no CheckNewRegion emitted */
return ret;
} else {
@ -112,6 +116,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, const SourceList& srcs,
AudioRegion* ar = new AudioRegion (other, srcs, srcs.front()->length(srcs.front()->timeline_position()), name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
@ -128,6 +133,7 @@ boost::shared_ptr<Region>
RegionFactory::create (Session& session, XMLNode& node, bool yn)
{
boost::shared_ptr<Region> r = session.XMLRegionFactory (node, yn);
r->unlock_property_changes ();
if (r) {
CheckNewRegion (r);
@ -148,6 +154,7 @@ RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length
AudioRegion* ar = new AudioRegion (srcs, start, length, name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
@ -158,6 +165,7 @@ RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length
MidiRegion* ar = new MidiRegion (srcs, start, length, name, layer, flags);
boost::shared_ptr<MidiRegion> mrp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (mrp));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
@ -177,10 +185,12 @@ RegionFactory::create (SourceList& srcs, const XMLNode& node)
if (srcs[0]->type() == DataType::AUDIO) {
boost::shared_ptr<Region> ret (new AudioRegion (srcs, node));
ret->unlock_property_changes ();
CheckNewRegion (ret);
return ret;
} else if (srcs[0]->type() == DataType::MIDI) {
boost::shared_ptr<Region> ret (new MidiRegion (srcs, node));
ret->unlock_property_changes ();
CheckNewRegion (ret);
return ret;
}
@ -196,12 +206,14 @@ RegionFactory::create (boost::shared_ptr<Source> src, nframes_t start, nframes_t
if ((as = boost::dynamic_pointer_cast<AudioSource>(src)) != 0) {
boost::shared_ptr<Region> ret (new AudioRegion (as, start, length, name, layer, flags));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}
return ret;
} else if ((ms = boost::dynamic_pointer_cast<MidiSource>(src)) != 0) {
boost::shared_ptr<Region> ret (new MidiRegion (ms, start, length, name, layer, flags));
ret->unlock_property_changes ();
if (announce) {
CheckNewRegion (ret);
}

View file

@ -36,8 +36,9 @@
using namespace ARDOUR;
using namespace PBD;
Return::Return (Session& s)
: IOProcessor (s, true, false, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
Return::Return (Session& s, bool internal)
: IOProcessor (s, (internal ? false : true), false,
string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
, _metering (false)
{
/* never muted */
@ -48,8 +49,8 @@ Return::Return (Session& s)
ProcessorCreated (this); /* EMIT SIGNAL */
}
Return::Return (Session& s, const XMLNode& node)
: IOProcessor (s, true, false, "return")
Return::Return (Session& s, const XMLNode& node, bool internal)
: IOProcessor (s, (internal ? false : true), false, "return")
, _metering (false)
{
/* never muted */

View file

@ -38,6 +38,8 @@
#include "ardour/configuration.h"
#include "ardour/cycle_timer.h"
#include "ardour/dB.h"
#include "ardour/internal_send.h"
#include "ardour/internal_return.h"
#include "ardour/ladspa_plugin.h"
#include "ardour/meter.h"
#include "ardour/mix.h"
@ -73,6 +75,24 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
{
init ();
/* add standard processors other than amp (added by ::init()) */
_meter.reset (new PeakMeter (_session));
add_processor (_meter, PreFader);
if (_flags & ControlOut) {
/* where we listen to tracks */
_intreturn.reset (new InternalReturn (_session));
add_processor (_intreturn, PreFader);
}
_main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
add_processor (_main_outs, PostFader);
/* now that we have _meter, its safe to connect to this */
_meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
Route::Route (Session& sess, const XMLNode& node, DataType default_type)
@ -83,7 +103,12 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
, _default_type (default_type)
{
init ();
_set_state (node, false);
/* now that we have _meter, its safe to connect to this */
_meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
void
@ -123,20 +148,10 @@ Route::init ()
_input->changed.connect (mem_fun (this, &Route::input_change_handler));
_output->changed.connect (mem_fun (this, &Route::output_change_handler));
/* add standard processors */
/* add amp processor */
_amp.reset (new Amp (_session, _mute_master));
add_processor (_amp, PostFader);
_meter.reset (new PeakMeter (_session));
add_processor (_meter, PreFader);
_main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
add_processor (_main_outs, PostFader);
/* now we can meter */
_meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
Route::~Route ()
@ -316,7 +331,7 @@ Route::process_output_buffers (BufferSet& bufs,
switch (Config->get_monitoring_model()) {
case HardwareMonitoring:
case ExternalMonitoring:
monitor = record_enabled() && (_session.config.get_auto_input() || _session.actively_recording());
monitor = !record_enabled() || (_session.config.get_auto_input() && !_session.actively_recording());
break;
default:
monitor = true;
@ -327,13 +342,13 @@ Route::process_output_buffers (BufferSet& bufs,
}
/* figure out if we're going to use gain automation */
_amp->setup_gain_automation (start_frame, end_frame, nframes);
/* tell main outs what to do about monitoring */
/* tell main outs what to do about monitoring */
_main_outs->no_outs_cuz_we_no_monitor (!monitor);
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
----------------------------------------------------------------------------------------- */
@ -520,25 +535,16 @@ Route::muted() const
return _mute_master->muted ();
}
#if DEFINE_IF_YOU_NEED_THIS
static void
dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
{
cerr << name << " {" << endl;
for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
p != procs.end(); ++p) {
cerr << "\t" << (*p)->name() << endl;
cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << endl;
}
cerr << "}" << endl;
}
#endif
Route::ProcessorList::iterator
Route::prefader_iterator()
{
Glib::RWLock::ReaderLock lm (_processor_lock);
return find (_processors.begin(), _processors.end(), _amp);
}
int
Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err)
@ -615,6 +621,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
loc = iter;
}
cerr << "Adding " << processor->name() << " @ " << processor << endl;
_processors.insert (loc, processor);
// Set up processor list channels. This will set processor->[input|output]_streams(),
@ -626,6 +634,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
--ploc;
_processors.erase(ploc);
configure_processors_unlocked (0); // it worked before we tried to add it ...
cerr << "configure failed\n";
return -1;
}
@ -660,6 +669,7 @@ bool
Route::add_processor_from_xml (const XMLNode& node, Placement placement)
{
ProcessorList::iterator loc;
if (placement == PreFader) {
/* generic pre-fader: insert immediately before the amp */
loc = find(_processors.begin(), _processors.end(), _amp);
@ -699,7 +709,6 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
cerr << _name << " : got processor type " << prop->value() << endl;
boost::shared_ptr<Processor> processor;
bool have_insert = false;
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
@ -707,7 +716,6 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
prop->value() == "audiounit") {
processor.reset (new PluginInsert(_session, node));
have_insert = true;
} else if (prop->value() == "port") {
@ -716,32 +724,66 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
} else if (prop->value() == "send") {
processor.reset (new Send (_session, _mute_master, node));
have_insert = true;
} else if (prop->value() == "meter") {
if (_meter) {
if (_meter->set_state (node)) {
return false;
} else {
return true;
}
}
_meter.reset (new PeakMeter (_session, node));
processor = _meter;
processor->set_state (node);
} else if (prop->value() == "amp") {
/* amp always exists */
processor = _amp;
processor->set_state (node);
if (processor->set_state (node)) {
return false;
} else {
/* never any reason to add it */
return true;
}
} else if (prop->value() == "listen" || prop->value() == "deliver") {
/* XXX need to generalize */
processor = _control_outs;
processor->set_state (node);
} else if (prop->value() == "intsend") {
processor.reset (new InternalSend (_session, _mute_master, node));
} else if (prop->value() == "intreturn") {
if (_intreturn) {
if (_intreturn->set_state (node)) {
return false;
} else {
return true;
}
}
_intreturn.reset (new InternalReturn (_session, node));
processor = _intreturn;
} else if (prop->value() == "main-outs") {
if (_main_outs) {
if (_main_outs->set_state (node)) {
return false;
} else {
return true;
}
}
_main_outs.reset (new Delivery (_session, _output, _mute_master, node));
processor = _main_outs;
processor->set_state (node);
} else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
}
@ -997,31 +1039,6 @@ Route::ab_plugins (bool forward)
}
/* Figure out the streams that will feed into PreFader */
ChanCount
Route::pre_fader_streams() const
{
boost::shared_ptr<Processor> processor;
/* Find the last pre-fader redirect that isn't a send; sends don't affect the number
* of streams. */
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i) == _amp) {
break;
}
if (boost::dynamic_pointer_cast<Send> (*i) == 0) {
processor = *i;
}
}
if (processor) {
return processor->output_streams();
} else {
return _input->n_ports ();
}
}
/** Remove processors with a given placement.
* @param p Placement of processors to remove.
*/
@ -1195,7 +1212,11 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
ChanCount out;
list< pair<ChanCount,ChanCount> > configuration;
uint32_t index = 0;
cerr << "Processor check with " << _processors.size() << endl;
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
cerr << "Checking out " << (*p)->name() << " type = " << endl;
if ((*p)->can_support_io_configuration(in, out)) {
configuration.push_back(make_pair(in, out));
in = out;
@ -1489,6 +1510,34 @@ Route::_set_state (const XMLNode& node, bool call_base)
_flags = Flag (0);
}
/* add all processors (except amp, which is always present) */
nlist = node.children();
XMLNode processor_state (X_("processor_state"));
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
if (child->name() == IO::state_node_name) {
if ((prop = child->property (X_("direction"))) == 0) {
continue;
}
if (prop->value() == "Input") {
_input->set_state (*child);
} else if (prop->value() == "Output") {
_output->set_state (*child);
}
}
if (child->name() == X_("Processor")) {
processor_state.add_child_copy (*child);
}
}
set_processor_state (processor_state);
if ((prop = node.property (X_("phase-invert"))) != 0) {
set_phase_invert (prop->value()=="yes"?true:false);
}
@ -1555,32 +1604,6 @@ Route::_set_state (const XMLNode& node, bool call_base)
}
}
nlist = node.children();
XMLNode processor_state (X_("processor_state"));
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
if (child->name() == IO::state_node_name) {
if ((prop = child->property (X_("direction"))) == 0) {
continue;
}
if (prop->value() == "Input") {
_input->set_state (*child);
} else if (prop->value() == "Output") {
_output->set_state (*child);
}
}
if (child->name() == X_("Processor")) {
processor_state.add_child_copy (*child);
}
}
set_processor_state (processor_state);
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
@ -1642,13 +1665,21 @@ Route::set_processor_state (const XMLNode& node)
{
const XMLNodeList &nlist = node.children();
XMLNodeConstIterator niter;
bool has_meter_processor = false; // legacy sessions don't
ProcessorList::iterator i, o;
cerr << _name << " _set_processor_states\n";
dump_processors ("set processor states", _processors);
// Iterate through existing processors, remove those which are not in the state list
for (i = _processors.begin(); i != _processors.end(); ) {
/* leave amp alone, always */
if ((*i) == _amp) {
++i;
continue;
}
ProcessorList::iterator tmp = i;
++tmp;
@ -1657,6 +1688,7 @@ Route::set_processor_state (const XMLNode& node)
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
XMLProperty* id_prop = (*niter)->property(X_("id"));
cerr << "\tchecking " << id_prop->value() << endl;
if (id_prop && (*i)->id() == id_prop->value()) {
processorInStateList = true;
break;
@ -1672,22 +1704,20 @@ Route::set_processor_state (const XMLNode& node)
// Iterate through state list and make sure all processors are on the track and in the correct order,
// set the state of existing processors according to the new state on the same go
i = _processors.begin();
for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
XMLProperty* prop = (*niter)->property ("type");
if (prop && prop->value() == "meter") {
has_meter_processor = true;
}
o = i;
if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") {
// Check whether the next processor in the list
// Check whether the next processor in the list is the right one,
// except for "amp" which is always there and may not have the
// old ID since it is always created anew in every Route
if (prop->value() != "amp") {
while (o != _processors.end()) {
XMLProperty* id_prop = (*niter)->property(X_("id"));
if (id_prop && (*o)->id() == id_prop->value()) {
@ -1700,6 +1730,7 @@ Route::set_processor_state (const XMLNode& node)
// If the processor (*niter) is not on the route,
// create it and move it to the correct location
if (o == _processors.end()) {
if (add_processor_from_xml (**niter, i)) {
@ -1708,9 +1739,10 @@ Route::set_processor_state (const XMLNode& node)
cerr << "Error restoring route: unable to restore processor" << endl;
}
} else {
// Otherwise, the processor already exists; just
// ensure it is at the location provided in the XML state
} else {
if (i != o) {
boost::shared_ptr<Processor> tmp = (*o);
@ -1719,6 +1751,8 @@ Route::set_processor_state (const XMLNode& node)
--i; // move iterator to the correct processor
}
// and make it (just) so
(*i)->set_state (**niter);
}
}
@ -1727,10 +1761,6 @@ Route::set_processor_state (const XMLNode& node)
the XML state represents a working signal route.
*/
if (!has_meter_processor) {
set_meter_point (_meter_point, NULL);
}
processors_changed ();
}
@ -1772,33 +1802,38 @@ Route::silence (nframes_t nframes)
}
}
boost::shared_ptr<Delivery>
Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
BufferSet*
Route::get_return_buffer () const
{
string name = _name;
name += '[';
name += listen_name;
name += ']';
Glib::RWLock::ReaderLock rm (_processor_lock);
boost::shared_ptr<Delivery> listener (new Delivery (_session, _mute_master, name, Delivery::Listen));
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
/* As an IO, our control outs need as many IO outputs as we have outputs
* (we track the changes in ::output_change_handler()).
* As a processor, the listener is an identity processor
* (i.e. it does not modify its input buffers whatsoever)
*/
if (listener->output()->ensure_io (n_outputs(), true, this)) {
return boost::shared_ptr<Delivery>();
if (d) {
return d->get_buffers ();
}
}
add_processor (listener, PostFader);
return 0;
}
return listener;
void
Route::release_return_buffer () const
{
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
if (d) {
return d->release_buffers ();
}
}
}
int
Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
Route::listen_via (boost::shared_ptr<Route> route, const string& listen_name)
{
vector<string> ports;
vector<string>::const_iterator i;
@ -1807,71 +1842,58 @@ Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<const Delivery> d = boost::dynamic_pointer_cast<const Delivery>(*x);
boost::shared_ptr<const InternalSend> d = boost::dynamic_pointer_cast<const InternalSend>(*x);
if (d && d->output() == io) {
if (d && d->target_route() == route) {
/* already listening via the specified IO: do nothing */
return 0;
}
}
}
uint32_t ni = io->n_ports().n_total();
boost::shared_ptr<InternalSend> listener;
for (uint32_t n = 0; n < ni; ++n) {
ports.push_back (io->nth (n)->name());
}
try {
listener.reset (new InternalSend (_session, _mute_master, route));
if (ports.empty()) {
return 0;
}
} catch (failed_constructor& err) {
boost::shared_ptr<Delivery> listen_point = add_listener (io, listen_name);
/* XXX hack for now .... until we can generalize listen points */
_control_outs = listen_point;
/* now connect to the named ports */
ni = listen_point->output()->n_ports().n_total();
size_t psize = ports.size();
for (size_t n = 0; n < ni; ++n) {
if (listen_point->output()->connect (listen_point->output()->nth (n), ports[n % psize], this)) {
error << string_compose (_("could not connect %1 to %2"),
listen_point->output()->nth (n)->name(), ports[n % psize]) << endmsg;
return -1;
}
}
add_processor (listener, PreFader);
return 0;
}
void
Route::drop_listen (boost::shared_ptr<IO> io)
Route::drop_listen (boost::shared_ptr<Route> route)
{
ProcessorStreams err;
ProcessorList::iterator tmp;
Glib::RWLock::ReaderLock rm (_processor_lock);
Glib::RWLock::ReaderLock rl(_processor_lock);
rl.acquire ();
again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
tmp = x;
++tmp;
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x);
if (d && d->output() == io) {
/* already listening via the specified IO: do nothing */
if (d && d->target_route() == route) {
rl.release ();
remove_processor (*x, &err);
rl.acquire ();
/* list could have been demolished while we dropped the lock
so start over.
*/
goto again;
}
}
x = tmp;
}
rl.release ();
}
void
@ -1939,25 +1961,30 @@ Route::set_comment (string cmt, void *src)
}
bool
Route::feeds (boost::shared_ptr<IO> other)
Route::feeds (boost::shared_ptr<Route> other)
{
if (_output->connected_to (other)) {
// cerr << _name << endl;
if (_output->connected_to (other->input())) {
// cerr << "\tdirect FEEDS " << other->name() << endl;
return true;
}
/* check IOProcessors which may also interconnect Routes */
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
boost::shared_ptr<IOProcessor> iop;
if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) {
if (iop->output() && iop->output()->connected_to (other)) {
if (iop->feeds (other)) {
// cerr << "\tIOP " << iop->name() << " feeds " << other->name() << endl;
return true;
} else {
// cerr << "\tIOP " << iop->name() << " does NOT feeds " << other->name() << endl;
}
}
}
// cerr << "\tdoes NOT FEED " << other->name() << endl;
return false;
}
@ -2418,15 +2445,15 @@ Route::set_name (const string& str)
}
boost::shared_ptr<Send>
Route::send_for (boost::shared_ptr<const IO> target) const
Route::internal_send_for (boost::shared_ptr<const Route> target) const
{
Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<Send> send;
boost::shared_ptr<InternalSend> send;
if ((send = boost::dynamic_pointer_cast<Send>(*i)) != 0) {
if (send->output()->connected_to (target)) {
if ((send = boost::dynamic_pointer_cast<InternalSend>(*i)) != 0) {
if (send->target_route() == target) {
return send;
}
}

View file

@ -36,8 +36,9 @@
using namespace ARDOUR;
using namespace PBD;
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
: Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, bool internal)
: Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1),
(internal ? Delivery::Listen : Delivery::Send))
, _metering (false)
{
_amp.reset (new Amp (_session, _mute_master));
@ -46,8 +47,8 @@ Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
ProcessorCreated (this); /* EMIT SIGNAL */
}
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: Delivery (s, mm, "send", Delivery::Send)
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node, bool internal)
: Delivery (s, mm, "send", (internal ? Delivery::Listen : Delivery::Send))
, _metering (false)
{
_amp.reset (new Amp (_session, _mute_master));
@ -113,6 +114,7 @@ Send::state(bool full)
{
XMLNode& node = IOProcessor::state(full);
char buf[32];
node.add_property ("type", "send");
snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot);
node.add_property ("bitslot", buf);

View file

@ -294,6 +294,11 @@ Session::Session (AudioEngine &eng,
}
if (no_auto_connect()) {
input_ac = AutoConnectOption (0);
output_ac = AutoConnectOption (0);
}
Config->set_input_auto_connect (input_ac);
Config->set_output_auto_connect (output_ac);
@ -607,6 +612,8 @@ Session::when_engine_running ()
it doesn't really scale that well to higher channel counts
*/
/* mono output bundles */
for (uint32_t np = 0; np < n_physical_outputs; ++np) {
char buf[32];
snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
@ -618,6 +625,8 @@ Session::when_engine_running ()
add_bundle (c);
}
/* stereo output bundles */
for (uint32_t np = 0; np < n_physical_outputs; np += 2) {
if (np + 1 < n_physical_outputs) {
char buf[32];
@ -632,6 +641,8 @@ Session::when_engine_running ()
}
}
/* mono input bundles */
for (uint32_t np = 0; np < n_physical_inputs; ++np) {
char buf[32];
snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
@ -643,6 +654,8 @@ Session::when_engine_running ()
add_bundle (c);
}
/* stereo input bundles */
for (uint32_t np = 0; np < n_physical_inputs; np += 2) {
if (np + 1 < n_physical_inputs) {
char buf[32];
@ -658,14 +671,13 @@ Session::when_engine_running ()
}
}
/* create master/control ports */
if (Config->get_auto_connect_standard_busses() && !no_auto_connect()) {
if (_master_out) {
/* if requested auto-connect the outputs to the first N physical ports.
*/
if (Config->get_auto_connect_master()) {
uint32_t limit = _master_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) {
@ -681,6 +693,24 @@ Session::when_engine_running ()
}
}
}
if (_control_out) {
uint32_t limit = _control_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) {
Port* p = _control_out->output()->nth (n);
string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n);
if (!connect_to.empty()) {
if (_control_out->output()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect control output %1 to %2"), n, connect_to)
<< endmsg;
break;
}
}
}
}
}
BootMessage (_("Setup signal flow and plugins"));
@ -689,33 +719,6 @@ Session::when_engine_running ()
/* catch up on send+insert cnts */
BootMessage (_("Catch up with send/insert state"));
insert_cnt = 0;
for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
uint32_t id;
if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) {
if (id > insert_cnt) {
insert_cnt = id;
}
}
}
send_cnt = 0;
for (list<Send*>::iterator i = _sends.begin(); i != _sends.end(); ++i) {
uint32_t id;
if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) {
if (id > send_cnt) {
send_cnt = id;
}
}
}
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
/* hook us up to the engine */
@ -751,24 +754,6 @@ Session::hookup_io ()
}
}
/* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */
if (_control_out) {
// _control_out->ensure_io (_control_out->input_minimum(), _control_out->output_minimum(), false, this);
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x);
if (t) {
t->listen_via (_control_out->input(), X_("listen"));
}
}
}
/* load bundles, which we may have postponed earlier on */
if (_bundle_xml_node) {
load_bundles (*_bundle_xml_node);
@ -783,6 +768,22 @@ Session::hookup_io ()
Delivery::reset_panners ();
/* Connect tracks to listen/solo etc. busses XXX generalize this beyond control_out */
if (_control_out) {
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x);
if (t) {
t->listen_via (_control_out, X_("listen"));
}
}
}
/* Anyone who cares about input state, wake up and do something */
IOConnectionsComplete (); /* EMIT SIGNAL */
@ -1455,7 +1456,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
continue;
}
if ((*j)->feeds ((*i)->input())) {
if ((*j)->feeds (*i)) {
(*i)->fed_by.insert (*j);
}
}
@ -2064,8 +2065,11 @@ Session::add_routes (RouteList& new_routes, bool save)
RCUWriter<RouteList> writer (routes);
shared_ptr<RouteList> r = writer.get_copy ();
r->insert (r->end(), new_routes.begin(), new_routes.end());
if (!_control_out && IO::connecting_legal) {
resort_routes_using (r);
}
}
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
@ -2088,8 +2092,10 @@ 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->input(), "control");
(*x)->listen_via (_control_out, "control");
}
resort_routes ();
}
set_dirty();
@ -2145,13 +2151,14 @@ Session::remove_route (shared_ptr<Route> route)
}
if (route == _control_out) {
/* cancel control outs for all routes */
for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
(*r)->drop_listen (_control_out->input());
(*r)->drop_listen (_control_out);
}
_control_out = shared_ptr<Route> ();
_control_out.reset ();
}
update_route_solo_state ();
@ -2238,7 +2245,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
solo_update_disabled = true;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->feeds (route->input())) {
if ((*i)->feeds (route)) {
/* do it */
(*i)->main_outs()->mod_solo_level (delta);
@ -3533,26 +3540,7 @@ Session::record_enable_change_all (bool yn)
void
Session::add_processor (Processor* processor)
{
Send* send;
Return* retrn;
PortInsert* port_insert;
PluginInsert* plugin_insert;
if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) {
_port_inserts.insert (_port_inserts.begin(), port_insert);
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
_sends.insert (_sends.begin(), send);
} else if ((retrn = dynamic_cast<Return *> (processor)) != 0) {
_returns.insert (_returns.begin(), retrn);
} else {
fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/
}
processor->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_processor), processor));
set_dirty();
}
@ -3562,31 +3550,13 @@ Session::remove_processor (Processor* processor)
Send* send;
Return* retrn;
PortInsert* port_insert;
PluginInsert* plugin_insert;
if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) {
list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert);
if (x != _port_inserts.end()) {
insert_bitset[port_insert->bit_slot()] = false;
_port_inserts.erase (x);
}
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
_plugin_inserts.remove (plugin_insert);
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
if (x != _sends.end()) {
send_bitset[send->bit_slot()] = false;
_sends.erase (x);
}
} else if ((retrn = dynamic_cast<Return *> (processor)) != 0) {
list<Return*>::iterator x = find (_returns.begin(), _returns.end(), retrn);
if (x != _returns.end()) {
return_bitset[send->bit_slot()] = false;
_returns.erase (x);
}
} else {
fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
/*NOTREACHED*/
}
set_dirty();

View file

@ -153,7 +153,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_non_soloed_outs_muted = false;
g_atomic_int_set (&processing_prohibited, 0);
insert_cnt = 0;
_transport_speed = 0;
_last_transport_speed = 0;
_target_transport_speed = 0;

View file

@ -136,6 +136,8 @@ def build(bld):
gdither.cc
globals.cc
import.cc
internal_return.cc
internal_send.cc
interpolation.cc
io.cc
io_processor.cc