From 84906b5777d6748c09dd5ca56169aa3366d13c71 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 2 Jan 2007 02:51:41 +0000 Subject: Initial work on dynamic (Jack) buffer resizing (still unworking). git-svn-id: http://svn.drobilla.net/lad/ingen@229 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/Buffer.cpp | 193 +++++++++++++++++++----------------- src/libs/engine/Buffer.h | 50 +++------- src/libs/engine/Connection.h | 2 + src/libs/engine/Engine.cpp | 5 +- src/libs/engine/InputPort.cpp | 39 ++++---- src/libs/engine/InputPort.h | 5 +- src/libs/engine/JackAudioDriver.cpp | 10 +- src/libs/engine/Node.h | 3 +- src/libs/engine/NodeBase.cpp | 11 ++ src/libs/engine/NodeBase.h | 2 + src/libs/engine/Patch.cpp | 11 ++ src/libs/engine/Patch.h | 2 + src/libs/engine/Port.h | 3 + src/libs/engine/TypedConnection.cpp | 16 +++ src/libs/engine/TypedConnection.h | 2 + src/libs/engine/TypedPort.cpp | 35 ++++++- src/libs/engine/TypedPort.h | 3 + 17 files changed, 232 insertions(+), 160 deletions(-) (limited to 'src/libs') diff --git a/src/libs/engine/Buffer.cpp b/src/libs/engine/Buffer.cpp index af655a19..4cca362e 100644 --- a/src/libs/engine/Buffer.cpp +++ b/src/libs/engine/Buffer.cpp @@ -29,44 +29,76 @@ namespace Ingen { template Buffer::Buffer(size_t size) -: m_size(size), - m_filled_size(0), - m_is_joined(false), - m_state(OK), - m_set_value(0), - m_data(NULL), - m_local_data(NULL) +: _data(NULL), + _local_data(NULL), + _joined_buf(NULL), + _size(size), + _filled_size(0), + _state(OK), + _set_value(0) { - assert(m_size > 0); + assert(_size > 0); allocate(); - assert(m_data); + assert(data()); } template Buffer::Buffer(size_t size); template Buffer::Buffer(size_t size); +template +void +Buffer::resize(size_t size) +{ + _size = size; + + T* const old_data = _data; + + const bool using_local_data = (_data == _local_data); + + deallocate(); + + const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(T)); + if (ret != 0) { + cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; + exit(EXIT_FAILURE); + } + + assert(ret == 0); + assert(_local_data); + + if (using_local_data) + _data = _local_data; + else + _data = old_data; + + set(0, 0, _size-1); +} +template void Buffer::resize(size_t size); +template void Buffer::resize(size_t size); + + /** Allocate and use a locally managed buffer (data). */ template void Buffer::allocate() { - assert(!m_is_joined); - assert(m_data == NULL); - assert(m_local_data == NULL); - assert(m_size > 0); + assert(!_joined_buf); + assert(_local_data == NULL); + assert(_size > 0); - const int ret = posix_memalign((void**)&m_local_data, 16, m_size * sizeof(T)); + const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(T)); if (ret != 0) { cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; exit(EXIT_FAILURE); } assert(ret == 0); - assert(m_local_data != NULL); - m_data = m_local_data; + assert(_local_data); - set(0, 0, m_size-1); + _data = _local_data; + + set(0, 0, _size-1); } template void Buffer::allocate(); template void Buffer::allocate(); @@ -78,11 +110,10 @@ template void Buffer::deallocate() { - assert(!m_is_joined); - free(m_local_data); - if (m_data == m_local_data) - m_data = NULL; - m_local_data = NULL; + assert(!_joined_buf); + free(_local_data); + _local_data = NULL; + _data = NULL; } template void Buffer::deallocate(); template void Buffer::deallocate(); @@ -94,9 +125,9 @@ template void Buffer::clear() { - set(0, 0, m_size-1); - m_state = OK; - m_filled_size = 0; + set(0, 0, _size-1); + _state = OK; + _filled_size = 0; } template void Buffer::clear(); template void Buffer::clear(); @@ -112,14 +143,14 @@ template void Buffer::set(T val, size_t start_sample) { - assert(start_sample < m_size); + assert(start_sample < _size); - set(val, start_sample, m_size-1); + set(val, start_sample, _size-1); if (start_sample > 0) - m_state = HALF_SET_CYCLE_1; + _state = HALF_SET_CYCLE_1; - m_set_value = val; + _set_value = val; } template void Buffer::set(Sample val, size_t start_sample); template void Buffer::set(MidiMessage val, size_t start_sample); @@ -134,11 +165,13 @@ void Buffer::set(T val, size_t start_sample, size_t end_sample) { assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(m_data != NULL); + assert(end_sample < _size); + + T* const buf = data(); + assert(buf); for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] = val; + buf[i] = val; } template void Buffer::set(Sample val, size_t start_sample, size_t end_sample); template void Buffer::set(MidiMessage val, size_t start_sample, size_t end_sample); @@ -153,11 +186,13 @@ void Buffer::scale(T val, size_t start_sample, size_t end_sample) { assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(m_data != NULL); + assert(end_sample < _size); + + T* const buf = data(); + assert(buf); for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] *= val; + buf[i] *= val; } template void Buffer::scale(Sample val, size_t start_sample, size_t end_sample); @@ -172,15 +207,17 @@ void Buffer::copy(const Buffer* src, size_t start_sample, size_t end_sample) { assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(src != NULL); - assert(src->data() != NULL); - assert(m_data != NULL); + assert(end_sample < _size); + assert(src); + + T* const buf = data(); + assert(buf); - register const T* const src_data = src->data(); + const T* const src_buf = src->data(); + assert(src_buf); for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] = src_data[i]; + buf[i] = src_buf[i]; } template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); @@ -196,15 +233,17 @@ void Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample) { assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(src != NULL); - assert(src->data() != NULL); - assert(m_data != NULL); - - register const T* const src_data = src->data(); + assert(end_sample < _size); + assert(src); + T* const buf = data(); + assert(buf); + + const T* const src_buf = src->data(); + assert(src_buf); + for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] += src_data[i]; + buf[i] += src_buf[i]; } template void Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample); @@ -218,13 +257,12 @@ template void Buffer::join(Buffer* buf) { - assert(buf->size() == m_size); + assert(buf->size() == _size); - m_data = buf->m_data; - m_filled_size = buf->filled_size(); - m_is_joined = true; + _joined_buf = buf; + _filled_size = buf->filled_size(); - assert(m_filled_size <= m_size); + assert(_filled_size <= _size); } template void Buffer::join(Buffer* buf); template void Buffer::join(Buffer* buf); @@ -234,8 +272,8 @@ template void Buffer::unjoin() { - m_is_joined = false; - m_data = m_local_data; + _joined_buf = NULL; + _data = _local_data; } template void Buffer::unjoin(); template void Buffer::unjoin(); @@ -247,15 +285,15 @@ Buffer::prepare(SampleCount nframes) { // FIXME: nframes parameter doesn't actually work, // writing starts from 0 every time - assert(m_size == 1 || nframes == m_size); + assert(_size == 1 || nframes == _size); - switch (m_state) { + switch (_state) { case HALF_SET_CYCLE_1: - m_state = HALF_SET_CYCLE_2; + _state = HALF_SET_CYCLE_2; break; case HALF_SET_CYCLE_2: - set(m_set_value, 0, m_size-1); - m_state = OK; + set(_set_value, 0, _size-1); + _state = OK; break; default: break; @@ -276,41 +314,14 @@ Buffer::prepare(SampleCount nframes) */ template void -Buffer::set_data(T* data) +Buffer::set_data(T* buf) { - assert(!m_is_joined); - m_data = data; + assert(buf); + assert(!_joined_buf); + _data = buf; } template void Buffer::set_data(Sample* data); template void Buffer::set_data(MidiMessage* data); -////// DriverBuffer //////// -#if 0 -template -DriverBuffer::DriverBuffer(size_t size) -: Buffer(size) -{ - Buffer::deallocate(); // FIXME: allocate then immediately deallocate, dirty - Buffer::m_data = NULL; -} -template DriverBuffer::DriverBuffer(size_t size); -template DriverBuffer::DriverBuffer(size_t size); - - -/** Set the buffer (data) used. - * - * This is only to be used by Drivers (to provide zero-copy processing). - */ -template -void -DriverBuffer::set_data(T* data) -{ - assert(!m_is_joined); - m_data = data; -} -template void DriverBuffer::set_data(sample* data); -template void DriverBuffer::set_data(MidiMessage* data); -#endif - } // namespace Ingen diff --git a/src/libs/engine/Buffer.h b/src/libs/engine/Buffer.h index 13c75bbc..2dfaea81 100644 --- a/src/libs/engine/Buffer.h +++ b/src/libs/engine/Buffer.h @@ -43,49 +43,31 @@ public: /** For driver use only!! */ void set_data(T* data); - inline T& value_at(size_t offset) { assert(offset < m_size); return m_data[offset]; } + inline T& value_at(size_t offset) { assert(offset < _size); return data()[offset]; } void prepare(SampleCount nframes); - void filled_size(size_t size) { m_filled_size = size; } - size_t filled_size() const { return m_filled_size; } - bool is_joined() const { return m_is_joined; } - size_t size() const { return m_size; } - T* data() const { return m_data; } + void filled_size(size_t size) { _filled_size = size; } + size_t filled_size() const { return _filled_size; } + bool is_joined() const { return (_joined_buf == NULL); } + size_t size() const { return _size; } + inline T* data() const { return ((_joined_buf != NULL) ? _joined_buf->data() : _data); } + + void resize(size_t size); -protected: +private: enum BufferState { OK, HALF_SET_CYCLE_1, HALF_SET_CYCLE_2 }; void allocate(); void deallocate(); - size_t m_size; ///< Allocated buffer size - size_t m_filled_size; ///< Usable buffer size (for MIDI ports etc) - bool m_is_joined; ///< Whether or not @ref m_data is shares with another Buffer - BufferState m_state; ///< State of buffer for setting values next cycle - T m_set_value; ///< Value set by @ref set (may need to be set next cycle) - - T* m_data; ///< Buffer to be returned by data() (not equal to m_local_data if joined) - T* m_local_data; ///< Locally allocated buffer -}; - - -/** Less robust Buffer for Driver's use. - * - * Does not allocate an array by default, and allows direct setting of - * data pointer for zero-copy processing. - */ -template -class DriverBuffer : public Buffer -{ -public: - DriverBuffer(size_t size); - - - -private: - using Buffer::m_data; - using Buffer::m_is_joined; + T* _data; ///< Used data pointer (probably same as _local_data) + T* _local_data; ///< Locally allocated buffer (possibly unused if joined or set_data used) + Buffer* _joined_buf; ///< Buffer to mirror, if joined + size_t _size; ///< Allocated buffer size + size_t _filled_size; ///< Usable buffer size (for MIDI ports etc) + BufferState _state; ///< State of buffer for setting values next cycle + T _set_value; ///< Value set by @ref set (may need to be set next cycle) }; diff --git a/src/libs/engine/Connection.h b/src/libs/engine/Connection.h index 68ab5a3d..3fe86f94 100644 --- a/src/libs/engine/Connection.h +++ b/src/libs/engine/Connection.h @@ -49,6 +49,8 @@ public: bool pending_disconnection() { return m_pending_disconnection; } void pending_disconnection(bool b) { m_pending_disconnection = b; } + virtual void set_buffer_size(size_t size) {} + protected: Connection(Port* const src_port, Port* const dst_port); diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp index 56245534..b83c7244 100644 --- a/src/libs/engine/Engine.cpp +++ b/src/libs/engine/Engine.cpp @@ -157,8 +157,7 @@ Engine::activate(SharedPtr ad, SharedPtr es) // Set event source (FIXME: handle multiple sources) m_event_source = es; - - m_audio_driver->activate(); + m_event_source->activate(); // Create root patch @@ -170,7 +169,7 @@ Engine::activate(SharedPtr ad, SharedPtr es) enable_ev.pre_process(); enable_ev.execute(1, 0, 1); enable_ev.post_process(); - + assert(m_audio_driver->root_patch() != NULL); m_audio_driver->activate(); diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp index 830b370c..8b170958 100644 --- a/src/libs/engine/InputPort.cpp +++ b/src/libs/engine/InputPort.cpp @@ -71,7 +71,7 @@ InputPort::add_connection(ListNode*>* const c) // m_tied_port->buffer(i)->join(m_buffers.at(i)); } } - update_buffers(); + TypedPort::connect_buffers(); } //assert( ! m_is_tied || m_tied_port != NULL); @@ -125,7 +125,7 @@ InputPort::remove_connection(const OutputPort* const src_port) } if (modify_buffers) - update_buffers(); + TypedPort::connect_buffers(); //assert( ! m_is_tied || m_tied_port != NULL); //assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); @@ -138,22 +138,6 @@ template ListNode*>* InputPort::remove_connection(const OutputPort* const src_port); -/** Update any changed buffers with the plugin this is a port on. - * - * This calls ie the LADSPA connect_port function when buffers have been changed - * due to a connection or disconnection. - */ -template -void -InputPort::update_buffers() -{ - for (size_t i=0; i < _poly; ++i) - InputPort::parent_node()->set_port_buffer(i, _index, m_buffers.at(i)->data()); -} -template void InputPort::update_buffers(); -template void InputPort::update_buffers(); - - /** Returns whether this port is connected to the passed port. */ template @@ -234,7 +218,7 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); do_mixdown = false; } - update_buffers(); + connect_buffers(); } else { do_mixdown = false; } @@ -303,7 +287,7 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime // m_tied_port->buffer(0)->join(m_buffers.at(0)); do_mixdown = false; } - update_buffers(); + connect_buffers(); } else { do_mixdown = false; } @@ -349,5 +333,20 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime } +template +void +InputPort::set_buffer_size(size_t size) +{ + TypedPort::set_buffer_size(size); + assert(_buffer_size = size); + + for (typename List*>::iterator c = m_connections.begin(); c != m_connections.end(); ++c) + (*c)->set_buffer_size(size); + +} +template void InputPort::set_buffer_size(size_t size); +template void InputPort::set_buffer_size(size_t size); + + } // namespace Ingen diff --git a/src/libs/engine/InputPort.h b/src/libs/engine/InputPort.h index d1060042..1fc90246 100644 --- a/src/libs/engine/InputPort.h +++ b/src/libs/engine/InputPort.h @@ -50,7 +50,7 @@ public: InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); virtual ~InputPort() {} - void add_connection(ListNode*>* const c); + void add_connection(ListNode*>* const c); ListNode*>* remove_connection(const OutputPort* const src_port); const List*>& connections() { return m_connections; } @@ -63,8 +63,9 @@ public: bool is_input() const { return true; } bool is_output() const { return false; } + virtual void set_buffer_size(size_t size); + private: - void update_buffers(); List*> m_connections; diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp index 81f15a78..082afe5a 100644 --- a/src/libs/engine/JackAudioDriver.cpp +++ b/src/libs/engine/JackAudioDriver.cpp @@ -302,8 +302,8 @@ JackAudioDriver::_process_cb(jack_nframes_t nframes) } // Run root patch - assert(_root_patch != NULL); - _root_patch->process(nframes, start_of_current_cycle, start_of_current_cycle + nframes); + if (_root_patch) + _root_patch->process(nframes, start_of_current_cycle, start_of_current_cycle + nframes); return 0; } @@ -333,10 +333,8 @@ JackAudioDriver::_sample_rate_cb(jack_nframes_t nframes) int JackAudioDriver::_buffer_size_cb(jack_nframes_t nframes) { - if (_is_activated) { - cerr << "[JackAudioDriver] On-the-fly buffer size changing not supported (yet). Aborting." << endl; - exit(EXIT_FAILURE); - } else { + if (_root_patch) { + _root_patch->set_buffer_size(nframes); _buffer_size = nframes; } return 0; diff --git a/src/libs/engine/Node.h b/src/libs/engine/Node.h index beabb7da..7a4600ee 100644 --- a/src/libs/engine/Node.h +++ b/src/libs/engine/Node.h @@ -112,8 +112,7 @@ public: virtual void remove_from_patch() = 0; - /** Send any necessary notification to client on node creation. */ - //virtual void send_creation_messages(Shared::ClientInterface* client) const = 0; + virtual void set_buffer_size(size_t size) = 0; }; diff --git a/src/libs/engine/NodeBase.cpp b/src/libs/engine/NodeBase.cpp index abba3c33..1462e3bf 100644 --- a/src/libs/engine/NodeBase.cpp +++ b/src/libs/engine/NodeBase.cpp @@ -125,6 +125,17 @@ NodeBase::remove_from_store() } +void +NodeBase::set_buffer_size(size_t size) +{ + _buffer_size = size; + + if (_ports) + for (size_t i=0; i < _ports->size(); ++i) + _ports->at(i)->set_buffer_size(size); +} + + /** Runs the Node for the specified number of frames (block size) */ void diff --git a/src/libs/engine/NodeBase.h b/src/libs/engine/NodeBase.h index 2159ff9d..d48dd1a1 100644 --- a/src/libs/engine/NodeBase.h +++ b/src/libs/engine/NodeBase.h @@ -56,6 +56,8 @@ public: virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) {} + virtual void set_buffer_size(size_t size); + virtual void add_to_patch() {} virtual void remove_from_patch() {} diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp index 747d60c7..967623e5 100644 --- a/src/libs/engine/Patch.cpp +++ b/src/libs/engine/Patch.cpp @@ -137,6 +137,17 @@ Patch::process(SampleCount nframes, FrameTime start, FrameTime end) (*i)->process(nframes, start, end); } + +void +Patch::set_buffer_size(size_t size) +{ + NodeBase::set_buffer_size(size); + assert(_buffer_size == size); + + for (List::iterator j = _nodes.begin(); j != _nodes.end(); ++j) + (*j)->set_buffer_size(size); +} + void Patch::add_to_store(ObjectStore* store) diff --git a/src/libs/engine/Patch.h b/src/libs/engine/Patch.h index e02731ff..b7fe5718 100644 --- a/src/libs/engine/Patch.h +++ b/src/libs/engine/Patch.h @@ -56,6 +56,8 @@ public: void process(SampleCount nframes, FrameTime start, FrameTime end); + void set_buffer_size(size_t size); + //void send_creation_messages(ClientInterface* client) const; void add_to_store(ObjectStore* store); diff --git a/src/libs/engine/Port.h b/src/libs/engine/Port.h index 273ff690..90dbdd00 100644 --- a/src/libs/engine/Port.h +++ b/src/libs/engine/Port.h @@ -64,6 +64,9 @@ public: DataType type() const { return _type; } size_t buffer_size() const { return _buffer_size; } + virtual void set_buffer_size(size_t size) = 0; + virtual void connect_buffers() = 0; + protected: Port(Node* const node, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); diff --git a/src/libs/engine/TypedConnection.cpp b/src/libs/engine/TypedConnection.cpp index a0cd01e6..d4391fab 100644 --- a/src/libs/engine/TypedConnection.cpp +++ b/src/libs/engine/TypedConnection.cpp @@ -61,6 +61,22 @@ template TypedConnection::~TypedConnection(); template TypedConnection::~TypedConnection(); +/** Allocate a mixdown buffer if necessary */ +template +void +TypedConnection::set_buffer_size(size_t size) +{ + if (m_must_mix) { + assert(m_local_buffer); + delete m_local_buffer; + + m_local_buffer = new Buffer(size); + } + + m_buffer_size = size; +} + + template void TypedConnection::process(SampleCount nframes, FrameTime start, FrameTime end) diff --git a/src/libs/engine/TypedConnection.h b/src/libs/engine/TypedConnection.h index 7f142f9d..c6b0b0cf 100644 --- a/src/libs/engine/TypedConnection.h +++ b/src/libs/engine/TypedConnection.h @@ -55,6 +55,8 @@ public: */ inline Buffer* buffer(size_t voice) const; + void set_buffer_size(size_t size); + private: Buffer* m_local_buffer; ///< Only used for poly->mono connections bool m_must_mix; diff --git a/src/libs/engine/TypedPort.cpp b/src/libs/engine/TypedPort.cpp index 4cc184e6..d2825b17 100644 --- a/src/libs/engine/TypedPort.cpp +++ b/src/libs/engine/TypedPort.cpp @@ -100,11 +100,33 @@ template void TypedPort::allocate_buffers(); template void -TypedPort::process(SampleCount nframes, FrameTime start, FrameTime end) +TypedPort::set_buffer_size(size_t size) { + _buffer_size = size; + for (size_t i=0; i < _poly; ++i) - m_buffers.at(i)->prepare(nframes); + m_buffers.at(i)->resize(size); + + connect_buffers(); } +template void TypedPort::set_buffer_size(size_t size); +template void TypedPort::set_buffer_size(size_t size); + + +/** Update any changed buffers with the plugin this is a port on. + * + * This calls ie the LADSPA connect_port function when buffers have been changed + * due to a connection, disconnection, resize, etc. + */ +template +void +TypedPort::connect_buffers() +{ + for (size_t i=0; i < _poly; ++i) + TypedPort::parent_node()->set_port_buffer(i, _index, m_buffers.at(i)->data()); +} +template void TypedPort::connect_buffers(); +template void TypedPort::connect_buffers(); template @@ -118,5 +140,14 @@ template void TypedPort::clear_buffers(); template void TypedPort::clear_buffers(); +template +void +TypedPort::process(SampleCount nframes, FrameTime start, FrameTime end) +{ + for (size_t i=0; i < _poly; ++i) + m_buffers.at(i)->prepare(nframes); +} + + } // namespace Ingen diff --git a/src/libs/engine/TypedPort.h b/src/libs/engine/TypedPort.h index 2647d8ce..56d6fc51 100644 --- a/src/libs/engine/TypedPort.h +++ b/src/libs/engine/TypedPort.h @@ -56,10 +56,13 @@ public: void fixed_buffers(bool b) { m_fixed_buffers = b; } bool fixed_buffers() { return m_fixed_buffers; } + virtual void set_buffer_size(size_t size); + protected: TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); void allocate_buffers(); + void connect_buffers(); bool m_fixed_buffers; -- cgit v1.2.1