diff options
Diffstat (limited to 'src/server/PortImpl.cpp')
-rw-r--r-- | src/server/PortImpl.cpp | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp deleted file mode 100644 index b0ef3c85..00000000 --- a/src/server/PortImpl.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2016 David Robillard <http://drobilla.net/> - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "ingen/URIs.hpp" -#include "ingen/World.hpp" -#include "lv2/lv2plug.in/ns/ext/atom/util.h" -#include "raul/Array.hpp" -#include "raul/Maid.hpp" - -#include "BlockImpl.hpp" -#include "Buffer.hpp" -#include "BufferFactory.hpp" -#include "Engine.hpp" -#include "PortImpl.hpp" -#include "PortType.hpp" -#include "ThreadManager.hpp" - -namespace Ingen { -namespace Server { - -static const uint32_t monitor_rate = 25.0; // Hz - -/** The length of time between monitor updates in frames */ -static inline uint32_t -monitor_period(const Engine& engine) -{ - return std::max(engine.block_length(), - engine.sample_rate() / monitor_rate); -} - -PortImpl::PortImpl(BufferFactory& bufs, - BlockImpl* const block, - const Raul::Symbol& name, - uint32_t index, - uint32_t poly, - PortType type, - LV2_URID buffer_type, - const Atom& value, - size_t buffer_size, - bool is_output) - : NodeImpl(bufs.uris(), block, name) - , _bufs(bufs) - , _index(index) - , _poly(poly) - , _buffer_size(buffer_size) - , _frames_since_monitor(0) - , _monitor_value(0.0f) - , _peak(0.0f) - , _type(type) - , _buffer_type(buffer_type) - , _value(value) - , _min(bufs.forge().make(0.0f)) - , _max(bufs.forge().make(1.0f)) - , _voices(bufs.maid().make_managed<Voices>(poly)) - , _connected_flag(false) - , _monitored(false) - , _force_monitor_update(false) - , _is_morph(false) - , _is_auto_morph(false) - , _is_logarithmic(false) - , _is_sample_rate(false) - , _is_toggled(false) - , _is_driver_port(false) - , _is_output(is_output) -{ - assert(block != nullptr); - assert(_poly > 0); - - const Ingen::URIs& uris = bufs.uris(); - - set_type(type, buffer_type); - - remove_property(uris.lv2_index, uris.patch_wildcard); - set_property(uris.lv2_index, bufs.forge().make((int32_t)index)); - - if (has_value()) { - set_property(uris.ingen_value, value); - } - if (type == PortType::ATOM) { - set_property(uris.atom_bufferType, - bufs.forge().make_urid(buffer_type)); - } - - if (is_output) { - if (_parent->graph_type() != Node::GraphType::GRAPH) { - add_property(bufs.uris().rdf_type, bufs.uris().lv2_OutputPort.urid); - } - } - - get_buffers(bufs, &BufferFactory::get_buffer, _voices, poly, 0); -} - -bool -PortImpl::get_buffers(BufferFactory& bufs, - GetFn get, - const MPtr<Voices>& voices, - uint32_t poly, - size_t num_in_arcs) const -{ - for (uint32_t v = 0; v < poly; ++v) { - voices->at(v).buffer.reset(); - voices->at(v).buffer = (bufs.*get)( - buffer_type(), _value.type(), _buffer_size); - } - - return true; -} - -bool -PortImpl::setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly) -{ - return get_buffers(bufs, &BufferFactory::claim_buffer, _voices, poly, 0); -} - -void -PortImpl::set_type(PortType port_type, LV2_URID buffer_type) -{ - const Ingen::URIs& uris = _bufs.uris(); - Ingen::World* world = _bufs.engine().world(); - - // Update type properties so clients are aware of current type - remove_property(uris.rdf_type, uris.lv2_AudioPort); - remove_property(uris.rdf_type, uris.lv2_CVPort); - remove_property(uris.rdf_type, uris.lv2_ControlPort); - remove_property(uris.rdf_type, uris.atom_AtomPort); - add_property(uris.rdf_type, world->forge().make_urid(port_type.uri())); - - // Update audio thread types - _type = port_type; - _buffer_type = buffer_type; - if (!_buffer_type) { - switch (_type.id()) { - case PortType::CONTROL: - _buffer_type = uris.atom_Float; - break; - case PortType::AUDIO: - case PortType::CV: - _buffer_type = uris.atom_Sound; - break; - default: - break; - } - } - _buffer_size = std::max(_buffer_size, _bufs.default_size(_buffer_type)); -} - -bool -PortImpl::has_value() const -{ - return (_type == PortType::CONTROL || - _type == PortType::CV || - (_type == PortType::ATOM && - _value.type() == _bufs.uris().atom_Float)); -} - -bool -PortImpl::supports(const URIs::Quark& value_type) const -{ - return has_property(_bufs.uris().atom_supports, value_type); -} - -void -PortImpl::activate(BufferFactory& bufs) -{ - /* Set the time since the last monitor update to a random value within the - monitor period, to spread the load out over time. Otherwise, every - port would try to send an update at exactly the same time, every time. - */ - const double srate = bufs.engine().sample_rate(); - const uint32_t period = srate / monitor_rate; - _frames_since_monitor = bufs.engine().frand() * period; - _monitor_value = 0.0f; - _peak = 0.0f; - - // Trigger buffer re-connect next cycle - _connected_flag.clear(std::memory_order_release); -} - -void -PortImpl::deactivate() -{ - if (is_output() && !_is_driver_port) { - for (uint32_t v = 0; v < _poly; ++v) { - if (_voices->at(v).buffer) { - _voices->at(v).buffer->clear(); - } - } - } - _monitor_value = 0.0f; - _peak = 0.0f; -} - -void -PortImpl::set_voices(RunContext& context, MPtr<Voices>&& voices) -{ - _voices = std::move(voices); - connect_buffers(); -} - -void -PortImpl::cache_properties() -{ - _is_logarithmic = has_property(_bufs.uris().lv2_portProperty, - _bufs.uris().pprops_logarithmic); - _is_sample_rate = has_property(_bufs.uris().lv2_portProperty, - _bufs.uris().lv2_sampleRate); - _is_toggled = has_property(_bufs.uris().lv2_portProperty, - _bufs.uris().lv2_toggled); -} - -void -PortImpl::set_control_value(const RunContext& context, - FrameTime time, - Sample value) -{ - for (uint32_t v = 0; v < _poly; ++v) { - update_set_state(context, v); - set_voice_value(context, v, time, value); - } -} - -void -PortImpl::set_voice_value(const RunContext& context, - uint32_t voice, - FrameTime time, - Sample value) -{ - switch (_type.id()) { - case PortType::CONTROL: - if (buffer(voice)->value()) { - ((LV2_Atom_Float*)buffer(voice)->value())->body = value; - } - _voices->at(voice).set_state.set(context, context.start(), value); - break; - case PortType::AUDIO: - case PortType::CV: { - // Time may be at end so internal blocks can set triggers - assert(time >= context.start()); - assert(time <= context.start() + context.nframes()); - - const FrameTime offset = time - context.start(); - if (offset < context.nframes()) { - buffer(voice)->set_block(value, offset, context.nframes()); - } - /* else, this is a set at context.nframes(), used to reset a CV port's - value for the next block, particularly for triggers on the last - frame of a block (set nframes-1 to 1, then nframes to 0). */ - - _voices->at(voice).set_state.set(context, time, value); - } break; - case PortType::ATOM: - if (buffer(voice)->is_sequence()) { - const FrameTime offset = time - context.start(); - // Same deal as above - if (offset < context.nframes()) { - buffer(voice)->append_event(offset, - sizeof(value), - _bufs.uris().atom_Float, - (const uint8_t*)&value); - } - _voices->at(voice).set_state.set(context, time, value); - } else { -#ifndef NDEBUG - fprintf(stderr, - "error: %s set non-sequence atom port value (buffer type %u)\n", - path().c_str(), buffer(voice)->type()); -#endif - } - default: - break; - } -} - -void -PortImpl::update_set_state(const RunContext& context, uint32_t v) -{ - Voice& voice = _voices->at(v); - SetState& state = voice.set_state; - BufferRef buf = voice.buffer; - switch (state.state) { - case SetState::State::SET: - break; - case SetState::State::SET_CYCLE_1: - if (state.time < context.start() && - buf->is_sequence() && - buf->value_type() == _bufs.uris().atom_Float && - !_parent->is_main()) { - buf->clear(); - state.time = context.start(); - } - state.state = SetState::State::SET; - break; - case SetState::State::HALF_SET_CYCLE_1: - state.state = SetState::State::HALF_SET_CYCLE_2; - break; - case SetState::State::HALF_SET_CYCLE_2: - if (buf->is_sequence()) { - buf->clear(); - buf->append_event( - 0, sizeof(float), _bufs.uris().atom_Float, - (const uint8_t*)&state.value); - } else { - buf->set_block(state.value, 0, context.nframes()); - } - state.state = SetState::State::SET_CYCLE_1; - break; - } -} - -bool -PortImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - if (_is_driver_port || _parent->is_main() || - (_type == PortType::ATOM && !_value.is_valid())) { - return false; - } else if (_poly == poly) { - return true; - } else if (_prepared_voices && _prepared_voices->size() != poly) { - _prepared_voices.reset(); - } - - if (!_prepared_voices) { - _prepared_voices = bufs.maid().make_managed<Voices>( - poly, *_voices, Voice()); - } - - get_buffers(bufs, &BufferFactory::get_buffer, - _prepared_voices, _prepared_voices->size(), num_arcs()); - - return true; -} - -bool -PortImpl::apply_poly(RunContext& context, uint32_t poly) -{ - if (_parent->is_main() || - (_type == PortType::ATOM && !_value.is_valid())) { - return false; - } else if (!_prepared_voices) { - return true; - } - - assert(poly == _prepared_voices->size()); - - _poly = poly; - - // Apply a new set of voices from a preceding call to prepare_poly - _voices = std::move(_prepared_voices); - - if (is_a(PortType::CONTROL) || is_a(PortType::CV)) { - set_control_value(context, context.start(), _value.get<float>()); - } - - assert(_voices->size() >= poly); - assert(this->poly() == poly); - assert(!_prepared_voices); - - connect_buffers(); - - return true; -} - -void -PortImpl::set_buffer_size(RunContext& context, BufferFactory& bufs, size_t size) -{ - _buffer_size = size; - - for (uint32_t v = 0; v < _poly; ++v) { - _voices->at(v).buffer->resize(size); - } - - connect_buffers(); -} - -void -PortImpl::connect_buffers(SampleCount offset) -{ - for (uint32_t v = 0; v < _poly; ++v) { - PortImpl::parent_block()->set_port_buffer(v, _index, buffer(v), offset); - } -} - -void -PortImpl::recycle_buffers() -{ - for (uint32_t v = 0; v < _poly; ++v) { - _voices->at(v).buffer = nullptr; - } -} - -void -PortImpl::set_is_driver_port(BufferFactory& bufs) -{ - _is_driver_port = true; -} - -void -PortImpl::clear_buffers(const RunContext& ctx) -{ - switch (_type.id()) { - case PortType::AUDIO: - default: - for (uint32_t v = 0; v < _poly; ++v) { - buffer(v)->clear(); - } - break; - 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; - } -} - -void -PortImpl::monitor(RunContext& context, bool send_now) -{ - if (!context.must_notify(this)) { - return; - } - - const uint32_t period = monitor_period(context.engine()); - _frames_since_monitor += context.nframes(); - - const bool time_to_send = send_now || _frames_since_monitor >= period; - const bool is_sequence = (_type.id() == PortType::ATOM && - _buffer_type == _bufs.uris().atom_Sequence); - if (!time_to_send && !(is_sequence && _monitored) && (!is_sequence && buffer(0)->value())) { - return; - } - - Forge& forge = context.engine().world()->forge(); - URIs& uris = context.engine().world()->uris(); - LV2_URID key = 0; - float val = 0.0f; - switch (_type.id()) { - case PortType::UNKNOWN: - break; - case PortType::AUDIO: - key = uris.ingen_activity; - val = _peak = std::max(_peak, buffer(0)->peak(context)); - break; - case PortType::CONTROL: - case PortType::CV: - key = uris.ingen_value; - val = buffer(0)->value_at(0); - break; - case PortType::ATOM: - if (_buffer_type == _bufs.uris().atom_Sequence) { - const LV2_Atom* atom = buffer(0)->get<const LV2_Atom>(); - const LV2_Atom* value = buffer(0)->value(); - if (atom->type != _bufs.uris().atom_Sequence) { - /* Buffer contents are not actually a Sequence. Probably an - uninitialized Chunk, so do nothing. */ - } else if (_monitored) { - /* Sequence explicitly monitored, send everything. */ - const LV2_Atom_Sequence* seq = (const LV2_Atom_Sequence*)atom; - LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { - context.notify(uris.ingen_activity, - context.start() + ev->time.frames, - this, - ev->body.size, - ev->body.type, - LV2_ATOM_BODY(&ev->body)); - } - } else if (value && value->type == _bufs.uris().atom_Float) { - /* Float sequence, monitor as a control. */ - key = uris.ingen_value; - val = ((LV2_Atom_Float*)buffer(0)->value())->body; - } else if (atom->size > sizeof(LV2_Atom_Sequence_Body)) { - /* General sequence, send activity for blinkenlights. */ - const int32_t one = 1; - context.notify(uris.ingen_activity, - context.start(), - this, - sizeof(int32_t), - (LV2_URID)uris.atom_Bool, - &one); - _force_monitor_update = false; - } - } - } - - _frames_since_monitor = _frames_since_monitor % period; - if (key && val != _monitor_value) { - if (context.notify(key, context.start(), this, - sizeof(float), forge.Float, &val)) { - /* Update frames since last update to conceptually zero, but keep - the remainder to preserve load balancing. */ - _frames_since_monitor = _frames_since_monitor % period; - _peak = 0.0f; - _monitor_value = val; - } - // Otherwise failure, leave old value and try again next time - } -} - -BufferRef -PortImpl::value_buffer(uint32_t voice) -{ - return buffer(voice)->value_buffer(); -} - -SampleCount -PortImpl::next_value_offset(SampleCount offset, SampleCount end) const -{ - SampleCount earliest = end; - for (uint32_t v = 0; v < _poly; ++v) { - const SampleCount o = _voices->at(v).buffer->next_value_offset(offset, end); - if (o < earliest) { - earliest = o; - } - } - return earliest; -} - -void -PortImpl::update_values(SampleCount offset, uint32_t voice) -{ - buffer(voice)->update_value_buffer(offset); -} - -void -PortImpl::pre_process(RunContext& context) -{ - if (!_connected_flag.test_and_set(std::memory_order_acquire)) { - connect_buffers(); - clear_buffers(context); - } - - for (uint32_t v = 0; v < _poly; ++v) { - _voices->at(v).buffer->prepare_output_write(context); - } -} - -void -PortImpl::post_process(RunContext& context) -{ - for (uint32_t v = 0; v < _poly; ++v) { - update_set_state(context, v); - update_values(0, v); - } - - monitor(context); -} - -} // namespace Server -} // namespace Ingen |