summaryrefslogtreecommitdiffstats
path: root/src/engine/InputPort.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-11-16 00:30:35 +0000
committerDavid Robillard <d@drobilla.net>2009-11-16 00:30:35 +0000
commit3d89115a67a9c947a28539ffdd2399808a53279b (patch)
tree826b900de3979eed9c31aae0d3ac560d39b53460 /src/engine/InputPort.cpp
parent597fa9212f27d2448c0cdd20fbf616928c662cc1 (diff)
downloadingen-3d89115a67a9c947a28539ffdd2399808a53279b.tar.gz
ingen-3d89115a67a9c947a28539ffdd2399808a53279b.tar.bz2
ingen-3d89115a67a9c947a28539ffdd2399808a53279b.zip
Rework objects extension to have "value ports" and "message ports".
Make audio and control buffers in ingen actually object buffers (towards interop). Overhaul the hell out of ingen buffer and mixing stuff. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2266 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/InputPort.cpp')
-rw-r--r--src/engine/InputPort.cpp191
1 files changed, 68 insertions, 123 deletions
diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp
index 5d3a0627..4182e862 100644
--- a/src/engine/InputPort.cpp
+++ b/src/engine/InputPort.cpp
@@ -27,6 +27,7 @@
#include "OutputPort.hpp"
#include "ProcessContext.hpp"
#include "ThreadManager.hpp"
+#include "BufferFactory.hpp"
#include "util.hpp"
using namespace std;
@@ -36,14 +37,15 @@ namespace Ingen {
namespace Shared { class Patch; }
using namespace Shared;
-InputPort::InputPort(NodeImpl* parent,
+InputPort::InputPort(BufferFactory& bufs,
+ NodeImpl* parent,
const string& name,
uint32_t index,
uint32_t poly,
DataType type,
const Raul::Atom& value,
size_t buffer_size)
- : PortImpl(parent, name, index, poly, type, value, buffer_size)
+ : PortImpl(bufs, parent, name, index, poly, type, value, buffer_size)
{
if (!dynamic_cast<Patch*>(parent))
add_property("rdf:type", Raul::Atom(Raul::Atom::URI, "lv2:InputPort"));
@@ -53,28 +55,32 @@ InputPort::InputPort(NodeImpl* parent,
bool
InputPort::can_direct() const
{
- return _connections.size() == 1 && _connections.front()->can_direct();
+ return _connections.size() == 1
+ && _connections.front()->src_port()->poly() == poly()
+ && (_connections.front()->src_port()->type() == type()
+ || (_connections.front()->src_port()->type() == DataType::AUDIO
+ && type() == DataType::CONTROL));
}
void
-InputPort::set_buffer_size(size_t size)
+InputPort::set_buffer_size(BufferFactory& bufs, size_t size)
{
- PortImpl::set_buffer_size(size);
+ PortImpl::set_buffer_size(bufs, size);
assert(_buffer_size = size);
for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c)
- ((ConnectionImpl*)c->get())->set_buffer_size(size);
+ ((ConnectionImpl*)c->get())->set_buffer_size(bufs, size);
}
bool
-InputPort::prepare_poly(uint32_t poly)
+InputPort::prepare_poly(BufferFactory& bufs, uint32_t poly)
{
- PortImpl::prepare_poly(poly);
+ PortImpl::prepare_poly(bufs, poly);
for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c)
- ((ConnectionImpl*)c->get())->prepare_poly(poly);
+ ((ConnectionImpl*)c->get())->prepare_poly(bufs, poly);
return true;
}
@@ -92,47 +98,51 @@ InputPort::apply_poly(Raul::Maid& maid, uint32_t poly)
PortImpl::apply_poly(maid, poly);
assert(this->poly() == poly);
- if (can_direct()) {
+ if (_connections.size() == 1) {
ConnectionImpl* c = _connections.begin()->get();
- for (uint32_t i=_poly; i < poly; ++i)
- _buffers->at(i)->join(c->buffer(i));
+ for (uint32_t v = _poly; v < poly; ++v)
+ _buffers->at(v) = c->buffer(v);
}
- for (uint32_t i=0; i < _poly; ++i)
+ for (uint32_t i = 0; i < _poly; ++i)
PortImpl::parent_node()->set_port_buffer(i, _index, buffer(i));
return true;
}
+/** Connect buffers to the appropriate locations based on the current connections */
+void
+InputPort::connect_buffers()
+{
+ // Single connection now, use it directly
+ if (_connections.size() == 1) {
+ for (uint32_t v = 0; v < _poly; ++v)
+ _buffers->at(v) = _connections.front()->buffer(v);
+
+ // Use local buffers
+ } else {
+ for (uint32_t v = 0; v < _poly; ++v)
+ _buffers->at(v) = _bufs.get(type()); // Use local buffer
+ }
+
+ // Connect node to buffers
+ PortImpl::connect_buffers();
+}
+
+
/** Add a connection. Realtime safe.
*
* The buffer of this port will be set directly to the connection's buffer
- * if there is only one connection, since no mixing needs to take place.
+ * if there is only one connection, since no copying/mixing needs to take place.
*/
void
InputPort::add_connection(Connections::Node* const c)
{
assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
- const bool could_direct = can_direct();
-
_connections.push_back(c);
-
- if (!_fixed_buffers) {
- if (can_direct()) {
- // Use buffer directly to avoid copying
- for (uint32_t i=0; i < _poly; ++i) {
- _buffers->at(i)->join(c->elem()->buffer(i));
- }
- } else if (could_direct) {
- // Used to directly use single connection's buffer(s),
- // but now there's two so use the local ones again and mix down
- for (uint32_t i=0; i < _poly; ++i) {
- _buffers->at(i)->unjoin();
- }
- }
- }
+ connect_buffers();
// Automatically broadcast connected control inputs
if (_type == DataType::CONTROL)
@@ -146,38 +156,23 @@ InputPort::remove_connection(const OutputPort* src_port)
{
assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
- bool found = false;
Connections::Node* connection = NULL;
- for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) {
- if ((*i)->src_port() == src_port) {
+ for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i)
+ if ((*i)->src_port() == src_port)
connection = _connections.erase(i);
- found = true;
- }
- }
- if ( ! found) {
- cerr << "WARNING: [InputPort::remove_connection] Connection not found !" << endl;
- exit(EXIT_FAILURE);
- } else {
- if (_connections.size() == 0) {
- for (uint32_t i=0; i < _poly; ++i) {
- // Use a local buffer
- if (!_fixed_buffers)
- _buffers->at(i)->unjoin();
- _buffers->at(i)->clear(); // Write silence
- }
- } else if (_connections.size() == 1 && !_fixed_buffers && can_direct()) {
- // Share a buffer
- for (uint32_t i=0; i < _poly; ++i) {
- _buffers->at(i)->join(_connections.front()->buffer(i));
- }
- }
+ if ( ! connection) {
+ cerr << "ERROR: [InputPort::remove_connection] Connection not found!" << endl;
+ return NULL;
}
- if (!_fixed_buffers)
- PortImpl::connect_buffers();
+ connect_buffers();
- // Turn off broadcasting if we're not connected any more (FIXME: not quite right..)
+ if (_connections.size() == 0)
+ for (uint32_t v = 0; v < _poly; ++v)
+ buffer(v)->clear();
+
+ // Turn off broadcasting if we're no longer connected
if (_type == DataType::CONTROL && _connections.size() == 0)
_broadcast = false;
@@ -190,74 +185,31 @@ InputPort::remove_connection(const OutputPort* src_port)
void
InputPort::pre_process(Context& context)
{
- // If value has been set (e.g. events pushed) by the user,
- // don't do anything this cycle to avoid smashing the value
+ // If value has been set (e.g. events pushed) by the user, don't smash it
if (_set_by_user)
return;
- // No connections, just prepare buffers for reading by our node
- if (_connections.size() == 0) {
- for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_read(context);
- return;
- }
+ //connect_buffers();
+ // Process connections (mix down polyphony, if necessary)
for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c)
(*c)->process(context);
- if (!_fixed_buffers) {
- // Single (matching) connection, use buffer(s) directly (zero copy)
- if (can_direct()) {
- for (uint32_t i=0; i < _poly; ++i) {
- _buffers->at(i)->join(_connections.front()->buffer(i));
- _buffers->at(i)->prepare_read(context);
- }
- connect_buffers();
- return;
- }
-
- connect_buffers();
- }
-
- /*cerr << path() << " poly = " << _poly << ", fixed buffers: " << _fixed_buffers
- << ", joined: " << _buffers->at(0)->is_joined()
- << " to " << _buffers->at(0)->joined_buffer() << endl;*/
-
- /*if (type() == DataType::EVENT)
- for (uint32_t i=0; i < _poly; ++i)
- if (((EventBuffer*)buffer(i))->event_count() > 0)
- cerr << path() << " (" << buffer(i) << ") # events: "
- << ((EventBuffer*)buffer(i))->event_count()
- << ", joined: " << _buffers->at(i)->is_joined() << endl;*/
-
- // Mix down all incoming connection to buffers
-
- if (_type == DataType::CONTROL || _type == DataType::AUDIO) {
- for (uint32_t voice=0; voice < _poly; ++voice) {
+ // Multiple connections, mix them all into our local buffers
+ if (_connections.size() > 1) {
+ for (uint32_t v = 0; v < _poly; ++v) {
// Copy first connection
- buffer(voice)->copy(context, _connections.front()->buffer(voice));
-
- // Accumulate the rest
- if (_connections.size() > 1) {
- Connections::iterator c = _connections.begin();
- for (++c; c != _connections.end(); ++c)
- ((AudioBuffer*)buffer(voice))->accumulate(
- ((AudioBuffer*)(*c)->buffer(voice)), 0, _buffer_size-1);
- }
- }
- } else {
- assert(_poly == 1);
+ buffer(v)->copy(context, _connections.front()->buffer(v).get());
- // FIXME
- if (_connections.size() > 1)
- cerr << "WARNING: MIDI mixing not implemented, only first connection used." << endl;
-
- // Copy first connection
- buffer(0)->copy(context, _connections.front()->buffer(0));
+ // Mix in the rest
+ Connections::iterator c = _connections.begin();
+ for (++c; c != _connections.end(); ++c)
+ buffer(v)->mix(context, (*c)->buffer(v).get());
+ }
}
- for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_read(context);
+ for (uint32_t v = 0; v < _poly; ++v)
+ buffer(v)->prepare_read(context);
if (_broadcast)
broadcast_value(context, false);
@@ -269,17 +221,10 @@ InputPort::post_process(Context& context)
{
// Prepare buffers for next cycle
if (!can_direct())
- for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_write(context);
+ for (uint32_t v = 0; v < _poly; ++v)
+ buffer(v)->prepare_write(context);
_set_by_user = false;
-
- /*if (_broadcast && (_type == DataType::CONTROL)) {
- const Sample value = ((AudioBuffer*)(*_buffers)[0])->value_at(0);
-
- cerr << path() << " input post: buffer: " << buffer(0) << " value = "
- << value << " (last " << _last_broadcasted_value << ")" <<endl;
- }*/
}