summaryrefslogtreecommitdiffstats
path: root/src/engine/InputPort.cpp
diff options
context:
space:
mode:
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;
- }*/
}