summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-03-20 03:27:33 +0100
committerDavid Robillard <d@drobilla.net>2017-03-20 03:27:33 +0100
commit9f1f6485c99e90831bbcebaa35831ff76b2204ed (patch)
tree608d084815b27ee59af77683d13020d24aa9c36f /src/server
parent59f579df71e52207bcdda15d4abb3562fdc1d6f2 (diff)
downloadingen-9f1f6485c99e90831bbcebaa35831ff76b2204ed.tar.gz
ingen-9f1f6485c99e90831bbcebaa35831ff76b2204ed.tar.bz2
ingen-9f1f6485c99e90831bbcebaa35831ff76b2204ed.zip
Always use sample accurate controls
This changes control port buffers to always be sequences of float, splitting cycles internally so nodes with control ports act as if they support sample accurate control input and output. This allows things like having networks of control ports manipulated by the user which are run into CV ports and having sample accurate changes end up in the CV ports even though the values were calculated by plugins with single float ports. Further work is probably necessary to thin and smooth changes that come from a user drag (perhaps there should be a mode for this?) to keep the amount of cycle splitting reasonable, and support for plugins with fixed block length.
Diffstat (limited to 'src/server')
-rw-r--r--src/server/ArcImpl.cpp16
-rw-r--r--src/server/BlockImpl.cpp11
-rw-r--r--src/server/Buffer.cpp7
-rw-r--r--src/server/Buffer.hpp8
-rw-r--r--src/server/InputPort.cpp4
-rw-r--r--src/server/LV2Block.cpp5
-rw-r--r--src/server/PortImpl.cpp24
-rw-r--r--src/server/events/SetPortValue.cpp4
8 files changed, 43 insertions, 36 deletions
diff --git a/src/server/ArcImpl.cpp b/src/server/ArcImpl.cpp
index 406d2010..5b96ca03 100644
--- a/src/server/ArcImpl.cpp
+++ b/src/server/ArcImpl.cpp
@@ -67,21 +67,7 @@ ArcImpl::head_path() const
BufferRef
ArcImpl::buffer(uint32_t voice, SampleCount offset) const
{
- assert(_tail->poly() == 1 || _tail->poly() > voice);
- if (_tail->poly() == 1) {
- voice = 0;
- }
-
- if (_tail->buffer(0)->is_sequence()) {
- if (_head->type() == PortType::CONTROL) {
- _tail->update_values(offset, voice); // Update value buffer
- return _tail->value_buffer(voice); // Return value buffer
- } else if (_head->type() == PortType::CV) {
- // Return full tail buffer below
- }
- }
-
- return _tail->buffer(voice);
+ return _tail->buffer(std::min(voice, _tail->poly() - 1));
}
bool
diff --git a/src/server/BlockImpl.cpp b/src/server/BlockImpl.cpp
index 3b051fd4..d0f0d646 100644
--- a/src/server/BlockImpl.cpp
+++ b/src/server/BlockImpl.cpp
@@ -258,6 +258,17 @@ BlockImpl::process(RunContext& context)
// Run the chunk
run(subcontext);
+ // Emit control port outputs as events
+ for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
+ PortImpl* const port = _ports->at(i);
+ if (port->type() == PortType::CONTROL && port->is_output()) {
+ // TODO: Only emit events when value has actually changed?
+ for (uint32_t v = 0; v < _polyphony; ++v) {
+ port->buffer(v)->append_event(offset, port->buffer(v)->value());
+ }
+ }
+ }
+
offset = chunk_end;
subcontext.slice(offset, chunk_end - offset);
}
diff --git a/src/server/Buffer.cpp b/src/server/Buffer.cpp
index fb7efa85..2353ab5d 100644
--- a/src/server/Buffer.cpp
+++ b/src/server/Buffer.cpp
@@ -166,12 +166,6 @@ Buffer::copy(const RunContext& context, const Buffer* src)
} else {
clear();
}
-
- if (_value_buffer && src->_value_buffer) {
- memcpy(_value_buffer->get<LV2_Atom>(),
- src->value(),
- lv2_atom_total_size(src->value()));
- }
} else if (src->is_audio() && is_control()) {
samples()[0] = src->samples()[0];
} else if (src->is_control() && is_audio()) {
@@ -201,6 +195,7 @@ Buffer::port_data(PortType port_type, SampleCount offset)
{
switch (port_type.id()) {
case PortType::ID::CONTROL:
+ return &_value_buffer->get<LV2_Atom_Float>()->body;
case PortType::ID::CV:
case PortType::ID::AUDIO:
if (_type == _factory.uris().atom_Float) {
diff --git a/src/server/Buffer.hpp b/src/server/Buffer.hpp
index 939f1f87..bc8ff1aa 100644
--- a/src/server/Buffer.hpp
+++ b/src/server/Buffer.hpp
@@ -115,6 +115,14 @@ public:
const SampleCount start,
const SampleCount end)
{
+ if (is_sequence()) {
+ append_event(start, sizeof(val), _factory.uris().atom_Float,
+ reinterpret_cast<const uint8_t*>(
+ static_cast<const float*>(&val)));
+ _value_buffer->get<LV2_Atom_Float>()->body = val;
+ return;
+ }
+
assert(is_audio() || is_control());
assert(end <= _capacity / sizeof(Sample));
// Note: Do not change this without ensuring GCC can still vectorize it
diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp
index fe613f31..cfc43526 100644
--- a/src/server/InputPort.cpp
+++ b/src/server/InputPort.cpp
@@ -210,6 +210,10 @@ InputPort::pre_run(RunContext& context)
mix(context, buffer(v).get(), srcs, n_srcs);
update_values(context.offset(), v);
}
+ } else if (is_a(PortType::CONTROL)) {
+ for (uint32_t v = 0; v < _poly; ++v) {
+ update_values(context.offset(), v);
+ }
}
}
diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp
index 77835b67..e023e3d7 100644
--- a/src/server/LV2Block.cpp
+++ b/src/server/LV2Block.cpp
@@ -117,7 +117,7 @@ LV2Block::make_instance(URIs& uris,
if (buffer) {
if (port->is_a(PortType::CONTROL)) {
- buffer->samples()[0] = port->value().get<float>();
+ buffer->set_value(port->value());
} else if (port->is_a(PortType::CV)) {
buffer->set_block(port->value().get<float>(), 0, engine.block_length());
} else {
@@ -267,7 +267,8 @@ LV2Block::instantiate(BufferFactory& bufs, const LilvState* state)
}
if (port_type == PortType::UNKNOWN) {
port_type = PortType::CONTROL;
- buffer_type = uris.atom_Float;
+ buffer_type = uris.atom_Sequence;
+ val = forge.make(def_values[j]);
}
} else if (lilv_port_is_a(plug, id, uris.lv2_CVPort)) {
port_type = PortType::CV;
diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp
index 45a5a082..a9c1aefe 100644
--- a/src/server/PortImpl.cpp
+++ b/src/server/PortImpl.cpp
@@ -243,7 +243,7 @@ PortImpl::set_voice_value(const RunContext& context,
{
switch (_type.id()) {
case PortType::CONTROL:
- buffer(voice)->samples()[0] = value;
+ ((LV2_Atom_Float*)buffer(voice)->value())->body = value;
_voices->at(voice).set_state.set(context, context.start(), value);
break;
case PortType::AUDIO:
@@ -411,22 +411,24 @@ void
PortImpl::clear_buffers(const RunContext& ctx)
{
switch (_type.id()) {
- case PortType::CONTROL:
- case PortType::CV:
+ case PortType::AUDIO:
+ default:
for (uint32_t v = 0; v < _poly; ++v) {
- Buffer* buf = buffer(v).get();
- buf->set_block(_value.get<float>(), 0, ctx.nframes());
- SetState& state = _voices->at(v).set_state;
- state.state = SetState::State::SET;
- state.value = _value.get<float>();
- state.time = 0;
+ buffer(v)->clear();
}
break;
- case PortType::AUDIO:
- default:
+ case PortType::CONTROL:
for (uint32_t v = 0; v < _poly; ++v) {
buffer(v)->clear();
+ _voices->at(v).set_state.set(ctx, ctx.start(), _value.get<float>());
+ }
+ break;
+ case PortType::CV:
+ for (uint32_t v = 0; v < _poly; ++v) {
+ buffer(v)->set_block(_value.get<float>(), 0, ctx.nframes());
+ _voices->at(v).set_state.set(ctx, ctx.start(), _value.get<float>());
}
+ break;
}
}
diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp
index b8c23605..89c92580 100644
--- a/src/server/events/SetPortValue.cpp
+++ b/src/server/events/SetPortValue.cpp
@@ -56,7 +56,7 @@ SetPortValue::~SetPortValue()
bool
SetPortValue::pre_process(PreProcessContext& ctx)
{
- Ingen::URIs& uris = _engine.world()->uris();
+ Ingen::URIs& uris = _engine.world()->uris();
if (_port->is_output()) {
return Event::pre_process_done(Status::DIRECTION_MISMATCH, _port->path());
}
@@ -72,7 +72,7 @@ SetPortValue::pre_process(PreProcessContext& ctx)
if (_port->buffer_type() == uris.atom_Sequence) {
_buffer = _engine.buffer_factory()->get_buffer(
_port->buffer_type(),
- 0,
+ _value.type() == uris.atom_Float ? _value.type() : 0,
_engine.buffer_factory()->default_size(_port->buffer_type()));
}