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 #!/bin/sh
. `dirname "$0"`/../build/default/gtk2_ardour/ardev_common_waf.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 export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
exec valgrind --num-callers=50 --tool=memcheck $TOP/$EXECUTABLE --novst "$@" 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> 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); assert(region);
region->block_property_changes ();
region->set_position (_trackview.session().transport_frame(), this); region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (make_pair(region, (RegionView*)0)); 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> 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); assert(region);
region->block_property_changes ();
region->set_position (_trackview.session().transport_frame(), this); region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (make_pair(region, (RegionView*)0)); 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); send->set_metering (false);
} }
_current_delivery = _route->send_for (target->input()); _current_delivery = _route->internal_send_for (target);
if (_current_delivery) { if (_current_delivery) {
send = boost::dynamic_pointer_cast<Send>(_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 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> ( ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
"input-auto-connect", "input-auto-connect",
_("Connect track and bus inputs"), _("Connect track and bus inputs"),

View file

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

View file

@ -57,6 +57,13 @@ public:
_written = true; _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*/ /** 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) { void accumulate_from (const AudioBuffer& src, nframes_t len, nframes_t dst_offset = 0, nframes_t src_offset = 0) {
assert(_capacity > 0); assert(_capacity > 0);

View file

@ -76,6 +76,7 @@ public:
virtual void clear() { silence(_capacity, 0); } 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 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: protected:
Buffer(DataType type, size_t capacity) Buffer(DataType type, size_t capacity)

View file

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

View file

@ -40,7 +40,13 @@ public:
Main = 0x8 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 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& s, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&); 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 Session;
class IO; class IO;
class Route;
/** A mixer strip element (Processor) with 1 or 2 IO elements. /** A mixer strip element (Processor) with 1 or 2 IO elements.
*/ */
@ -66,6 +67,8 @@ class IOProcessor : public Processor
void silence (nframes_t nframes); void silence (nframes_t nframes);
virtual bool feeds (boost::shared_ptr<Route> other) const;
sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged; sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged;
sigc::signal<void,IOProcessor*,uint32_t> AutomationChanged; sigc::signal<void,IOProcessor*,uint32_t> AutomationChanged;

View file

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

View file

@ -39,6 +39,7 @@ public:
void silence (nframes_t nframes, nframes_t offset = 0); 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 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); 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; static const std::string state_node_name;
Processor(Session&, const std::string& name); Processor(Session&, const std::string& name);
Processor(Session&, const XMLNode& node);
virtual ~Processor() { } virtual ~Processor() { }

View file

@ -19,7 +19,7 @@
/* IO connection */ /* 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, output_auto_connect, "output-auto-connect", AutoConnectOption (0))
CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-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, LeftOfSplit = 0x4000,
RightOfSplit = 0x8000, RightOfSplit = 0x8000,
Hidden = 0x10000, Hidden = 0x10000,
DoNotSaveState = 0x20000, DoNotSendPropertyChanges = 0x20000,
PositionLocked = 0x40000, PositionLocked = 0x40000,
// //
range_guarantoor = USHRT_MAX range_guarantoor = USHRT_MAX
@ -97,6 +97,8 @@ class Region
sigc::signal<void,Change> StateChanged; sigc::signal<void,Change> StateChanged;
static sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > RegionPropertyChanged; 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(); virtual ~Region();
@ -160,8 +162,6 @@ class Region
void set_position_lock_style (PositionLockStyle ps); void set_position_lock_style (PositionLockStyle ps);
void recompute_position_from_lock_style (); void recompute_position_from_lock_style ();
virtual bool should_save_state () const { return !(_flags & DoNotSaveState); };
void freeze (); void freeze ();
void thaw (const std::string& why); void thaw (const std::string& why);

View file

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

View file

@ -52,6 +52,7 @@ class Panner;
class Processor; class Processor;
class RouteGroup; class RouteGroup;
class Send; class Send;
class InternalReturn;
class Route : public SessionObject, public AutomatableControls 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 max_processor_streams () const { return processor_max_streams; }
ChanCount pre_fader_streams() const;
/* special processors */ /* special processors */
boost::shared_ptr<Delivery> control_outs() const { return _control_outs; } boost::shared_ptr<Delivery> control_outs() const { return _control_outs; }
boost::shared_ptr<Delivery> main_outs() const { return _main_outs; } boost::shared_ptr<Delivery> main_outs() const { return _main_outs; }
boost::shared_ptr<InternalReturn> internal_return() const { return _intreturn; }
boost::shared_ptr<Send> send_for (boost::shared_ptr<const IO> target) const; 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. /** 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. * 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; sigc::signal<void,void*> SelectedChanged;
int listen_via (boost::shared_ptr<IO>, const std::string& name); int listen_via (boost::shared_ptr<Route>, const std::string& name);
void drop_listen (boost::shared_ptr<IO>); 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; std::set<boost::shared_ptr<Route> > fed_by;
/* Controls (not all directly owned by the Route */ /* Controls (not all directly owned by the Route */
@ -341,6 +341,7 @@ class Route : public SessionObject, public AutomatableControls
mutable Glib::RWLock _processor_lock; mutable Glib::RWLock _processor_lock;
boost::shared_ptr<Delivery> _main_outs; boost::shared_ptr<Delivery> _main_outs;
boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points
boost::shared_ptr<InternalReturn> _intreturn;
Flag _flags; Flag _flags;
int _pending_declick; int _pending_declick;
@ -381,8 +382,6 @@ class Route : public SessionObject, public AutomatableControls
virtual int _set_state (const XMLNode&, bool call_base); 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<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter; boost::shared_ptr<PeakMeter> _meter;
sigc::connection _meter_connection; sigc::connection _meter_connection;

View file

@ -37,8 +37,8 @@ class Amp;
class Send : public Delivery class Send : public Delivery
{ {
public: public:
Send (Session&, boost::shared_ptr<MuteMaster>); Send (Session&, boost::shared_ptr<MuteMaster>, bool internal = false);
Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&); Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&, bool internal = false);
virtual ~Send (); virtual ~Send ();
uint32_t bit_slot() const { return _bitslot; } 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> control_out() const { return _control_out; }
boost::shared_ptr<Route> master_out() const { return _master_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) { static void set_disable_all_loaded_plugins (bool yn) {
_disable_all_loaded_plugins = yn; _disable_all_loaded_plugins = yn;
} }
@ -1558,16 +1552,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* INSERT AND SEND MANAGEMENT */ /* 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> send_bitset;
boost::dynamic_bitset<uint32_t> return_bitset; boost::dynamic_bitset<uint32_t> return_bitset;
boost::dynamic_bitset<uint32_t> insert_bitset; boost::dynamic_bitset<uint32_t> insert_bitset;
uint32_t send_cnt;
uint32_t insert_cnt;
void add_processor (Processor *); void add_processor (Processor *);
void remove_processor (Processor *); void remove_processor (Processor *);

View file

@ -31,23 +31,23 @@
#include "midi++/jack.h" #include "midi++/jack.h"
#include "ardour/amp.h"
#include "ardour/audio_port.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/buffer.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/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/timestamps.h"
#include "ardour/utils.h"
#include "i18n.h" #include "i18n.h"
@ -364,6 +364,7 @@ AudioEngine::process_callback (nframes_t nframes)
Delivery::CycleStart (nframes); Delivery::CycleStart (nframes);
Port::set_port_offset (0); Port::set_port_offset (0);
InternalReturn::CycleStart (nframes);
/* tell all Ports that we're starting a new cycle */ /* tell all Ports that we're starting a new cycle */
@ -822,10 +823,15 @@ AudioEngine::frames_per_cycle ()
Port * Port *
AudioEngine::get_port_by_name (const string& portname) 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); Glib::Mutex::Lock lm (_process_lock);
return get_port_by_name_locked (portname); return get_port_by_name_locked (s);
} }
Port * Port *

