From 70b939da4f9d4097160e32f2373a7a5ff8f4957f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 30 Jan 2009 07:40:13 +0000 Subject: first pass at internal sends. this is a very tentative work in progress, and it is possible that major changes may follow in the near future. it is certainly not complete, but the fundamental changes to Port/Buffer operation merit a commit at this point git-svn-id: svn://localhost/ardour2/branches/3.0@4464 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/SConscript | 1 + libs/ardour/ardour/ardour.h | 3 - libs/ardour/ardour/audio_buffer.h | 23 ++++++- libs/ardour/ardour/audio_port.h | 6 +- libs/ardour/ardour/audio_track.h | 4 ++ libs/ardour/ardour/automatable.h | 7 ++- libs/ardour/ardour/buffer.h | 6 +- libs/ardour/ardour/buffer_set.h | 3 +- libs/ardour/ardour/io.h | 29 ++++----- libs/ardour/ardour/io_processor.h | 4 +- libs/ardour/ardour/port.h | 10 ++- libs/ardour/ardour/processor.h | 7 ++- libs/ardour/ardour/session.h | 1 - libs/ardour/ardour/types.h | 5 +- libs/ardour/audio_buffer.cc | 34 +++++++--- libs/ardour/audio_port.cc | 126 +++++++++++++++++++++++++------------- libs/ardour/audio_track.cc | 40 +++++++++++- libs/ardour/audioengine.cc | 9 --- libs/ardour/buffer_set.cc | 6 +- libs/ardour/io.cc | 102 +++++++++++++++--------------- libs/ardour/io_processor.cc | 8 ++- libs/ardour/port.cc | 123 ++++++++++++++++++++++++++++--------- libs/ardour/processor.cc | 7 --- libs/ardour/route.cc | 60 ++++++++++++------ libs/ardour/send.cc | 10 +-- libs/ardour/session.cc | 7 ++- 26 files changed, 430 insertions(+), 211 deletions(-) (limited to 'libs/ardour') diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index f34dd9b078..59ffd764bc 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -92,6 +92,7 @@ gain.cc gdither.cc globals.cc import.cc +internal_send.cc io.cc io_processor.cc jack_slave.cc diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index 635e8a31ca..7321daf097 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -42,9 +42,6 @@ namespace MIDI { namespace ARDOUR { class AudioEngine; - class OSC; - - extern OSC* osc; static const nframes_t max_frames = JACK_MAX_FRAMES; extern sigc::signal BootMessage; diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h index 9a41e8e093..829288a7af 100644 --- a/libs/ardour/ardour/audio_buffer.h +++ b/libs/ardour/ardour/audio_buffer.h @@ -68,9 +68,14 @@ public: /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset * scaling by @a gain_coeff */ void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff) { + assert(_capacity > 0); assert(offset + len <= _capacity); + if (src.silent()) { + return; + } + Sample* const dst_raw = _data + offset; const Sample* const src_raw = src.data(); @@ -82,6 +87,7 @@ public: /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset * scaling by @a gain_coeff */ void accumulate_with_gain_from(const Sample* src_raw, nframes_t len, nframes_t offset, gain_t gain_coeff) { + assert(_capacity > 0); assert(offset + len <= _capacity); @@ -123,7 +129,22 @@ public: Sample* data (nframes_t nframes, nframes_t offset) { assert(offset + nframes <= _capacity); return _data + offset; } -private: + void replace_data (size_t nframes); + + void drop_data () { + assert (_owns_data); + assert (_data); + + free (_data); + _data = 0; + _size = 0; + _capacity = 0; + _silent = false; + } + + void copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset); + + private: bool _owns_data; Sample* _data; ///< Actual buffer contents }; diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index 339165da0f..304902bccb 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -51,12 +51,16 @@ class AudioPort : public Port AudioPort (std::string const &, Flags, bool, nframes_t); + bool using_internal_data() const; + void use_internal_data (); + void use_external_data (); + private: void mixdown (nframes_t, nframes_t, bool); bool _has_been_mixed_down; AudioBuffer* _buffer; - bool _own_buffer; + bool _internal_buffer; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index fe7dcb58ff..48609271d7 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -73,6 +73,10 @@ class AudioTrack : public Track int deprecated_use_diskstream_connections (); void set_state_part_two (); void set_state_part_three (); + + void catch_up_on_busses (ARDOUR::RouteList&); + void add_internal_send (boost::shared_ptr); + }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index fc61e2200d..d99960334d 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -94,15 +94,16 @@ public: Evoral::ControlSet& data() { return *this; } const Evoral::ControlSet& data() const { return *this; } -protected: + int set_automation_state (const XMLNode&, Evoral::Parameter default_param); + XMLNode& get_automation_state(); + + protected: Session& _a_session; void can_automate(Evoral::Parameter); virtual void auto_state_changed (Evoral::Parameter which) {} - int set_automation_state(const XMLNode&, Evoral::Parameter default_param); - XMLNode& get_automation_state(); int load_automation (const std::string& path); int old_set_automation_state(const XMLNode&); diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h index e03489568c..02d6975fad 100644 --- a/libs/ardour/ardour/buffer.h +++ b/libs/ardour/ardour/buffer.h @@ -68,7 +68,7 @@ public: * passed to the constructor must have been non-zero. */ virtual void resize(size_t) = 0; - + /** Clear (eg zero, or empty) buffer starting at TIME @a offset */ virtual void silence(nframes_t len, nframes_t offset=0) = 0; @@ -77,9 +77,9 @@ public: virtual void read_from(const Buffer& src, nframes_t offset, nframes_t len) = 0; -protected: + protected: Buffer(DataType type, size_t capacity) - : _type(type), _capacity(capacity), _size(0), _silent(true) + : _type(type), _capacity(capacity), _size(0), _silent(true) {} DataType _type; diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h index c750615798..3f7a6e7665 100644 --- a/libs/ardour/ardour/buffer_set.h +++ b/libs/ardour/ardour/buffer_set.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ARDOUR { @@ -53,7 +54,7 @@ public: void clear(); - void attach_buffers(PortSet& ports); + void attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset); void ensure_buffers(const ChanCount& count, size_t buffer_capacity); void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity); diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 2d5b55c502..32962fef0d 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -109,6 +109,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent void just_meter_input (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset); + BufferSet& output_buffers() { return *_output_buffers; } + gain_t gain () const { return _desired_gain; } virtual gain_t effective_gain () const; @@ -121,6 +123,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent Panner& panner() { return *_panner; } PeakMeter& peak_meter() { return *_meter; } const Panner& panner() const { return *_panner; } + void reset_panner (); int ensure_io (ChanCount in, ChanCount out, bool clear, void *src); @@ -196,15 +199,10 @@ class IO : public SessionObject, public AutomatableControls, public Latent int set_state (const XMLNode&); static int disable_connecting (void); - static int enable_connecting (void); - static int disable_ports (void); - static int enable_ports (void); - static int disable_panners (void); - static int reset_panners (void); static sigc::signal PortsLegal; @@ -214,16 +212,16 @@ class IO : public SessionObject, public AutomatableControls, public Latent static sigc::signal PortCountChanged; static sigc::signal PortsCreated; - static void update_meters(); + static void update_meters(); private: - - static sigc::signal Meter; - static Glib::StaticMutex m_meter_signal_lock; - sigc::connection m_meter_connection; + + static sigc::signal Meter; + static Glib::StaticMutex m_meter_signal_lock; + sigc::connection m_meter_connection; public: - + /* automation */ struct GainControl : public AutomationControl { @@ -292,8 +290,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent virtual void set_deferred_state() {} - void reset_panner (); - virtual uint32_t pans_required() const { return _inputs.count().n_audio(); } @@ -314,14 +310,11 @@ class IO : public SessionObject, public AutomatableControls, public Latent static bool connecting_legal; static bool ports_legal; - BufferSet& output_buffers() { return *_output_buffers; } - private: + static bool panners_legal; - friend class Send; + void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset); - static bool panners_legal; - int connecting_became_legal (); int panners_became_legal (); sigc::connection connection_legal_c; diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h index d2bd210516..3739c496c5 100644 --- a/libs/ardour/ardour/io_processor.h +++ b/libs/ardour/ardour/io_processor.h @@ -53,7 +53,9 @@ class IOProcessor : public Processor { public: IOProcessor (Session&, const string& name, Placement, - int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1); + int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1, + ARDOUR::DataType default_type = DataType::AUDIO, + bool public_ports = true); IOProcessor (const IOProcessor&); virtual ~IOProcessor (); diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h index 7539aac9d5..759d532e82 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -71,6 +71,7 @@ public: } bool connected () const; + bool externally_connected () const; int disconnect_all (); int get_connections (std::vector &) const; @@ -81,7 +82,7 @@ public: /* connection by Port* */ bool connected_to (Port *) const; - int connect (Port *); + virtual int connect (Port *); int disconnect (Port *); void ensure_monitor_input (bool); @@ -113,6 +114,12 @@ protected: std::set _connections; ///< internal Ports that we are connected to static AudioEngine* _engine; ///< the AudioEngine + + virtual bool using_internal_data() const { return false; } + virtual void use_internal_data () {} + virtual void use_external_data () {} + + void check_buffer_status (); private: friend class AudioEngine; @@ -130,6 +137,7 @@ private: /// list of JACK ports that we are connected to; we only keep this around /// so that we can implement ::reconnect () std::set _named_connections; + }; } diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 4b236d159e..da00c77dab 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -39,6 +39,7 @@ class XMLNode; namespace ARDOUR { class Session; +class Route; /* A mixer strip element - plugin, send, meter, etc. */ @@ -60,7 +61,6 @@ class Processor : public SessionObject, public AutomatableControls, public Laten void set_placement (Placement); bool active () const { return _active; } - void set_active (bool yn); bool get_next_ab_is_active () const { return _next_ab_is_active; } void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; } @@ -77,8 +77,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten virtual void silence (nframes_t nframes, nframes_t offset) {} - virtual void activate () { _active = true; ActiveChanged.emit(); } - virtual void deactivate () { _active = false; ActiveChanged.emit(); } + void activate () { _active = true; ActiveChanged(); } + void deactivate () { _active = false; ActiveChanged(); } virtual bool configure_io (ChanCount in, ChanCount out); @@ -108,6 +108,7 @@ class Processor : public SessionObject, public AutomatableControls, public Laten sigc::signal PlacementChanged; protected: + int _pending_active; bool _active; bool _next_ab_is_active; bool _configured; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 1a88882eb6..7cdc11a054 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -306,7 +306,6 @@ class Session : public PBD::StatefulDestructible uint32_t n_diskstreams() const; typedef std::list > DiskstreamList; - typedef std::list > RouteList; int load_routes (const XMLNode&); boost::shared_ptr get_routes() const { diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index cb058254bf..125c8569a8 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -51,6 +51,7 @@ namespace ARDOUR { class Source; class AudioSource; + class Route; typedef jack_default_audio_sample_t Sample; typedef float pan_t; @@ -419,9 +420,11 @@ namespace ARDOUR { typedef std::list AnalysisFeatureList; + typedef std::list > RouteList; + class Bundle; typedef std::vector > BundleList; - + } // namespace ARDOUR std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); diff --git a/libs/ardour/audio_buffer.cc b/libs/ardour/audio_buffer.cc index 915fdeb948..506b34eb04 100644 --- a/libs/ardour/audio_buffer.cc +++ b/libs/ardour/audio_buffer.cc @@ -29,9 +29,7 @@ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it mat #endif using namespace PBD; - -namespace ARDOUR { - +using namespace ARDOUR; AudioBuffer::AudioBuffer(size_t capacity) : Buffer(DataType::AUDIO, capacity) @@ -41,6 +39,7 @@ AudioBuffer::AudioBuffer(size_t capacity) if (_capacity > 0) { _owns_data = true; // prevent resize() from gagging resize (_capacity); + _silent = false; // force silence on the intial buffer state silence (_capacity); } } @@ -51,10 +50,28 @@ AudioBuffer::~AudioBuffer() free(_data); } +/* called to replace a pointer to an external buffer (e.g. JACK) with + buffer-owned memory. +*/ + +void +AudioBuffer::replace_data (size_t capacity) +{ + _owns_data = true; + _data = 0; + _capacity = 0; // force reallocation + resize (capacity); +} + void AudioBuffer::resize (size_t size) { - if (!_owns_data || (size < _capacity)) { + if (!_owns_data) { + return; + } + + if (size < _capacity) { + _size = size; return; } @@ -74,9 +91,12 @@ AudioBuffer::resize (size_t size) CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg; } #endif - - _owns_data = true; + } -} // namespace ARDOUR +void +AudioBuffer::copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset) +{ + memcpy (_data + offset, p, sizeof(Sample*) * cnt); +} diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc index 55d65d850d..0e48c2a699 100644 --- a/libs/ardour/audio_port.cc +++ b/libs/ardour/audio_port.cc @@ -29,9 +29,10 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t : Port (name, DataType::AUDIO, flags, ext) , _has_been_mixed_down (false) , _buffer (0) + , _internal_buffer (false) { assert (name.find_first_of (':') == string::npos); - + if (external ()) { /* external ports use the external port buffer */ @@ -41,8 +42,9 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t /* internal ports need their own buffers */ _buffer = new AudioBuffer (capacity); - } + + check_buffer_status (); } @@ -56,11 +58,22 @@ AudioPort::cycle_start (nframes_t nframes, nframes_t offset) { /* caller must hold process lock */ - _has_been_mixed_down = false; + /* For external (JACK) ports, get_buffer() must only be run + on outputs here in cycle_start(). - if (external ()) { - /* external ports use JACK's memory */ - _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes), nframes + offset); + Inputs must be done in the correct processing order, which + requires interleaving with route processing. that will + happen when Port::get_buffer() is called. + */ + + if (!receives_input() && external ()) { + _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes); + } + + if (receives_input()) { + _has_been_mixed_down = false; + } else { + _buffer->silence (nframes, offset); } } @@ -69,36 +82,21 @@ AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset) { /* caller must hold process lock */ - if (_has_been_mixed_down) { - return *_buffer; - } - - if (receives_input ()) { - - /* INPUT */ + if (receives_input () && !_has_been_mixed_down) { - /* If we're external (), we have some data in our buffer set up by JACK; - otherwise, we have an undefined buffer. In either case we mix down - our non-JACK inputs; either accumulating into the JACK data or - overwriting the undefined data */ - - mixdown (nframes, offset, !external ()); + /* external ports use JACK's memory unless otherwise noted */ - } else { - - /* OUTPUT */ - - if (!external ()) { - /* start internal output buffers with silence */ - _buffer->silence (nframes, offset); + if (external()) { + if (!using_internal_data()) { + _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes); + } else { + _buffer->silence (nframes, offset); + } } - - } - - if (nframes) { - _has_been_mixed_down = true; - } + mixdown (nframes, offset, !external ()); + } + return *_buffer; } @@ -111,22 +109,46 @@ AudioPort::cycle_end (nframes_t nframes, nframes_t offset) void AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite) { + /* note: this is only called for input ports */ + if (_connections.empty()) { - if (first_overwrite) { + + /* no internal mixing to do, so for internal ports + just make sure the buffer is silent. + */ + + if (!external()) { _buffer->silence (cnt, offset); + } + + } else { + + set::const_iterator p = _connections.begin(); + + /* mix in internally-connected ports. if this is an external port + then it may already have data present from JACK. in that case, we + do not want to overwrite that data, so we skip the initial ::read_from() + call and do everything with accumulate_from() + */ + + if (!external()) { + _buffer->read_from (dynamic_cast(*p)->get_audio_buffer (cnt, offset), cnt, offset); + ++p; + } - return; - } - - set::const_iterator p = _connections.begin(); - if (first_overwrite) { - _buffer->read_from (dynamic_cast(*p)->get_audio_buffer (cnt, offset), cnt, offset); - ++p; + for (; p != _connections.end (); ++p) { + _buffer->accumulate_from (dynamic_cast(*p)->get_audio_buffer (cnt, offset), cnt, offset); + + } } - for (; p != _connections.end (); ++p) { - _buffer->accumulate_from (dynamic_cast(*p)->get_audio_buffer (cnt, offset), cnt, offset); + /* XXX horrible heuristic designed to check that we worked the whole buffer. + Needs fixing but its a hard problem. + */ + + if (cnt && offset == 0) { + _has_been_mixed_down = true; } } @@ -140,3 +162,23 @@ AudioPort::reset () _buffer->clear (); } } + +bool +AudioPort::using_internal_data () const +{ + return _internal_buffer; +} + +void +AudioPort::use_internal_data () +{ + _buffer->replace_data (_buffer->capacity()); + _internal_buffer = true; +} + +void +AudioPort::use_external_data () +{ + _internal_buffer = false; + _buffer->drop_data (); +} diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index ada5a183dc..5749afd265 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include "i18n.h" using namespace std; @@ -65,6 +66,8 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode _session.add_diskstream (ds); + _session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses)); + set_diskstream (boost::dynamic_pointer_cast (ds), this); } @@ -72,12 +75,47 @@ AudioTrack::AudioTrack (Session& sess, const XMLNode& node) : Track (sess, node) { _set_state (node, false); + + _session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses)); } AudioTrack::~AudioTrack () { } +void +AudioTrack::catch_up_on_busses (RouteList& added) +{ + if (is_hidden()) { + return; + } + + for (RouteList::iterator x = added.begin(); x != added.end(); ++x) { + if (boost::dynamic_pointer_cast(*x) == 0 && (*x)->default_type() == DataType::AUDIO) { + /* Audio bus */ + if (!(*x)->is_master() && !(*x)->is_control()) { + add_internal_send (*x); + } + } + } +} + +void +AudioTrack::add_internal_send (boost::shared_ptr r) +{ + boost::shared_ptr is (new InternalSend (_session, PreFader, r)); + + cerr << name() << " Adding processor\n"; + + add_processor (is, 0); + + cerr << "After add, we have " << _processors.size() << endl; + + /* note: if adding failed, the InternalSend will be cleaned up automatically when + the shared_ptr goes out of scope. + */ +} + int AudioTrack::set_mode (TrackMode m) { @@ -879,7 +917,7 @@ AudioTrack::freeze (InterThreadInfo& itt) /* now deactivate the processor */ - processor->set_active (false); + processor->deactivate (); _session.set_dirty (); } } diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 4d8f18423f..27b5fcc5c5 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -348,13 +348,6 @@ AudioEngine::process_callback (nframes_t nframes) boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - /* Only run cycle_start() on output ports, because - inputs must be done in the correct processing order, - which requires interleaving with route processing. - */ - - /* XXX: we're running this on both inputs and outputs... */ (*i)->cycle_start (nframes, 0); } @@ -416,10 +409,8 @@ AudioEngine::process_callback (nframes_t nframes) // Finalize ports (ie write data if necessary) for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_end (nframes, 0); } - _processed_frames = next_processed_frames; return 0; } diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc index 5b6f071150..09fd880451 100644 --- a/libs/ardour/buffer_set.cc +++ b/libs/ardour/buffer_set.cc @@ -16,6 +16,7 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -61,7 +62,7 @@ BufferSet::clear() /** Make this BufferSet a direct mirror of a PortSet's buffers. */ void -BufferSet::attach_buffers(PortSet& ports) +BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset) { clear(); @@ -71,9 +72,8 @@ BufferSet::attach_buffers(PortSet& ports) for (PortSet::iterator p = ports.begin(*t); p != ports.end(*t); ++p) { assert(p->type() == *t); - v.push_back(&(p->get_buffer(0,0))); + v.push_back(&(p->get_buffer(nframes, offset))); } - } _count = ports.count(); diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index a5a330cc36..dbe7b3c526 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -153,9 +153,6 @@ IO::IO (Session& s, const string& name, m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); } - // Connect to our own PortCountChanged signal to connect output buffers - IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers)); - _session.add_controllable (_gain_control); create_bundles_for_inputs_and_outputs (); @@ -195,9 +192,6 @@ IO::IO (Session& s, const XMLNode& node, DataType dt) m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); } - // Connect to our own PortCountChanged signal to connect output buffers - IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers)); - _session.add_controllable (_gain_control); create_bundles_for_inputs_and_outputs (); @@ -222,7 +216,6 @@ IO::~IO () delete _meter; delete _panner; - delete _output_buffers; } void @@ -266,48 +259,61 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, _gain = dg; } } + + /* do this so that any processing that comes after deliver_outputs() + can use the output buffers. + */ + + output_buffers().attach_buffers (_outputs, nframes, offset); // Use the panner to distribute audio to output port buffers - if( _panner && _panner->npanners() && !_panner->bypassed()) { + + if (0 && _panner && _panner->npanners() && !_panner->bypassed()) { + + /* blech .. we shouldn't be creating and tearing this down every process() + cycle. XXX fix me to not waste cycles and do memory allocation etc. + */ + _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes, offset); + } else { - const DataType type = DataType::AUDIO; - - // Copy any audio 1:1 to outputs - - BufferSet::iterator o = output_buffers().begin(type); - BufferSet::iterator i = bufs.begin(type); - BufferSet::iterator prev = i; - - while (i != bufs.end(type) && o != output_buffers().end (type)) { - o->read_from(*i, nframes, offset); - prev = i; - ++i; - ++o; - } - /* extra outputs get a copy of the last buffer */ + /* do a 1:1 copy of data to output ports */ - while (o != output_buffers().end(type)) { - o->read_from(*prev, nframes, offset); - ++o; + if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) { + copy_to_outputs (bufs, DataType::AUDIO, nframes, offset); + } + if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) { + copy_to_outputs (bufs, DataType::MIDI, nframes, offset); } } +} - /* ********** MIDI ********** */ +void +IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset) +{ + // Copy any buffers 1:1 to outputs + + PortSet::iterator o = _outputs.begin(type); + BufferSet::iterator i = bufs.begin(type); + BufferSet::iterator prev = i; + + while (i != bufs.end(type) && o != _outputs.end (type)) { + + Buffer& port_buffer (o->get_buffer (nframes, offset)); + port_buffer.read_from (*i, nframes, offset); - // No MIDI, we're done here - if (bufs.count().n_midi() == 0 || output_buffers().count().n_midi () == 0) { - return; + prev = i; + ++i; + ++o; } - - const DataType type = DataType::MIDI; - - // Copy any MIDI 1:1 to outputs - assert(bufs.count().n_midi() == output_buffers().count().n_midi()); - BufferSet::iterator o = output_buffers().begin(type); - for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) { - o->read_from(*i, nframes, offset); + + /* extra outputs get a copy of the last buffer */ + + while (o != _outputs.end(type)) { + Buffer& port_buffer (o->get_buffer (nframes, offset)); + port_buffer.read_from(*prev, nframes, offset); + ++o; } } @@ -324,8 +330,10 @@ IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset) for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { BufferSet::iterator o = outs.begin(*t); - for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) { - o->read_from(i->get_buffer(nframes,offset), nframes, offset); + PortSet::iterator e = _inputs.end (*t); + for (PortSet::iterator i = _inputs.begin(*t); i != e; ++i, ++o) { + Buffer& b (i->get_buffer (nframes,offset)); + o->read_from (b, nframes, offset); } } @@ -879,16 +887,6 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src) return changed; } -/** Attach output_buffers to port buffers. - * - * Connected to IO's own PortCountChanged signal. - */ -void -IO::attach_buffers(ChanCount ignored) -{ - _output_buffers->attach_buffers(_outputs); -} - int IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) { @@ -2321,6 +2319,8 @@ IO::set_gain (gain_t val, void *src) val = 1.99526231f; } + cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl; + if (src != _gain_control.get()) { _gain_control->set_value(val); // bit twisty, this will come back and call us again @@ -2741,3 +2741,5 @@ IO::bundle_channel_name (uint32_t c, uint32_t n) const return ""; } + + diff --git a/libs/ardour/io_processor.cc b/libs/ardour/io_processor.cc index 08530b924c..fb27ba6f54 100644 --- a/libs/ardour/io_processor.cc +++ b/libs/ardour/io_processor.cc @@ -43,10 +43,12 @@ using namespace ARDOUR; using namespace PBD; IOProcessor::IOProcessor (Session& s, const string& name, Placement p, - int input_min, int input_max, - int output_min, int output_max) + int input_min, int input_max, + int output_min, int output_max, + DataType dtype, + bool public_ports) : Processor(s, name, p) - , _io(new IO(s, name, input_min, input_max, output_min, output_max)) + , _io (new IO(s, name, input_min, input_max, output_min, output_max, dtype, public_ports)) { _active = false; _sort_key = 0; diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index b200888508..74de1922fe 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -25,19 +25,30 @@ #include "pbd/compose.h" #include -ARDOUR::AudioEngine* ARDOUR::Port::_engine = 0; +using namespace std; +using namespace ARDOUR; + +AudioEngine* Port::_engine = 0; /** @param n Port short name */ -ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_port (0), _last_monitor (false), _latency (0), _name (n), _flags (f) +Port::Port (std::string const & n, DataType t, Flags f, bool e) + : _jack_port (0) + , _last_monitor (false) + , _latency (0) + , _name (n) + , _flags (f) { + /* Unfortunately we have to pass the DataType into this constructor so that we can create the right kind of JACK port; aside from this we'll use the virtual function type () - to establish type. */ + to establish type. + */ assert (_name.find_first_of (':') == std::string::npos); if (e) { try { + cerr << "NEW PORT " << _name << " ext = " << e << endl; do_make_external (t); } catch (...) { @@ -47,7 +58,7 @@ ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_ } /** Port destructor */ -ARDOUR::Port::~Port () +Port::~Port () { if (_jack_port) { jack_port_unregister (_engine->jack (), _jack_port); @@ -58,28 +69,27 @@ ARDOUR::Port::~Port () * @param t Data type, so that we can call this method from the constructor. */ void -ARDOUR::Port::do_make_external (DataType t) +Port::do_make_external (DataType t) { if (_jack_port) { /* already external */ return; } - _jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0); - if (_jack_port == 0) { + if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) { throw std::runtime_error ("Could not register JACK port"); } } void -ARDOUR::Port::make_external () +Port::make_external () { do_make_external (type ()); } /** @return true if this port is connected to anything */ bool -ARDOUR::Port::connected () const +Port::connected () const { if (!_connections.empty ()) { /* connected to a Port* */ @@ -94,8 +104,20 @@ ARDOUR::Port::connected () const return (jack_port_connected (_jack_port) != 0); } +/** @return true if this port is connected to anything via an external port */ +bool +Port::externally_connected () const +{ + if (_jack_port == 0) { + /* not using a JACK port, so can't be connected to anything else */ + return false; + } + + return (jack_port_connected (_jack_port) != 0); +} + int -ARDOUR::Port::disconnect_all () +Port::disconnect_all () { /* Disconnect from Port* connections */ for (std::set::iterator i = _connections.begin (); i != _connections.end (); ++i) { @@ -108,6 +130,8 @@ ARDOUR::Port::disconnect_all () jack_port_disconnect (_engine->jack(), _jack_port); _named_connections.clear (); + check_buffer_status (); + return 0; } @@ -115,7 +139,7 @@ ARDOUR::Port::disconnect_all () * @return true if this port is connected to o, otherwise false. */ bool -ARDOUR::Port::connected_to (std::string const & o) const +Port::connected_to (std::string const & o) const { std::string const full = _engine->make_port_name_non_relative (o); std::string const shrt = _engine->make_port_name_non_relative (o); @@ -137,7 +161,7 @@ ARDOUR::Port::connected_to (std::string const & o) const /** @param o Filled in with port full names of ports that we are connected to */ int -ARDOUR::Port::get_connections (std::vector & c) const +Port::get_connections (std::vector & c) const { int n = 0; @@ -163,7 +187,7 @@ ARDOUR::Port::get_connections (std::vector & c) const } int -ARDOUR::Port::connect (std::string const & other) +Port::connect (std::string const & other) { /* caller must hold process lock */ @@ -197,11 +221,13 @@ ARDOUR::Port::connect (std::string const & other) } } + check_buffer_status (); + return r; } int -ARDOUR::Port::disconnect (std::string const & other) +Port::disconnect (std::string const & other) { /* caller must hold process lock */ @@ -227,6 +253,8 @@ ARDOUR::Port::disconnect (std::string const & other) if (r == 0) { _named_connections.erase (other); } + + check_buffer_status (); } return r; @@ -234,13 +262,13 @@ ARDOUR::Port::disconnect (std::string const & other) bool -ARDOUR::Port::connected_to (Port* o) const +Port::connected_to (Port* o) const { return connected_to (o->name ()); } int -ARDOUR::Port::connect (Port* o) +Port::connect (Port* o) { /* caller must hold process lock */ @@ -253,11 +281,14 @@ ARDOUR::Port::connect (Port* o) _connections.insert (o); o->_connections.insert (this); + check_buffer_status (); + o->check_buffer_status (); + return 0; } int -ARDOUR::Port::disconnect (Port* o) +Port::disconnect (Port* o) { if (external () && o->external ()) { /* we're both external; try disconnecting using name */ @@ -270,17 +301,20 @@ ARDOUR::Port::disconnect (Port* o) _connections.erase (o); o->_connections.erase (this); + check_buffer_status (); + o->check_buffer_status (); + return 0; } void -ARDOUR::Port::set_engine (AudioEngine* e) +Port::set_engine (AudioEngine* e) { _engine = e; } void -ARDOUR::Port::ensure_monitor_input (bool yn) +Port::ensure_monitor_input (bool yn) { if (_jack_port) { jack_port_ensure_monitor (_jack_port, yn); @@ -288,7 +322,7 @@ ARDOUR::Port::ensure_monitor_input (bool yn) } bool -ARDOUR::Port::monitoring_input () const +Port::monitoring_input () const { if (_jack_port) { return jack_port_monitoring_input (_jack_port); @@ -298,7 +332,7 @@ ARDOUR::Port::monitoring_input () const } void -ARDOUR::Port::reset () +Port::reset () { _last_monitor = false; @@ -308,7 +342,7 @@ ARDOUR::Port::reset () } void -ARDOUR::Port::recompute_total_latency () const +Port::recompute_total_latency () const { #ifdef HAVE_JACK_RECOMPUTE_LATENCY if (_jack_port) { @@ -318,7 +352,7 @@ ARDOUR::Port::recompute_total_latency () const } nframes_t -ARDOUR::Port::total_latency () const +Port::total_latency () const { if (_jack_port) { return jack_port_get_total_latency (_engine->jack (), _jack_port); @@ -328,7 +362,7 @@ ARDOUR::Port::total_latency () const } int -ARDOUR::Port::reestablish () +Port::reestablish () { if (!_jack_port) { return 0; @@ -348,7 +382,7 @@ ARDOUR::Port::reestablish () int -ARDOUR::Port::reconnect () +Port::reconnect () { /* caller must hold process lock; intended to be used only after reestablish() */ @@ -367,7 +401,7 @@ ARDOUR::Port::reconnect () /** @param n Short name */ int -ARDOUR::Port::set_name (std::string const & n) +Port::set_name (std::string const & n) { assert (_name.find_first_of (':') == std::string::npos); @@ -386,15 +420,48 @@ ARDOUR::Port::set_name (std::string const & n) } void -ARDOUR::Port::set_latency (nframes_t n) +Port::set_latency (nframes_t n) { _latency = n; } void -ARDOUR::Port::request_monitor_input (bool yn) +Port::request_monitor_input (bool yn) { if (_jack_port) { jack_port_request_monitor (_jack_port, yn); } } + +void +Port::check_buffer_status () +{ + if (external() && receives_input()) { + if (!externally_connected()) { + if (!_connections.empty()) { + + /* There are no external connections, so the + external port buffer will be the silent buffer. We cannot write into it. + But we have to write somewhere because there is at least one internal + connection that is supplying us with data. + */ + + if (!using_internal_data()) { + use_internal_data (); + } + + } else { + + /* There are no external connections and no internal ones + either, so we can revert to use the externally supplied + buffer which will be silent (whatever the semantics of + that are for a particular data type. + */ + + if (using_internal_data()) { + use_external_data (); + } + } + } + } +} diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index a541ae0423..a528a4587c 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -105,13 +105,6 @@ Processor::set_placement (Placement p) } } -void -Processor::set_active (bool yn) -{ - _active = yn; - ActiveChanged (); -} - XMLNode& Processor::get_state (void) { diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index fab3c085db..14a8537068 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1229,6 +1230,11 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* int Route::add_processors (const ProcessorList& others, ProcessorStreams* err) { + /* NOTE: this is intended to be used ONLY when copying + processors from another Route. Hence the subtle + differences between this and ::add_processor() + */ + ChanCount old_pmo = processor_max_outs; if (!_session.engine().connected()) { @@ -1292,7 +1298,7 @@ Route::disable_processors (Placement p) for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->placement() == p) { - (*i)->set_active (false); + (*i)->deactivate (); } } @@ -1308,7 +1314,7 @@ Route::disable_processors () Glib::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->set_active (false); + (*i)->deactivate (); } _session.set_dirty (); @@ -1325,7 +1331,7 @@ Route::disable_plugins (Placement p) for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (boost::dynamic_pointer_cast (*i) && (*i)->placement() == p) { - (*i)->set_active (false); + (*i)->deactivate (); } } @@ -1342,7 +1348,7 @@ Route::disable_plugins () for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (boost::dynamic_pointer_cast (*i)) { - (*i)->set_active (false); + (*i)->deactivate (); } } @@ -1367,7 +1373,7 @@ Route::ab_plugins (bool forward) } if ((*i)->active()) { - (*i)->set_active (false); + (*i)->deactivate (); (*i)->set_next_ab_is_active (true); } else { (*i)->set_next_ab_is_active (false); @@ -1385,9 +1391,9 @@ Route::ab_plugins (bool forward) } if ((*i)->get_next_ab_is_active()) { - (*i)->set_active (true); + (*i)->activate (); } else { - (*i)->set_active (false); + (*i)->deactivate (); } } } @@ -1602,9 +1608,11 @@ Route::_reset_processor_counts (ProcessorStreams* err) } else if (boost::dynamic_pointer_cast (*r) != 0) { ++send_cnt; + } else if (boost::dynamic_pointer_cast (*r) != 0) { + ++send_cnt; } } - + if (insert_cnt == 0) { if (send_cnt) { goto recompute; @@ -1665,20 +1673,32 @@ Route::_reset_processor_counts (ProcessorStreams* err) for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) { boost::shared_ptr s; + boost::shared_ptr is; if ((s = boost::dynamic_pointer_cast (*r)) != 0) { + + /* don't pay any attention to send output configuration, since it doesn't + affect the route. + */ + if (r == _processors.begin()) { s->expect_inputs (n_inputs()); } else { s->expect_inputs ((*prev)->output_streams()); } + } else if ((is = boost::dynamic_pointer_cast (*r)) != 0) { + + /* XXX ditto, but clean this inheritance pattern up someday soon */ + + if (r == _processors.begin()) { + is->expect_inputs (n_inputs()); + } else { + is->expect_inputs ((*prev)->output_streams()); + } + } else { - /* don't pay any attention to send output configuration, since it doesn't - affect the route. - */ - max_audio = max ((*r)->output_streams ().n_audio(), max_audio); max_midi = max ((*r)->output_streams ().n_midi(), max_midi); } @@ -1711,8 +1731,6 @@ Route::apply_some_processor_counts (list& iclist) ProcessorCount& pc (*i); - cerr << "now applying for " << (*i).processor->name() << " in = " << pc.in.n_audio() << " out = " << pc.out.n_audio() << endl; - if (pc.processor->configure_io (pc.in, pc.out)) { return -1; } @@ -1743,8 +1761,6 @@ Route::check_some_processor_counts (list& iclist, ChanCount requ for (i = iclist.begin(); i != iclist.end(); ++i, ++index) { - cerr << "Checking whether " << (*i).processor->name() << " can support " << required_inputs.n_audio() << " inputs\n"; - if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) { if (err) { err->index = index; @@ -1853,7 +1869,11 @@ Route::all_processors_flip () bool first_is_on = _processors.front()->active(); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->set_active (!first_is_on); + if (first_is_on) { + (*i)->deactivate (); + } else { + (*i)->activate (); + } } _session.set_dirty (); @@ -1874,7 +1894,11 @@ Route::all_processors_active (Placement p, bool state) for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->placement() == p) { - (*i)->set_active (state); + if (state) { + (*i)->activate (); + } else { + (*i)->deactivate (); + } } } diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 58352a5dfe..d562ddff3f 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -140,7 +140,7 @@ Send::set_state(const XMLNode& node) if ((*niter)->name() == "IOProcessor") { insert_node = *niter; } else if ((*niter)->name() == X_("Automation")) { - _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation)); + // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation)); } } @@ -165,10 +165,10 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, _io->deliver_output (sendbufs, start_frame, end_frame, nframes, offset); if (_metering) { - if (_io->_gain == 0) { - _io->_meter->reset(); + if (_io->effective_gain() == 0) { + _io->peak_meter().reset(); } else { - _io->_meter->run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset); + _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset); } } @@ -176,7 +176,7 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, _io->silence (nframes, offset); if (_metering) { - _io->_meter->reset(); + _io->peak_meter().reset(); } } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 59b873e87f..6e7fe3a0f6 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -1822,7 +1823,7 @@ Session::set_remote_control_ids () } -Session::RouteList +RouteList Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many) { char bus_name[32]; @@ -3685,6 +3686,8 @@ Session::add_processor (Processor* processor) _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert); } else if ((send = dynamic_cast (processor)) != 0) { _sends.insert (_sends.begin(), send); + } else if (dynamic_cast (processor) != 0) { + /* relax */ } else { fatal << _("programming error: unknown type of Insert created!") << endmsg; /*NOTREACHED*/ @@ -3710,6 +3713,8 @@ Session::remove_processor (Processor* processor) } } else if ((plugin_insert = dynamic_cast (processor)) != 0) { _plugin_inserts.remove (plugin_insert); + } else if (dynamic_cast (processor) != 0) { + /* relax */ } else if ((send = dynamic_cast (processor)) != 0) { list::iterator x = find (_sends.begin(), _sends.end(), send); if (x != _sends.end()) { -- cgit v1.2.3