/*
This file is part of Ingen.
Copyright 2007-2016 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_LV2BLOCK_HPP
#define INGEN_ENGINE_LV2BLOCK_HPP
#include "BlockImpl.hpp"
#include "BufferRef.hpp"
#include "State.hpp"
#include "types.hpp"
#include "ingen/LV2Features.hpp"
#include "ingen/Properties.hpp"
#include "ingen/URI.hpp"
#include "lilv/lilv.h"
#include "lv2/worker/worker.h"
#include "raul/Array.hpp"
#include "raul/Maid.hpp"
#include "raul/Noncopyable.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace raul {
class Symbol;
} // namespace raul
namespace boost::intrusive {
template
struct cache_last;
template
struct constant_time_size;
} // namespace boost::intrusive
namespace ingen {
class Resource;
class URIs;
class World;
namespace server {
class BufferFactory;
class Engine;
class GraphImpl;
class LV2Plugin;
class RunContext;
class Worker;
/** An instance of a LV2 plugin.
*
* \ingroup engine
*/
class LV2Block final : public BlockImpl
{
public:
LV2Block(LV2Plugin* plugin,
const raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
SampleRate srate);
~LV2Block() override;
bool instantiate(BufferFactory& bufs, const LilvState* state);
LilvInstance* instance() override { return instance(0); }
bool save_state(const std::filesystem::path& dir) const override;
BlockImpl* duplicate(Engine& engine,
const raul::Symbol& symbol,
GraphImpl* parent) override;
bool prepare_poly(BufferFactory& bufs, uint32_t poly) override;
bool apply_poly(RunContext& ctx, uint32_t poly) override;
void activate(BufferFactory& bufs) override;
void deactivate() override;
LV2_Worker_Status work(uint32_t size, const void* data);
void run(RunContext& ctx) override;
void post_process(RunContext& ctx) override;
StatePtr load_preset(const URI& uri) override;
void apply_state(const std::unique_ptr& worker,
const LilvState* state) override;
std::optional save_preset(const URI& uri,
const Properties& props) override;
void set_port_buffer(uint32_t voice,
uint32_t port_num,
const BufferRef& buf,
SampleCount offset) override;
static StatePtr load_state(World& world, const std::filesystem::path& path);
protected:
struct Instance : public raul::Noncopyable {
explicit Instance(LilvInstance* i) noexcept : instance(i) {}
~Instance() { lilv_instance_free(instance); }
LilvInstance* const instance;
};
std::shared_ptr
make_instance(URIs& uris, SampleRate rate, uint32_t voice, bool preparing);
inline LilvInstance* instance(uint32_t voice) {
return static_cast((*_instances)[voice]->instance);
}
using Instances = raul::Array>;
static void drop_instances(const raul::managed_ptr& instances) {
if (instances) {
for (size_t i = 0; i < instances->size(); ++i) {
(*instances)[i].reset();
}
}
}
struct Response : public raul::Maid::Disposable
, public raul::Noncopyable
, public boost::intrusive::slist_base_hook<> {
Response(uint32_t s, const void* d)
: size(s)
, data(malloc(s))
{
memcpy(data, d, s);
}
~Response() override {
free(data);
}
const uint32_t size;
void* const data;
};
using Responses = boost::intrusive::slist<
Response,
boost::intrusive::cache_last,
boost::intrusive::constant_time_size>;
static LV2_Worker_Status work_respond(
LV2_Worker_Respond_Handle handle, uint32_t size, const void* data);
LV2Plugin* _lv2_plugin;
raul::managed_ptr _instances;
raul::managed_ptr _prepared_instances;
const LV2_Worker_Interface* _worker_iface{nullptr};
std::mutex _work_mutex;
Responses _responses;
std::shared_ptr _features;
};
} // namespace server
} // namespace ingen
#endif // INGEN_ENGINE_LV2BLOCK_HPP