diff options
43 files changed, 986 insertions, 354 deletions
diff --git a/gtk2_ardour/arval-waf b/gtk2_ardour/arval-waf index 439bebd6aa..f8c8a336a7 100644 --- a/gtk2_ardour/arval-waf +++ b/gtk2_ardour/arval-waf @@ -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 "$@" diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc index 7dbae624e1..e61bd6e744 100644 --- a/gtk2_ardour/audio_streamview.cc +++ b/gtk2_ardour/audio_streamview.cc @@ -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)); } diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index ebc6b0d642..30718ad158 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -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)); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 20f75f1100..89c3283062 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -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); diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 4f96486ddc..33af778744 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -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"), diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index 630bde675c..892df2eb50 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -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 (); diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h index ca1b36e0b1..be1af03061 100644 --- a/libs/ardour/ardour/audio_buffer.h +++ b/libs/ardour/ardour/audio_buffer.h @@ -56,6 +56,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) { diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h index da75556877..8ed054923b 100644 --- a/libs/ardour/ardour/buffer.h +++ b/libs/ardour/ardour/buffer.h @@ -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) diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h index 3f10929fe8..ecd4e4ab72 100644 --- a/libs/ardour/ardour/buffer_set.h +++ b/libs/ardour/ardour/buffer_set.h @@ -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? diff --git a/libs/ardour/ardour/delivery.h b/libs/ardour/ardour/delivery.h index c875f23fcc..32ecc98215 100644 --- a/libs/ardour/ardour/delivery.h +++ b/libs/ardour/ardour/delivery.h @@ -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&); diff --git a/libs/ardour/ardour/internal_return.h b/libs/ardour/ardour/internal_return.h new file mode 100644 index 0000000000..6aa8bfe7b4 --- /dev/null +++ b/libs/ardour/ardour/internal_return.h @@ -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__ */ diff --git a/libs/ardour/ardour/internal_send.h b/libs/ardour/ardour/internal_send.h new file mode 100644 index 0000000000..0bbb75d685 --- /dev/null +++ b/libs/ardour/ardour/internal_send.h @@ -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__ */ diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h index 14d88d6b44..430f54d46d 100644 --- a/libs/ardour/ardour/io_processor.h +++ b/libs/ardour/ardour/io_processor.h @@ -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; diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h index 57afcc39ca..414b559de0 100644 --- a/libs/ardour/ardour/meter.h +++ b/libs/ardour/ardour/meter.h @@ -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(); diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h index 64417cae26..4e27e33235 100644 --- a/libs/ardour/ardour/midi_buffer.h +++ b/libs/ardour/ardour/midi_buffer.h @@ -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); diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 06fcb81ce7..f91e9a6863 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -50,7 +50,8 @@ 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() { } virtual bool visible() const { return true; } diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 7387e5d001..3f063f4692 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -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)) diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index aa768e269f..d2cc252d61 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -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); diff --git a/libs/ardour/ardour/return.h b/libs/ardour/ardour/return.h index 3f75cc57b7..8f8a84f321 100644 --- a/libs/ardour/ardour/return.h +++ b/libs/ardour/ardour/return.h @@ -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; } diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 2a3580b187..339f18ef3f 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -52,6 +52,7 @@ class Panner; class Processor; class RouteGroup; class Send; +class InternalReturn; class Route : public SessionObject, public AutomatableControls { @@ -183,18 +184,17 @@ 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<Delivery> control_outs() const { return _control_outs; } + boost::shared_ptr<Delivery> main_outs() const { return _main_outs; } + 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; diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h index 3a0eae21e5..37d56e2abd 100644 --- a/libs/ardour/ardour/send.h +++ b/libs/ardour/ardour/send.h @@ -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; } diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 2e161ff776..e970d6e9e4 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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 *); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 4e2d97f718..4143cb109a 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -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/buffer_set.h" #include "ardour/cycle_timer.h" -#include "ardour/utils.h" +#include "ardour/delivery.h" #include "ardour/event_type_map.h" +#include "ardour/internal_return.h" #include "ardour/io.h" -#include "ardour/amp.h" +#include "ardour/meter.h" +#include "ardour/midi_port.h" +#include "ardour/port.h" #include "ardour/port_set.h" -#include "ardour/buffer_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 * diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 25948e595c..5743bae935 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -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); } diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc index 005a4dae65..319444e1b9 100644 --- a/libs/ardour/buffer_set.cc +++ b/libs/ardour/buffer_set.cc @@ -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 diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index 0a49a47a7f..a4a76c37ae 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -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)); - _output->changed.connect (mem_fun (*this, &Delivery::output_changed)); + 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,7 +77,9 @@ Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string& _current_gain = 1.0; _panner = boost::shared_ptr<Panner>(new Panner (_name, _session)); - _output->changed.connect (mem_fun (*this, &Delivery::output_changed)); + if (_output) { + _output->changed.connect (mem_fun (*this, &Delivery::output_changed)); + } } /* 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 (); } - _output->changed.connect (mem_fun (*this, &Delivery::output_changed)); + 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 @@ -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 (); } } + diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 6e98fdf5a7..43fb4e4014 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -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); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index a501e65931..0ce024c31e 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -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)); diff --git a/libs/ardour/internal_return.cc b/libs/ardour/internal_return.cc new file mode 100644 index 0000000000..409c87d93c --- /dev/null +++ b/libs/ardour/internal_return.cc @@ -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; +} + + + diff --git a/libs/ardour/internal_send.cc b/libs/ardour/internal_send.cc new file mode 100644 index 0000000000..398dbca08d --- /dev/null +++ b/libs/ardour/internal_send.cc @@ -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; +} diff --git a/libs/ardour/io_processor.cc b/libs/ardour/io_processor.cc index 7e0d4a771c..cfa2b4c689 100644 --- a/libs/ardour/io_processor.cc +++ b/libs/ardour/io_processor.cc @@ -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) { - _own_input = false; - _own_output = false; + 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) { - XMLNode& i (_input->state (full_state)); - // i.name() = X_("output"); - node.add_child_nocopy (i); node.add_property ("own-input", "yes"); + if (_input) { + XMLNode& i (_input->state (full_state)); + // i.name() = X_("output"); + node.add_child_nocopy (i); + } } else { node.add_property ("own-input", "no"); if (_input) { @@ -119,10 +133,12 @@ IOProcessor::state (bool full_state) } if (_own_output) { - XMLNode& o (_output->state (full_state)); - // o.name() = X_("output"); - node.add_child_nocopy (o); node.add_property ("own-output", "yes"); + if (_output) { + XMLNode& o (_output->state (full_state)); + // o.name() = X_("output"); + node.add_child_nocopy (o); + } } 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,7 +209,9 @@ IOProcessor::set_state (const XMLNode& node) if ((prop = node.property ("name")) == 0) { set_name (_output->name()); } - } + } else { + /* no output */ + } } return 0; @@ -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()); +} diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc index 0675e14cef..50bd290754 100644 --- a/libs/ardour/meter.cc +++ b/libs/ardour/meter.cc @@ -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 () { diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index bce47411cd..887545c662 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -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. diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index bd6d05a0b4..be72f65593 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -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; diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index 2e39c52d67..ab5902efa5 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -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(); diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index fb662beca3..1754e24b5e 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -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. diff --git a/libs/ardour/region_factory.cc b/libs/ardour/region_factory.cc index a6bf4e0870..004321fa9e 100644 --- a/libs/ardour/region_factory.cc +++ b/libs/ardour/region_factory.cc @@ -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); } diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc index 574b6736a0..5a44d3f6e6 100644 --- a/libs/ardour/return.cc +++ b/libs/ardour/return.cc @@ -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 */ diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 36b0a6bf68..0b6c3c48ca 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -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; @@ -1488,6 +1509,34 @@ Route::_set_state (const XMLNode& node, bool call_base) } else { _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,21 +1665,30 @@ 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; bool processorInStateList = false; - + 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,26 +1704,24 @@ 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()) { - break; + break; } ++o; @@ -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,10 +1739,11 @@ Route::set_processor_state (const XMLNode& node) cerr << "Error restoring route: unable to restore processor" << endl; } - // Otherwise, the processor already exists; just - // ensure it is at the location provided in the XML state } else { + // Otherwise, the processor already exists; just + // ensure it is at the location provided in the XML state + if (i != o) { boost::shared_ptr<Processor> tmp = (*o); _processors.erase (o); // remove the old copy @@ -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 += ']'; - - boost::shared_ptr<Delivery> listener (new Delivery (_session, _mute_master, name, Delivery::Listen)); - - /* 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>(); + 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->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(); - - for (uint32_t n = 0; n < ni; ++n) { - ports.push_back (io->nth (n)->name()); - } - - if (ports.empty()) { - return 0; - } - boost::shared_ptr<Delivery> listen_point = add_listener (io, listen_name); - - /* XXX hack for now .... until we can generalize listen points */ + boost::shared_ptr<InternalSend> listener; - _control_outs = listen_point; + try { + listener.reset (new InternalSend (_session, _mute_master, route)); - /* now connect to the named ports */ - - ni = listen_point->output()->n_ports().n_total(); - size_t psize = ports.size(); + } catch (failed_constructor& err) { - 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; } 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<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x); + boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*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; } } diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index ad66f73796..71685e1b88 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -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); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 394193e8b2..db30fea021 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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,16 +671,15 @@ Session::when_engine_running () } } - /* create master/control ports */ - - if (_master_out) { + if (Config->get_auto_connect_standard_busses() && !no_auto_connect()) { - /* if requested auto-connect the outputs to the first N physical ports. - */ + 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) { Port* p = _master_out->output()->nth (n); string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n); @@ -681,40 +693,31 @@ Session::when_engine_running () } } } - } - - BootMessage (_("Setup signal flow and plugins")); - hookup_io (); + if (_control_out) { - /* 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; + 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; + } + } } } } - send_cnt = 0; - - for (list<Send*>::iterator i = _sends.begin(); i != _sends.end(); ++i) { - uint32_t id; + BootMessage (_("Setup signal flow and plugins")); - if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) { - if (id > send_cnt) { - send_cnt = id; - } - } - } + hookup_io (); + /* catch up on send+insert cnts */ _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); @@ -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,7 +2065,10 @@ 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()); - resort_routes_using (r); + + 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); + insert_bitset[port_insert->bit_slot()] = false; } 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); - } + send_bitset[send->bit_slot()] = false; } 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*/ + return_bitset[send->bit_slot()] = false; } set_dirty(); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 5d622f95a7..f11342a0fd 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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; diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 89a7e06c04..fc08dfde0d 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -136,8 +136,10 @@ def build(bld): gdither.cc globals.cc import.cc + internal_return.cc + internal_send.cc interpolation.cc - io.cc + io.cc io_processor.cc jack_slave.cc ladspa_plugin.cc |