From 2fd281a285e4b0bc31e0a0dc6f970359440612c8 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 21 Sep 2007 00:46:21 +0000 Subject: Somewhat functional dynamic polyphony (LV2 and internal nodes only). git-svn-id: http://svn.drobilla.net/lad/ingen@744 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/Buffer.hpp | 5 ++-- src/libs/engine/Connection.cpp | 37 +++++++++++++++++++++++--- src/libs/engine/Connection.hpp | 9 ++++--- src/libs/engine/InputPort.cpp | 53 +++++++++---------------------------- src/libs/engine/JackAudioDriver.cpp | 18 ------------- src/libs/engine/LV2Node.cpp | 24 +++++++---------- src/libs/engine/MidiNoteNode.cpp | 12 ++++----- src/libs/engine/MidiNoteNode.hpp | 4 +-- src/libs/engine/NodeBase.cpp | 2 +- src/libs/engine/NodeFactory.cpp | 2 +- src/libs/engine/Patch.cpp | 6 +++++ src/libs/engine/Port.cpp | 13 ++++++++- 12 files changed, 92 insertions(+), 93 deletions(-) (limited to 'src/libs/engine') diff --git a/src/libs/engine/Buffer.hpp b/src/libs/engine/Buffer.hpp index 4a79c482..44b69cbe 100644 --- a/src/libs/engine/Buffer.hpp +++ b/src/libs/engine/Buffer.hpp @@ -21,13 +21,14 @@ #include #include #include +#include #include "types.hpp" #include "DataType.hpp" namespace Ingen { -class Buffer : public boost::noncopyable +class Buffer : public boost::noncopyable, public Raul::Deletable { public: Buffer(DataType type, size_t size) @@ -35,8 +36,6 @@ public: , _size(size) {} - virtual ~Buffer() {} - /** Clear contents and reset state */ virtual void clear() = 0; diff --git a/src/libs/engine/Connection.cpp b/src/libs/engine/Connection.cpp index bae72412..c2ecb2ec 100644 --- a/src/libs/engine/Connection.cpp +++ b/src/libs/engine/Connection.cpp @@ -16,6 +16,7 @@ */ #include +#include #include "util.hpp" #include "Connection.hpp" #include "Node.hpp" @@ -36,7 +37,10 @@ Connection::Connection(Port* src_port, Port* dst_port) , _dst_port(dst_port) , _local_buffer(NULL) , _buffer_size(dst_port->buffer_size()) - , _must_mix( (src_port->poly() != dst_port->poly()) + /*, _must_mix( (src_port->poly() != dst_port->poly()) + || (src_port->buffer(0)->size() < dst_port->buffer(0)->size()) )*/ + , _must_mix( (src_port->polyphonic() && (! dst_port->polyphonic())) + || (src_port->poly() != dst_port->poly() ) || (src_port->buffer(0)->size() < dst_port->buffer(0)->size()) ) , _pending_disconnection(false) { @@ -74,6 +78,33 @@ Connection::set_buffer_size(size_t size) } +void +Connection::prepare_poly(uint32_t poly) +{ + _must_mix = (type() == DataType::FLOAT) && (poly > 1) && ( + (_src_port->poly() != _dst_port->poly()) + || (_src_port->polyphonic() && !_dst_port->polyphonic()) + || (_src_port->parent()->polyphonic() && !_dst_port->parent()->polyphonic()) ); + + /*cerr << src_port()->path() << " * " << src_port()->poly() + << " -> " << dst_port()->path() << " * " << dst_port()->poly() + << "\t\tmust mix: " << _must_mix << " at poly " << poly << endl;*/ + + if (_must_mix && ! _local_buffer) + _local_buffer = BufferFactory::create(_dst_port->type(), _dst_port->buffer(0)->size()); +} + + +void +Connection::apply_poly(Raul::Maid& maid, uint32_t poly) +{ + if (poly == 1 && _local_buffer && !_must_mix) { + maid.push(_local_buffer); + _local_buffer = NULL; + } +} + + void Connection::process(SampleCount nframes, FrameTime start, FrameTime end) { @@ -97,8 +128,8 @@ Connection::process(SampleCount nframes, FrameTime start, FrameTime end) const size_t copy_size = std::min(src_buffer->size(), mix_buf->size()); - //cerr << "Mixing " << src_port()->buffer(0)->data() - // << " -> " << _local_buffer->data() << endl; + /*cerr << "[Connection] Mixing " << src_port()->path() << " * " << src_port()->poly() + << " -> " << dst_port()->path() << " * " << dst_port()->poly() << endl;*/ // Copy src buffer to start of mix buffer mix_buf->copy((AudioBuffer*)src_port()->buffer(0), 0, copy_size-1); diff --git a/src/libs/engine/Connection.hpp b/src/libs/engine/Connection.hpp index 816efe6c..44cbcccb 100644 --- a/src/libs/engine/Connection.hpp +++ b/src/libs/engine/Connection.hpp @@ -64,6 +64,8 @@ public: inline Buffer* buffer(size_t voice) const; void set_buffer_size(size_t size); + void prepare_poly(uint32_t poly); + void apply_poly(Raul::Maid& maid, uint32_t poly); DataType type() const { return _src_port->type(); } @@ -80,12 +82,13 @@ protected: inline Buffer* Connection::buffer(size_t voice) const { - if (_must_mix) + if (_must_mix) { return _local_buffer; - else if (_src_port->poly() == 1) + } else if ( ! _src_port->polyphonic()) { return _src_port->buffer(0); - else + } else { return _src_port->buffer(voice); + } } diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp index 2d76210b..1adb53a0 100644 --- a/src/libs/engine/InputPort.cpp +++ b/src/libs/engine/InputPort.cpp @@ -48,32 +48,22 @@ InputPort::add_connection(Raul::ListNode* const c) _connections.push_back(c); bool modify_buffers = !_fixed_buffers; - //if (modify_buffers && _is_tied) - // modify_buffers = !_tied_port->fixed_buffers(); if (modify_buffers) { if (_connections.size() == 1) { // Use buffer directly to avoid copying for (uint32_t i=0; i < _poly; ++i) { _buffers->at(i)->join(c->elem()->buffer(i)); - //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers->at(i)); - //assert(_buffers->at(i)->data() == c->elem()->buffer(i)->data()); } } else if (_connections.size() == 2) { // Used to directly use single connection buffer, now there's two // so have to use local ones again and mix down for (uint32_t i=0; i < _poly; ++i) { _buffers->at(i)->unjoin(); - //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers->at(i)); } } Port::connect_buffers(); } - - //assert( ! _is_tied || _tied_port != NULL); - //assert( ! _is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data()); } @@ -83,8 +73,6 @@ Raul::ListNode* InputPort::remove_connection(const OutputPort* src_port) { bool modify_buffers = !_fixed_buffers; - //if (modify_buffers && _is_tied) - // modify_buffers = !_tied_port->fixed_buffers(); bool found = false; Raul::ListNode* connection = NULL; @@ -105,15 +93,11 @@ InputPort::remove_connection(const OutputPort* src_port) if (modify_buffers) _buffers->at(i)->unjoin(); _buffers->at(i)->clear(); // Write silence - //if (_is_tied) - //m_tied_port->buffer(i)->join(_buffers->at(i)); } } else if (modify_buffers && _connections.size() == 1) { // Share a buffer for (uint32_t i=0; i < _poly; ++i) { _buffers->at(i)->join((*_connections.begin())->buffer(i)); - //if (_is_tied) - // _tied_port->buffer(i)->join(_buffers->at(i)); } } } @@ -121,9 +105,6 @@ InputPort::remove_connection(const OutputPort* src_port) if (modify_buffers) Port::connect_buffers(); - //assert( ! _is_tied || _tied_port != NULL); - //assert( ! _is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data()); - return connection; } @@ -147,8 +128,6 @@ InputPort::is_connected_to(const OutputPort* port) const void InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) { - //assert(!_is_tied || _tied_port != NULL); - bool do_mixdown = true; if (_connections.size() == 0) { @@ -160,39 +139,31 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end) for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->process(nframes, start, end); - // If only one connection, buffer is (maybe) used directly (no copying) - if (_connections.size() == 1) { - // Buffer changed since connection - if (!_buffers->at(0)->is_joined_to((*_connections.begin())->buffer(0))) { - if (_fixed_buffers) { // || (_is_tied && _tied_port->fixed_buffers())) { - // can't change buffer, must copy - do_mixdown = true; - } else { - // zero-copy - _buffers->at(0)->join((*_connections.begin())->buffer(0)); - do_mixdown = false; - } - connect_buffers(); - } else { + if ( ! _fixed_buffers) { + // If only one connection, try to use buffer directly (zero copy) + if (_connections.size() == 1) { + for (uint32_t i=0; i < _poly; ++i) + _buffers->at(i)->join((*_connections.begin())->buffer(i)); do_mixdown = false; } + connect_buffers(); + } else { + do_mixdown = true; } - //cerr << path() << " mixing: " << do_mixdown << endl; - for (uint32_t i=0; i < _poly; ++i) _buffers->at(i)->prepare_read(nframes); //cerr << path() << " poly = " << _poly << ", mixdown: " << do_mixdown << endl; if (!do_mixdown) { - assert(_buffers->at(0)->is_joined_to((*_connections.begin())->buffer(0))); +#ifndef NDEBUG + for (uint32_t i=0; i < _poly; ++i) + assert(_buffers->at(i)->is_joined_to((*_connections.begin())->buffer(i))); +#endif return; } - /*assert(!_is_tied || _tied_port != NULL); - assert(!_is_tied || _buffers->at(0)->data() == _tied_port->buffer(0)->data());*/ - if (_type == DataType::FLOAT) { for (uint32_t voice=0; voice < _poly; ++voice) { // Copy first connection diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp index b9e89189..b9cbdb60 100644 --- a/src/libs/engine/JackAudioDriver.cpp +++ b/src/libs/engine/JackAudioDriver.cpp @@ -75,33 +75,15 @@ JackAudioPort::~JackAudioPort() void JackAudioPort::prepare_buffer(jack_nframes_t nframes) { - // FIXME: Technically this doesn't need to be done every time for output ports - /*_jack_buffer->set_data((jack_default_audio_sample_t*) - jack_port_get_buffer(_jack_port, nframes)); - - _patch_port->buffer(0)->join(_jack_buffer); -*/ jack_sample_t* jack_buf = (jack_sample_t*)jack_port_get_buffer(_jack_port, nframes); AudioBuffer* patch_buf = (AudioBuffer*)_patch_port->buffer(0); if (jack_buf != _jack_buffer) { - //cerr << "Jack buffer: " << jack_buf << endl; patch_buf->set_data(jack_buf); _jack_buffer = jack_buf; } - //assert(_patch_port->tied_port() != NULL); - - // FIXME: fixed_buffers switch on/off thing can be removed once this - // gets figured out and assertions can go away - //m_patch_port->fixed_buffers(false); - //m_patch_port->buffer(0)->join(_jack_buffer); - //m_patch_port->tied_port()->buffer(0)->join(_jack_buffer); - - //m_patch_port->fixed_buffers(true); - - //assert(_patch_port->buffer(0)->data() == _patch_port->tied_port()->buffer(0)->data()); assert(patch_buf->data() == jack_buf); } diff --git a/src/libs/engine/LV2Node.cpp b/src/libs/engine/LV2Node.cpp index 6d66f332..f1b61997 100644 --- a/src/libs/engine/LV2Node.cpp +++ b/src/libs/engine/LV2Node.cpp @@ -60,7 +60,7 @@ LV2Node::prepare_poly(uint32_t poly) NodeBase::prepare_poly(poly); - if (poly <= _prepared_instances->size()) + if (_prepared_instances && poly <= _prepared_instances->size()) return true; _prepared_instances = new Raul::Array(poly, *_instances); @@ -70,11 +70,11 @@ LV2Node::prepare_poly(uint32_t poly) cerr << "Failed to instantiate plugin!" << endl; return false; } + + if (_activated) + slv2_instance_activate((*_prepared_instances)[i]); } - for (uint32_t j=0; j < num_ports(); ++j) - _ports->at(j)->prepare_poly(poly); - return true; } @@ -86,23 +86,25 @@ LV2Node::apply_poly(Raul::Maid& maid, uint32_t poly) return true; assert(poly <= _prepared_instances->size()); - - NodeBase::apply_poly(maid, poly); if (_prepared_instances) { maid.push(_instances); _instances = _prepared_instances; +#if 0 for (uint32_t port=0; port < num_ports(); ++port) - for (uint32_t voice = _polyphony; voice < _prepared_instances->size(); ++voice) + for (uint32_t voice = /*_polyphony*/0; voice < _prepared_instances->size(); ++voice) slv2_instance_connect_port((*_instances)[voice], port, _ports->at(port)->buffer(voice)->raw_data()); +#endif _prepared_instances = NULL; } _polyphony = poly; + NodeBase::apply_poly(maid, poly); + return true; } @@ -255,13 +257,7 @@ LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num, Buffer* buf) { assert(voice < _polyphony); - if (buf->type() == DataType::FLOAT) { - slv2_instance_connect_port((*_instances)[voice], port_num, ((AudioBuffer*)buf)->data()); - } else if (buf->type() == DataType::MIDI) { - slv2_instance_connect_port((*_instances)[voice], port_num, ((MidiBuffer*)buf)->data()); - } else if (buf->type() == DataType::OSC) { - slv2_instance_connect_port((*_instances)[voice], port_num, ((OSCBuffer*)buf)->data()); - } + slv2_instance_connect_port((*_instances)[voice], port_num, buf->raw_data()); } diff --git a/src/libs/engine/MidiNoteNode.cpp b/src/libs/engine/MidiNoteNode.cpp index 3ac33a68..a5b29f85 100644 --- a/src/libs/engine/MidiNoteNode.cpp +++ b/src/libs/engine/MidiNoteNode.cpp @@ -87,9 +87,10 @@ MidiNoteNode::prepare_poly(uint32_t poly) NodeBase::prepare_poly(poly); + if (_prepared_voices && poly <= _prepared_voices->size()) + return true; + _prepared_voices = new Raul::Array(poly, *_voices); - - cerr << path() << " prepared poly " << poly << endl; return true; } @@ -113,8 +114,6 @@ MidiNoteNode::apply_poly(Raul::Maid& maid, uint32_t poly) _polyphony = poly; assert(_voices->size() >= _polyphony); - cerr << path() << " applied poly " << poly << endl; - return true; } @@ -219,7 +218,8 @@ MidiNoteNode::note_on(uchar note_num, uchar velocity, FrameTime time, SampleCoun assert(voice != NULL); assert(voice == &(*_voices)[voice_num]); - //cerr << "[MidiNoteNode] Note on @ " << time << ". Key " << (int)note_num << ", Voice " << voice_num << endl; + //cerr << "[MidiNoteNode] Note " << (int)note_num << " on @ " << time + // << ". Voice " << voice_num << " / " << _polyphony << endl; // Update stolen key, if applicable if (voice->state == Voice::Voice::ACTIVE) { @@ -300,7 +300,7 @@ MidiNoteNode::note_off(uchar note_num, FrameTime time, SampleCount nframes, Fram void -MidiNoteNode::free_voice(size_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end) +MidiNoteNode::free_voice(uint32_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end) { assert(time >= start && time <= end); assert(time - start < _buffer_size); diff --git a/src/libs/engine/MidiNoteNode.hpp b/src/libs/engine/MidiNoteNode.hpp index 34a926ff..f2fbbf5d 100644 --- a/src/libs/engine/MidiNoteNode.hpp +++ b/src/libs/engine/MidiNoteNode.hpp @@ -59,7 +59,7 @@ private: struct Key { enum State { OFF, ON_ASSIGNED, ON_UNASSIGNED }; Key() : state(OFF), voice(0), time(0) {} - State state; size_t voice; SampleCount time; + State state; uint32_t voice; SampleCount time; }; /** Voice, one of these always exists for each voice */ @@ -70,7 +70,7 @@ private: }; float note_to_freq(int num); - void free_voice(size_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end); + void free_voice(uint32_t voice, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end); Raul::Array* _voices; Raul::Array* _prepared_voices; diff --git a/src/libs/engine/NodeBase.cpp b/src/libs/engine/NodeBase.cpp index 90d5864f..4f3d37b2 100644 --- a/src/libs/engine/NodeBase.cpp +++ b/src/libs/engine/NodeBase.cpp @@ -28,7 +28,7 @@ #include "Patch.hpp" #include "ObjectStore.hpp" -using std::cout; using std::cerr; using std::endl; +using namespace std; namespace Ingen { diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp index ea670ab0..fe8cf626 100644 --- a/src/libs/engine/NodeFactory.cpp +++ b/src/libs/engine/NodeFactory.cpp @@ -608,7 +608,7 @@ NodeFactory::load_ladspa_plugins() for (list::const_iterator i = _plugins.begin(); i != _plugins.end(); ++i) { if ((*i)->uri() == plugin->uri()) { cerr << "Warning: Duplicate LADSPA plugin " << plugin->uri() - << " found.\nChoosing " << (*i)->lib_path() + << " found.\n Choosing " << (*i)->lib_path() << " over " << plugin->lib_path() << endl; found = true; break; diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp index 3d8e7756..2705db36 100644 --- a/src/libs/engine/Patch.cpp +++ b/src/libs/engine/Patch.cpp @@ -115,6 +115,9 @@ Patch::prepare_internal_poly(uint32_t poly) for (Raul::List::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->prepare_poly(poly); + + for (Raul::List::iterator i = _connections.begin(); i != _connections.end(); ++i) + (*i)->prepare_poly(poly); /* FIXME: Deal with failure */ @@ -129,6 +132,9 @@ Patch::apply_internal_poly(Raul::Maid& maid, uint32_t poly) for (Raul::List::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->apply_poly(maid, poly); + + for (Raul::List::iterator i = _connections.begin(); i != _connections.end(); ++i) + (*i)->apply_poly(maid, poly); _internal_poly = poly; diff --git a/src/libs/engine/Port.cpp b/src/libs/engine/Port.cpp index bcf47e90..30ee73f2 100644 --- a/src/libs/engine/Port.cpp +++ b/src/libs/engine/Port.cpp @@ -31,7 +31,7 @@ const char* const DataType::type_uris[4] = { "UNKNOWN", "FLOAT", "MIDI", "OSC" } Port::Port(Node* const node, const string& name, uint32_t index, uint32_t poly, DataType type, size_t buffer_size) - : GraphObject(node, name) + : GraphObject(node, name, true) , _index(index) , _poly(poly) , _type(type) @@ -45,6 +45,9 @@ Port::Port(Node* const node, const string& name, uint32_t index, uint32_t poly, allocate_buffers(); clear_buffers(); + if (node->parent() == NULL) + _polyphonic = false; + assert(_buffers->size() > 0); } @@ -61,6 +64,9 @@ Port::~Port() bool Port::prepare_poly(uint32_t poly) { + if (!_polyphonic || !_parent->polyphonic()) + return true; + /* FIXME: poly never goes down, harsh on memory.. */ if (poly > _poly) { _prepared_buffers = new Raul::Array(poly, *_buffers); @@ -76,6 +82,9 @@ Port::prepare_poly(uint32_t poly) bool Port::apply_poly(Raul::Maid& maid, uint32_t poly) { + if (!_polyphonic || !_parent->polyphonic()) + return true; + assert(poly <= _prepared_poly); // Apply a new set of buffers from a preceding call to prepare_poly @@ -86,6 +95,8 @@ Port::apply_poly(Raul::Maid& maid, uint32_t poly) _poly = poly; + connect_buffers(); + return true; } -- cgit v1.2.1