View file

@ -655,6 +655,14 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
_flags = Flag (_flags & ~Region::RightOfSplit); _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) { if ((old_flags ^ _flags) & Muted) {
what_changed = Change (what_changed|MuteChanged); what_changed = Change (what_changed|MuteChanged);
} }

View file

@ -225,5 +225,32 @@ BufferSet::read_from (BufferSet& in, nframes_t nframes)
set_count(in.count()); 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 } // namespace ARDOUR

View file

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

View file

@ -396,7 +396,7 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Region, LeftOfSplit); REGISTER_CLASS_ENUM (Region, LeftOfSplit);
REGISTER_CLASS_ENUM (Region, RightOfSplit); REGISTER_CLASS_ENUM (Region, RightOfSplit);
REGISTER_CLASS_ENUM (Region, Hidden); REGISTER_CLASS_ENUM (Region, Hidden);
REGISTER_CLASS_ENUM (Region, DoNotSaveState); REGISTER_CLASS_ENUM (Region, DoNotSendPropertyChanges);
REGISTER_BITS (_Region_Flag); REGISTER_BITS (_Region_Flag);
REGISTER_CLASS_ENUM (Region, AudioTime); 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) ARDOUR::LocaleGuard::LocaleGuard (const char* str)
{ {
old = strdup (setlocale (LC_NUMERIC, NULL)); 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) { if (with_output) {
_output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype)); _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 */ /* 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) , _input (in)
, _output (out) , _output (out)
{ {
cerr << "XML create IOP name = " << proc_name << " in = " << in << " out = " << out << endl;
if (in) {
_own_input = false; _own_input = false;
} else {
_own_input = true;
}
if (out) {
_own_output = false; _own_output = false;
} else {
_own_output = true;
}
} }
IOProcessor::~IOProcessor () IOProcessor::~IOProcessor ()
@ -107,10 +119,12 @@ IOProcessor::state (bool full_state)
XMLNode& node (Processor::state (full_state)); XMLNode& node (Processor::state (full_state));
if (_own_input) { if (_own_input) {
node.add_property ("own-input", "yes");
if (_input) {
XMLNode& i (_input->state (full_state)); XMLNode& i (_input->state (full_state));
// i.name() = X_("output"); // i.name() = X_("output");
node.add_child_nocopy (i); node.add_child_nocopy (i);
node.add_property ("own-input", "yes"); }
} else { } else {
node.add_property ("own-input", "no"); node.add_property ("own-input", "no");
if (_input) { if (_input) {
@ -119,10 +133,12 @@ IOProcessor::state (bool full_state)
} }
if (_own_output) { if (_own_output) {
node.add_property ("own-output", "yes");
if (_output) {
XMLNode& o (_output->state (full_state)); XMLNode& o (_output->state (full_state));
// o.name() = X_("output"); // o.name() = X_("output");
node.add_child_nocopy (o); node.add_child_nocopy (o);
node.add_property ("own-output", "yes"); }
} else { } else {
node.add_property ("own-output", "no"); node.add_property ("own-output", "no");
if (_output) { if (_output) {
@ -173,9 +189,9 @@ IOProcessor::set_state (const XMLNode& node)
} }
} else { } else {
error << _("XML node describing an IOProcessor is missing an IO node") << endmsg; /* no input */
return -1;
} }
} }
if (_own_output) { if (_own_output) {
@ -193,6 +209,8 @@ IOProcessor::set_state (const XMLNode& node)
if ((prop = node.property ("name")) == 0) { if ((prop = node.property ("name")) == 0) {
set_name (_output->name()); set_name (_output->name());
} }
} else {
/* no output */
} }
} }
@ -246,3 +264,9 @@ IOProcessor::set_name (const std::string& name)
return ret; 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 void
PeakMeter::reset () PeakMeter::reset ()
{ {

View file

@ -99,6 +99,17 @@ MidiBuffer::read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offse
_silent = src.silent(); _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. /** Push an event into the buffer.
* *
* Note that the raw MIDI pointed to by ev will be COPIED and unmodified. * 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) { if (inbufs.count().n_audio() > 0) {
BufferSet::audio_iterator i = inbufs.audio_begin(); BufferSet::audio_iterator i = inbufs.audio_begin();
for (++i; i != inbufs.audio_end(); ++i) { 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 // accumulate starting with the second
BufferSet::audio_iterator i = inbufs.audio_begin(); BufferSet::audio_iterator i = inbufs.audio_begin();
for (++i; i != inbufs.audio_end(); ++i) { for (++i; i != inbufs.audio_end(); ++i) {
dst.accumulate_from(*i, nframes); dst.merge_from(*i, nframes);
} }
return; 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& XMLNode&
Processor::get_state (void) Processor::get_state (void)
{ {
@ -141,6 +152,9 @@ Processor::set_state (const XMLNode& node)
// may not exist for legacy 3.0 sessions // may not exist for legacy 3.0 sessions
if ((prop = node.property ("id")) != 0) { if ((prop = node.property ("id")) != 0) {
_id = prop->value(); _id = prop->value();
cerr << "---------------- ID for processor " << name() << " = " << _id << endl;
} else {
cerr << "---------------- NO ID for processor " << name() << endl;
} }
XMLNodeList nlist = node.children(); 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) Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: SessionObject(s, name) : SessionObject(s, name)
, _type(type) , _type(type)
, _flags(flags) , _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _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) 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) : SessionObject(src->session(), name)
, _type(type) , _type(type)
, _flags(flags) , _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _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) 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) : SessionObject(srcs.front()->session(), name)
, _type(type) , _type(type)
, _flags(flags) , _flags(Flag (flags|DoNotSendPropertyChanges))
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _position(0)
@ -150,6 +150,8 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
_start = other->_start + offset; _start = other->_start + offset;
copy_stuff (other, offset, length, name, layer, flags); copy_stuff (other, offset, length, name, layer, flags);
_flags = Flag (_flags | DoNotSendPropertyChanges);
/* if the other region had a distinct sync point /* if the other region had a distinct sync point
set, then continue to use it as best we can. set, then continue to use it as best we can.
otherwise, reset sync point back to start. 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; _start = 0;
copy_stuff (other, 0, length, name, layer, flags); 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, /* 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 so set our sync position to whatever the the difference between
_start and _sync_pos was in the other region. _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)) , _pending_changed(Change(0))
, _last_layer_op(other->_last_layer_op) , _last_layer_op(other->_last_layer_op)
{ {
_flags = Flag (_flags | DoNotSendPropertyChanges);
other->_first_edit = EditChangesName; other->_first_edit = EditChangesName;
if (other->_extra_xml) { if (other->_extra_xml) {
@ -268,7 +274,7 @@ Region::Region (boost::shared_ptr<const Region> other)
Region::Region (const SourceList& srcs, const XMLNode& node) Region::Region (const SourceList& srcs, const XMLNode& node)
: SessionObject(srcs.front()->session(), X_("error: XML did not reset this")) : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL) // to be loaded from XML , _type(DataType::NIL) // to be loaded from XML
, _flags(Flag(0)) , _flags(DoNotSendPropertyChanges)
, _start(0) , _start(0)
, _length(0) , _length(0)
, _position(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) Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
: SessionObject(src->session(), X_("error: XML did not reset this")) : SessionObject(src->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL) , _type(DataType::NIL)
, _flags(Flag(0)) , _flags(DoNotSendPropertyChanges)
, _start(0) , _start(0)
, _length(0) , _length(0)
, _position(0) , _position(0)
@ -1400,7 +1406,7 @@ Region::send_change (Change what_changed)
StateChanged (what_changed); StateChanged (what_changed);
if (!(_flags & DoNotSaveState)) { if (!(_flags & DoNotSendPropertyChanges)) {
/* Try and send a shared_pointer unless this is part of the constructor. /* Try and send a shared_pointer unless this is part of the constructor.
If so, do nothing. 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); AudioRegion* ar = new AudioRegion (other_a, start, length, name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar); boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp)); boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); 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); MidiRegion* ar = new MidiRegion (other_m, start, length, name, layer, flags);
boost::shared_ptr<MidiRegion> arp (ar); boost::shared_ptr<MidiRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp)); boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); CheckNewRegion (ret);
} }
@ -75,10 +77,12 @@ RegionFactory::create (boost::shared_ptr<const Region> region)
if ((ar = boost::dynamic_pointer_cast<const AudioRegion>(region)) != 0) { if ((ar = boost::dynamic_pointer_cast<const AudioRegion>(region)) != 0) {
boost::shared_ptr<Region> ret (new AudioRegion (ar)); boost::shared_ptr<Region> ret (new AudioRegion (ar));
ret->unlock_property_changes ();
/* pure copy constructor - no CheckNewRegion emitted */ /* pure copy constructor - no CheckNewRegion emitted */
return ret; return ret;
} else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) { } else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) {
boost::shared_ptr<Region> ret (new MidiRegion (mr)); boost::shared_ptr<Region> ret (new MidiRegion (mr));
ret->unlock_property_changes ();
/* pure copy constructor - no CheckNewRegion emitted */ /* pure copy constructor - no CheckNewRegion emitted */
return ret; return ret;
} else { } 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); 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<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp)); boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); CheckNewRegion (ret);
} }
@ -128,6 +133,7 @@ boost::shared_ptr<Region>
RegionFactory::create (Session& session, XMLNode& node, bool yn) RegionFactory::create (Session& session, XMLNode& node, bool yn)
{ {
boost::shared_ptr<Region> r = session.XMLRegionFactory (node, yn); boost::shared_ptr<Region> r = session.XMLRegionFactory (node, yn);
r->unlock_property_changes ();
if (r) { if (r) {
CheckNewRegion (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); AudioRegion* ar = new AudioRegion (srcs, start, length, name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar); boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp)); boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); 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); MidiRegion* ar = new MidiRegion (srcs, start, length, name, layer, flags);
boost::shared_ptr<MidiRegion> mrp (ar); boost::shared_ptr<MidiRegion> mrp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (mrp)); boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (mrp));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); CheckNewRegion (ret);
} }
@ -177,10 +185,12 @@ RegionFactory::create (SourceList& srcs, const XMLNode& node)
if (srcs[0]->type() == DataType::AUDIO) { if (srcs[0]->type() == DataType::AUDIO) {
boost::shared_ptr<Region> ret (new AudioRegion (srcs, node)); boost::shared_ptr<Region> ret (new AudioRegion (srcs, node));
ret->unlock_property_changes ();
CheckNewRegion (ret); CheckNewRegion (ret);
return ret; return ret;
} else if (srcs[0]->type() == DataType::MIDI) { } else if (srcs[0]->type() == DataType::MIDI) {
boost::shared_ptr<Region> ret (new MidiRegion (srcs, node)); boost::shared_ptr<Region> ret (new MidiRegion (srcs, node));
ret->unlock_property_changes ();
CheckNewRegion (ret); CheckNewRegion (ret);
return 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) { if ((as = boost::dynamic_pointer_cast<AudioSource>(src)) != 0) {
boost::shared_ptr<Region> ret (new AudioRegion (as, start, length, name, layer, flags)); boost::shared_ptr<Region> ret (new AudioRegion (as, start, length, name, layer, flags));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); CheckNewRegion (ret);
} }
return ret; return ret;
} else if ((ms = boost::dynamic_pointer_cast<MidiSource>(src)) != 0) { } else if ((ms = boost::dynamic_pointer_cast<MidiSource>(src)) != 0) {
boost::shared_ptr<Region> ret (new MidiRegion (ms, start, length, name, layer, flags)); boost::shared_ptr<Region> ret (new MidiRegion (ms, start, length, name, layer, flags));
ret->unlock_property_changes ();
if (announce) { if (announce) {
CheckNewRegion (ret); CheckNewRegion (ret);
} }

View file

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

View file

@ -38,6 +38,8 @@
#include "ardour/configuration.h" #include "ardour/configuration.h"
#include "ardour/cycle_timer.h" #include "ardour/cycle_timer.h"
#include "ardour/dB.h" #include "ardour/dB.h"
#include "ardour/internal_send.h"
#include "ardour/internal_return.h"
#include "ardour/ladspa_plugin.h" #include "ardour/ladspa_plugin.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/mix.h" #include "ardour/mix.h"
@ -73,6 +75,24 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
{ {
init (); 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) 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) , _default_type (default_type)
{ {
init (); init ();
_set_state (node, false); _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 void
@ -123,20 +148,10 @@ Route::init ()
_input->changed.connect (mem_fun (this, &Route::input_change_handler)); _input->changed.connect (mem_fun (this, &Route::input_change_handler));
_output->changed.connect (mem_fun (this, &Route::output_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)); _amp.reset (new Amp (_session, _mute_master));
add_processor (_amp, PostFader); 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 () Route::~Route ()
@ -316,7 +331,7 @@ Route::process_output_buffers (BufferSet& bufs,
switch (Config->get_monitoring_model()) { switch (Config->get_monitoring_model()) {
case HardwareMonitoring: case HardwareMonitoring:
case ExternalMonitoring: 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; break;
default: default:
monitor = true; monitor = true;
@ -327,13 +342,13 @@ Route::process_output_buffers (BufferSet& bufs,
} }
/* figure out if we're going to use gain automation */ /* figure out if we're going to use gain automation */
_amp->setup_gain_automation (start_frame, end_frame, nframes); _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); _main_outs->no_outs_cuz_we_no_monitor (!monitor);
/* ------------------------------------------------------------------------------------------- /* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.) GLOBAL DECLICK (for transport changes etc.)
----------------------------------------------------------------------------------------- */ ----------------------------------------------------------------------------------------- */
@ -520,25 +535,16 @@ Route::muted() const
return _mute_master->muted (); return _mute_master->muted ();
} }
#if DEFINE_IF_YOU_NEED_THIS
static void static void
dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs) dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
{ {
cerr << name << " {" << endl; cerr << name << " {" << endl;
for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin(); for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
p != procs.end(); ++p) { p != procs.end(); ++p) {
cerr << "\t" << (*p)->name() << endl; cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << endl;
} }
cerr << "}" << endl; cerr << "}" << endl;
} }
#endif
Route::ProcessorList::iterator
Route::prefader_iterator()
{
Glib::RWLock::ReaderLock lm (_processor_lock);
return find (_processors.begin(), _processors.end(), _amp);
}
int int
Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err) 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; loc = iter;
} }
cerr << "Adding " << processor->name() << " @ " << processor << endl;
_processors.insert (loc, processor); _processors.insert (loc, processor);
// Set up processor list channels. This will set processor->[input|output]_streams(), // 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; --ploc;
_processors.erase(ploc); _processors.erase(ploc);
configure_processors_unlocked (0); // it worked before we tried to add it ... configure_processors_unlocked (0); // it worked before we tried to add it ...
cerr << "configure failed\n";
return -1; return -1;
} }
@ -660,6 +669,7 @@ bool
Route::add_processor_from_xml (const XMLNode& node, Placement placement) Route::add_processor_from_xml (const XMLNode& node, Placement placement)
{ {
ProcessorList::iterator loc; ProcessorList::iterator loc;
if (placement == PreFader) { if (placement == PreFader) {
/* generic pre-fader: insert immediately before the amp */ /* generic pre-fader: insert immediately before the amp */
loc = find(_processors.begin(), _processors.end(), _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; cerr << _name << " : got processor type " << prop->value() << endl;
boost::shared_ptr<Processor> processor; boost::shared_ptr<Processor> processor;
bool have_insert = false;
if (prop->value() == "ladspa" || prop->value() == "Ladspa" || if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" || prop->value() == "lv2" ||
@ -707,7 +716,6 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
prop->value() == "audiounit") { prop->value() == "audiounit") {
processor.reset (new PluginInsert(_session, node)); processor.reset (new PluginInsert(_session, node));
have_insert = true;
} else if (prop->value() == "port") { } 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") { } else if (prop->value() == "send") {
processor.reset (new Send (_session, _mute_master, node)); processor.reset (new Send (_session, _mute_master, node));
have_insert = true;
} else if (prop->value() == "meter") { } 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 = _meter;
processor->set_state (node);
} else if (prop->value() == "amp") { } else if (prop->value() == "amp") {
/* amp always exists */
processor = _amp; 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") { } else if (prop->value() == "listen" || prop->value() == "deliver") {
/* XXX need to generalize */ /* XXX need to generalize */
processor = _control_outs; } else if (prop->value() == "intsend") {
processor->set_state (node);
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") { } 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 = _main_outs;
processor->set_state (node);
} else { } else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; 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. /** Remove processors with a given placement.
* @param p Placement of processors to remove. * @param p Placement of processors to remove.
*/ */
@ -1195,7 +1212,11 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
ChanCount out; ChanCount out;
list< pair<ChanCount,ChanCount> > configuration; list< pair<ChanCount,ChanCount> > configuration;
uint32_t index = 0; uint32_t index = 0;
cerr << "Processor check with " << _processors.size() << endl;
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) { 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)) { if ((*p)->can_support_io_configuration(in, out)) {
configuration.push_back(make_pair(in, out)); configuration.push_back(make_pair(in, out));
in = out; in = out;
@ -1489,6 +1510,34 @@ Route::_set_state (const XMLNode& node, bool call_base)
_flags = Flag (0); _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) { if ((prop = node.property (X_("phase-invert"))) != 0) {
set_phase_invert (prop->value()=="yes"?true:false); 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){ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter; child = *niter;
@ -1642,13 +1665,21 @@ Route::set_processor_state (const XMLNode& node)
{ {
const XMLNodeList &nlist = node.children(); const XMLNodeList &nlist = node.children();
XMLNodeConstIterator niter; XMLNodeConstIterator niter;
bool has_meter_processor = false; // legacy sessions don't
ProcessorList::iterator i, o; 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 // Iterate through existing processors, remove those which are not in the state list
for (i = _processors.begin(); i != _processors.end(); ) { for (i = _processors.begin(); i != _processors.end(); ) {
/* leave amp alone, always */
if ((*i) == _amp) {
++i;
continue;
}
ProcessorList::iterator tmp = i; ProcessorList::iterator tmp = i;
++tmp; ++tmp;
@ -1657,6 +1688,7 @@ Route::set_processor_state (const XMLNode& node)
for (niter = nlist.begin(); niter != nlist.end(); ++niter) { for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
XMLProperty* id_prop = (*niter)->property(X_("id")); XMLProperty* id_prop = (*niter)->property(X_("id"));
cerr << "\tchecking " << id_prop->value() << endl;
if (id_prop && (*i)->id() == id_prop->value()) { if (id_prop && (*i)->id() == id_prop->value()) {
processorInStateList = true; processorInStateList = true;
break; 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, // 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 // set the state of existing processors according to the new state on the same go
i = _processors.begin(); i = _processors.begin();
for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
XMLProperty* prop = (*niter)->property ("type"); XMLProperty* prop = (*niter)->property ("type");
if (prop && prop->value() == "meter") {
has_meter_processor = true;
}
o = i; o = i;
if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") { // Check whether the next processor in the list is the right one,
// except for "amp" which is always there and may not have the
// Check whether the next processor in the list // old ID since it is always created anew in every Route
if (prop->value() != "amp") {
while (o != _processors.end()) { while (o != _processors.end()) {
XMLProperty* id_prop = (*niter)->property(X_("id")); XMLProperty* id_prop = (*niter)->property(X_("id"));
if (id_prop && (*o)->id() == id_prop->value()) { 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, // If the processor (*niter) is not on the route,
// create it and move it to the correct location // create it and move it to the correct location
if (o == _processors.end()) { if (o == _processors.end()) {
if (add_processor_from_xml (**niter, i)) { 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; cerr << "Error restoring route: unable to restore processor" << endl;
} }
} else {
// Otherwise, the processor already exists; just // Otherwise, the processor already exists; just
// ensure it is at the location provided in the XML state // ensure it is at the location provided in the XML state
} else {
if (i != o) { if (i != o) {
boost::shared_ptr<Processor> tmp = (*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 --i; // move iterator to the correct processor
} }
// and make it (just) so
(*i)->set_state (**niter); (*i)->set_state (**niter);
} }
} }
@ -1727,10 +1761,6 @@ Route::set_processor_state (const XMLNode& node)
the XML state represents a working signal route. the XML state represents a working signal route.
*/ */
if (!has_meter_processor) {
set_meter_point (_meter_point, NULL);
}
processors_changed (); processors_changed ();
} }
@ -1772,33 +1802,38 @@ Route::silence (nframes_t nframes)
} }
} }
boost::shared_ptr<Delivery> BufferSet*
Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name) Route::get_return_buffer () const
{ {
string name = _name; Glib::RWLock::ReaderLock rm (_processor_lock);
name += '[';
name += listen_name;
name += ']';
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 if (d) {
* (we track the changes in ::output_change_handler()). return d->get_buffers ();
* 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>();
} }
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 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> ports;
vector<string>::const_iterator i; 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); Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) { 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 */ /* already listening via the specified IO: do nothing */
return 0; return 0;
} }
} }
} }
uint32_t ni = io->n_ports().n_total(); boost::shared_ptr<InternalSend> listener;
for (uint32_t n = 0; n < ni; ++n) { try {
ports.push_back (io->nth (n)->name()); listener.reset (new InternalSend (_session, _mute_master, route));
}
if (ports.empty()) { } catch (failed_constructor& err) {
return 0;
}
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; return -1;
} }
}
add_processor (listener, PreFader);
return 0; return 0;
} }
void void
Route::drop_listen (boost::shared_ptr<IO> io) Route::drop_listen (boost::shared_ptr<Route> route)
{ {
ProcessorStreams err; ProcessorStreams err;
ProcessorList::iterator tmp; 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(); ) { for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
tmp = x; boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
++tmp;
boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x); if (d && d->target_route() == route) {
rl.release ();
if (d && d->output() == io) {
/* already listening via the specified IO: do nothing */
remove_processor (*x, &err); 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 void
@ -1939,25 +1961,30 @@ Route::set_comment (string cmt, void *src)
} }
bool 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; return true;
} }
/* check IOProcessors which may also interconnect Routes */
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) { for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
boost::shared_ptr<IOProcessor> iop; boost::shared_ptr<IOProcessor> iop;
if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) { 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; return true;
} else {
// cerr << "\tIOP " << iop->name() << " does NOT feeds " << other->name() << endl;
} }
} }
} }
// cerr << "\tdoes NOT FEED " << other->name() << endl;
return false; return false;
} }
@ -2418,15 +2445,15 @@ Route::set_name (const string& str)
} }
boost::shared_ptr<Send> 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); Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { 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 = boost::dynamic_pointer_cast<InternalSend>(*i)) != 0) {
if (send->output()->connected_to (target)) { if (send->target_route() == target) {
return send; return send;
} }
} }

