/* This file is part of Ingen. Copyright 2007-2023 David Robillard 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 . */ #ifndef INGEN_ENGINE_GRAPHIMPL_HPP #define INGEN_ENGINE_GRAPHIMPL_HPP #include "BlockImpl.hpp" #include "DuplexPort.hpp" #include "ThreadManager.hpp" #include "server.h" #include "types.hpp" #include "lv2/urid/urid.h" #include "raul/Maid.hpp" #include #include #include #include #include #include // IWYU pragma: no_include "CompiledGraph.hpp" namespace raul { class Symbol; } // namespace raul namespace ingen::server { class ArcImpl; class BufferFactory; class CompiledGraph; // IWYU pragma: keep class Engine; class PortImpl; class RunContext; /** A group of blocks in a graph, possibly polyphonic. * * Note that this is also a Block, just one which contains Blocks. * Therefore infinite subgraphing is possible, of polyphonic * graphs of polyphonic blocks etc. etc. * * \ingroup engine */ class INGEN_SERVER_API GraphImpl final : public BlockImpl { public: GraphImpl(Engine& engine, const raul::Symbol& symbol, uint32_t poly, GraphImpl* parent, SampleRate srate, uint32_t internal_poly); ~GraphImpl() override; GraphType graph_type() const override { return GraphType::GRAPH; } BlockImpl* duplicate(Engine& engine, const raul::Symbol& symbol, GraphImpl* parent) override; void activate(BufferFactory& bufs) override; void deactivate() override; void pre_process(RunContext& ctx) override; void process(RunContext& ctx) override; void run(RunContext& ctx) override; void set_buffer_size(RunContext& ctx, BufferFactory& bufs, LV2_URID type, uint32_t size) override; /** Prepare for a new (internal) polyphony value. * * Pre-process thread, poly is actually applied by apply_internal_poly. * \return true on success. */ bool prepare_internal_poly(BufferFactory& bufs, uint32_t poly); /** Apply a new (internal) polyphony value. * * Audio thread. * * \param ctx Process context * * \param bufs New set of buffers * * \param poly Must be < the most recent value passed to * prepare_internal_poly. * * \param maid Any objects no longer needed will be * pushed to this */ bool apply_internal_poly(RunContext& ctx, BufferFactory& bufs, raul::Maid& maid, uint32_t poly); // Graph specific stuff not inherited from Block using Blocks = boost::intrusive::slist>; /** Add a block to this graph. * Pre-process thread only. */ void add_block(BlockImpl& block); /** Remove a block from this graph. * Pre-process thread only. */ void remove_block(BlockImpl& block); Blocks& blocks() { return _blocks; } const Blocks& blocks() const { return _blocks; } uint32_t num_ports_non_rt() const; bool has_port_with_index(uint32_t index) const; using PortList = boost::intrusive::slist>; void add_input(DuplexPort& port) { ThreadManager::assert_thread(THREAD_PRE_PROCESS); assert(port.is_input()); _inputs.push_front(port); } void add_output(DuplexPort& port) { ThreadManager::assert_thread(THREAD_PRE_PROCESS); assert(port.is_output()); _outputs.push_front(port); } /** Remove port from ports list used in pre-processing thread. * * Port is not removed from ports array for process thread (which could be * simultaneously running). * * Pre-processing thread or situations that won't cause races with it only. */ void remove_port(DuplexPort& port); /** Remove all ports from ports list used in pre-processing thread. * * Ports are not removed from ports array for process thread (which could be * simultaneously running). Returned is a (inputs, outputs) pair. * * Pre-processing thread or situations that won't cause races with it only. */ void clear_ports(); /** Add an arc to this graph. * Pre-processing thread only. */ void add_arc(const std::shared_ptr& a); /** Remove an arc from this graph. * Pre-processing thread only. */ std::shared_ptr remove_arc(const PortImpl* tail, const PortImpl* dst_port); bool has_arc(const PortImpl* tail, const PortImpl* dst_port) const; /** Set a new compiled graph to run, and return the old one. */ [[nodiscard]] std::unique_ptr swap_compiled_graph(std::unique_ptr cg); const raul::managed_ptr& external_ports() { return _ports; } void set_external_ports(raul::managed_ptr&& pa) { _ports = std::move(pa); } raul::managed_ptr build_ports_array(raul::Maid& maid); /** Whether to run this graph's DSP bits in the audio thread */ bool enabled() const { return _process; } void enable() { _process = true; } void disable(RunContext& ctx); uint32_t internal_poly() const { return _poly_pre; } uint32_t internal_poly_process() const { return _poly_process; } Engine& engine() { return _engine; } private: using CompiledGraphPtr = std::unique_ptr; Engine& _engine; uint32_t _poly_pre; ///< Pre-process thread only uint32_t _poly_process; ///< Process thread only CompiledGraphPtr _compiled_graph; ///< Process thread only PortList _inputs; ///< Pre-process thread only PortList _outputs; ///< Pre-process thread only Blocks _blocks; ///< Pre-process thread only bool _process{false}; ///< True iff graph is enabled }; } // namespace ingen::server #endif // INGEN_ENGINE_GRAPHIMPL_HPP