View file

@ -36,8 +36,9 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm) Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, bool internal)
: Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send) : Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1),
(internal ? Delivery::Listen : Delivery::Send))
, _metering (false) , _metering (false)
{ {
_amp.reset (new Amp (_session, _mute_master)); _amp.reset (new Amp (_session, _mute_master));
@ -46,8 +47,8 @@ Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
ProcessorCreated (this); /* EMIT SIGNAL */ ProcessorCreated (this); /* EMIT SIGNAL */
} }
Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node) Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node, bool internal)
: Delivery (s, mm, "send", Delivery::Send) : Delivery (s, mm, "send", (internal ? Delivery::Listen : Delivery::Send))
, _metering (false) , _metering (false)
{ {
_amp.reset (new Amp (_session, _mute_master)); _amp.reset (new Amp (_session, _mute_master));
@ -113,6 +114,7 @@ Send::state(bool full)
{ {
XMLNode& node = IOProcessor::state(full); XMLNode& node = IOProcessor::state(full);
char buf[32]; char buf[32];
node.add_property ("type", "send"); node.add_property ("type", "send");
snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot); snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot);
node.add_property ("bitslot", buf); 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_input_auto_connect (input_ac);
Config->set_output_auto_connect (output_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 it doesn't really scale that well to higher channel counts
*/ */
/* mono output bundles */
for (uint32_t np = 0; np < n_physical_outputs; ++np) { for (uint32_t np = 0; np < n_physical_outputs; ++np) {
char buf[32]; char buf[32];
snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1); snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
@ -618,6 +625,8 @@ Session::when_engine_running ()
add_bundle (c); add_bundle (c);
} }
/* stereo output bundles */
for (uint32_t np = 0; np < n_physical_outputs; np += 2) { for (uint32_t np = 0; np < n_physical_outputs; np += 2) {
if (np + 1 < n_physical_outputs) { if (np + 1 < n_physical_outputs) {
char buf[32]; char buf[32];
@ -632,6 +641,8 @@ Session::when_engine_running ()
} }
} }
/* mono input bundles */
for (uint32_t np = 0; np < n_physical_inputs; ++np) { for (uint32_t np = 0; np < n_physical_inputs; ++np) {
char buf[32]; char buf[32];
snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1); snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
@ -643,6 +654,8 @@ Session::when_engine_running ()
add_bundle (c); add_bundle (c);
} }
/* stereo input bundles */
for (uint32_t np = 0; np < n_physical_inputs; np += 2) { for (uint32_t np = 0; np < n_physical_inputs; np += 2) {
if (np + 1 < n_physical_inputs) { if (np + 1 < n_physical_inputs) {
char buf[32]; 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 (_master_out) {
/* if requested auto-connect the outputs to the first N physical ports. /* 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(); uint32_t limit = _master_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) { 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")); BootMessage (_("Setup signal flow and plugins"));
@ -689,33 +719,6 @@ Session::when_engine_running ()
/* catch up on send+insert cnts */ /* 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)); _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
/* hook us up to the engine */ /* 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 */ /* load bundles, which we may have postponed earlier on */
if (_bundle_xml_node) { if (_bundle_xml_node) {
load_bundles (*_bundle_xml_node); load_bundles (*_bundle_xml_node);
@ -783,6 +768,22 @@ Session::hookup_io ()
Delivery::reset_panners (); 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 */ /* Anyone who cares about input state, wake up and do something */
IOConnectionsComplete (); /* EMIT SIGNAL */ IOConnectionsComplete (); /* EMIT SIGNAL */
@ -1455,7 +1456,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
continue; continue;
} }
if ((*j)->feeds ((*i)->input())) { if ((*j)->feeds (*i)) {
(*i)->fed_by.insert (*j); (*i)->fed_by.insert (*j);
} }
} }
@ -2064,8 +2065,11 @@ Session::add_routes (RouteList& new_routes, bool save)
RCUWriter<RouteList> writer (routes); RCUWriter<RouteList> writer (routes);
shared_ptr<RouteList> r = writer.get_copy (); shared_ptr<RouteList> r = writer.get_copy ();
r->insert (r->end(), new_routes.begin(), new_routes.end()); r->insert (r->end(), new_routes.begin(), new_routes.end());
if (!_control_out && IO::connecting_legal) {
resort_routes_using (r); resort_routes_using (r);
} }
}
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { 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) { if (_control_out && IO::connecting_legal) {
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { 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(); set_dirty();
@ -2145,13 +2151,14 @@ Session::remove_route (shared_ptr<Route> route)
} }
if (route == _control_out) { if (route == _control_out) {
/* cancel control outs for all routes */ /* cancel control outs for all routes */
for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) { 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 (); update_route_solo_state ();
@ -2238,7 +2245,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
solo_update_disabled = true; solo_update_disabled = true;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->feeds (route->input())) { if ((*i)->feeds (route)) {
/* do it */ /* do it */
(*i)->main_outs()->mod_solo_level (delta); (*i)->main_outs()->mod_solo_level (delta);
@ -3533,26 +3540,7 @@ Session::record_enable_change_all (bool yn)
void void
Session::add_processor (Processor* processor) 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)); processor->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_processor), processor));
set_dirty(); set_dirty();
} }
@ -3562,31 +3550,13 @@ Session::remove_processor (Processor* processor)
Send* send; Send* send;
Return* retrn; Return* retrn;
PortInsert* port_insert; PortInsert* port_insert;
PluginInsert* plugin_insert;
if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) { 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; 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) { } 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; send_bitset[send->bit_slot()] = false;
_sends.erase (x);
}
} else if ((retrn = dynamic_cast<Return *> (processor)) != 0) { } 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; return_bitset[send->bit_slot()] = false;
_returns.erase (x);
}
} else {
fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
/*NOTREACHED*/
} }
set_dirty(); set_dirty();

View file

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

View file

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