Split processing up according to events
This commit is contained in:
parent
89aebf5d9e
commit
4dd9d55c62
@ -5,6 +5,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "./param-info.h"
|
#include "./param-info.h"
|
||||||
|
|
||||||
@ -104,6 +105,10 @@ struct Crc32 {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Crc32 copy() {
|
||||||
|
return {*this};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t done() const {
|
uint32_t done() const {
|
||||||
return crc^0xFFFFFFFFu;
|
return crc^0xFFFFFFFFu;
|
||||||
}
|
}
|
||||||
@ -132,12 +137,25 @@ struct Plugin : public clap_plugin {
|
|||||||
this->process = plugin_process;
|
this->process = plugin_process;
|
||||||
this->get_extension = plugin_get_extension;
|
this->get_extension = plugin_get_extension;
|
||||||
this->on_main_thread = plugin_on_main_thread;
|
this->on_main_thread = plugin_on_main_thread;
|
||||||
|
|
||||||
|
scanParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration state, used by multiple extensions
|
// plugin state
|
||||||
bool isConfigured = false;
|
bool isConfigured = false;
|
||||||
|
// for library STFX, all inputs/outputs (main and aux) get concatenated together
|
||||||
|
std::vector<const float *> inputBuffers;
|
||||||
|
std::vector<float *> outputBuffers;
|
||||||
|
|
||||||
// Main plugin methods
|
void processEvent(const clap_event_header *header) {
|
||||||
|
LOG_EXPR(header->size);
|
||||||
|
LOG_EXPR(header->time);
|
||||||
|
LOG_EXPR(header->space_id);
|
||||||
|
LOG_EXPR(header->type);
|
||||||
|
LOG_EXPR(header->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLAP plugin methods
|
||||||
static bool plugin_init(const clap_plugin *obj) {
|
static bool plugin_init(const clap_plugin *obj) {
|
||||||
auto &plugin = *(Plugin *)obj;
|
auto &plugin = *(Plugin *)obj;
|
||||||
LOG_EXPR(plugin.plugins.modulePath);
|
LOG_EXPR(plugin.plugins.modulePath);
|
||||||
@ -148,24 +166,21 @@ struct Plugin : public clap_plugin {
|
|||||||
}
|
}
|
||||||
static bool plugin_activate(const clap_plugin *obj, double sampleRate, uint32_t minFrames, uint32_t maxFrames) {
|
static bool plugin_activate(const clap_plugin *obj, double sampleRate, uint32_t minFrames, uint32_t maxFrames) {
|
||||||
auto &plugin = *(Plugin *)obj;
|
auto &plugin = *(Plugin *)obj;
|
||||||
|
auto &config = plugin.effect.config;
|
||||||
if (!plugin.isConfigured || sampleRate != plugin.effect.config.sampleRate) {
|
if (!plugin.isConfigured || sampleRate != plugin.effect.config.sampleRate) {
|
||||||
auto prevConfig = plugin.effect.config;
|
auto prevConfig = config;
|
||||||
plugin.isConfigured = plugin.effect.configure();
|
plugin.isConfigured = plugin.effect.configure();
|
||||||
if (!plugin.isConfigured) {
|
if (!plugin.isConfigured) {
|
||||||
// Can't change config (e.g. sample-rate/ports/etc.) here
|
// Can't change config (e.g. sample-rate/ports/etc.) here, return to previous
|
||||||
plugin.effect.config = prevConfig;
|
config = prevConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto &inputBuffers = plugin.inputBuffers;
|
size_t inputChannels = config.inputChannels;
|
||||||
inputBuffers.resize(plugin.effect.config.inputChannels);
|
for (auto &a : config.auxInputs) inputChannels += a;
|
||||||
for (auto &a : plugin.effect.config.auxInputs) {
|
plugin.inputBuffers.reserve(inputChannels);
|
||||||
inputBuffers.resize(inputBuffers.size() + a);
|
size_t outputChannels = config.outputChannels;
|
||||||
}
|
for (auto &a : config.auxOutputs) a += outputChannels;
|
||||||
auto &outputBuffers = plugin.outputBuffers;
|
plugin.outputBuffers.reserve(outputChannels);
|
||||||
outputBuffers.resize(plugin.effect.config.outputChannels);
|
|
||||||
for (auto &a : plugin.effect.config.auxOutputs) {
|
|
||||||
outputBuffers.resize(outputBuffers.size() + a);
|
|
||||||
}
|
|
||||||
return plugin.isConfigured;
|
return plugin.isConfigured;
|
||||||
}
|
}
|
||||||
static void plugin_deactivate(const clap_plugin *obj) {}
|
static void plugin_deactivate(const clap_plugin *obj) {}
|
||||||
@ -198,12 +213,9 @@ struct Plugin : public clap_plugin {
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::vector<const float *> inputBuffers;
|
|
||||||
std::vector<float *> outputBuffers;
|
|
||||||
static clap_process_status plugin_process(const clap_plugin *obj, const clap_process *process) {
|
static clap_process_status plugin_process(const clap_plugin *obj, const clap_process *process) {
|
||||||
auto &plugin = *(Plugin *)obj;
|
auto &plugin = *(Plugin *)obj;
|
||||||
auto &inputBuffers = plugin.inputBuffers;
|
auto &inputBuffers = plugin.inputBuffers;
|
||||||
inputBuffers.resize(0);
|
|
||||||
for (uint32_t i = 0; i < process->audio_inputs_count; ++i) {
|
for (uint32_t i = 0; i < process->audio_inputs_count; ++i) {
|
||||||
auto &buffer = process->audio_inputs[i];
|
auto &buffer = process->audio_inputs[i];
|
||||||
for (uint32_t c = 0; c < buffer.channel_count; ++c) {
|
for (uint32_t c = 0; c < buffer.channel_count; ++c) {
|
||||||
@ -211,14 +223,39 @@ struct Plugin : public clap_plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto &outputBuffers = plugin.outputBuffers;
|
auto &outputBuffers = plugin.outputBuffers;
|
||||||
outputBuffers.resize(0);
|
|
||||||
for (uint32_t i = 0; i < process->audio_outputs_count; ++i) {
|
for (uint32_t i = 0; i < process->audio_outputs_count; ++i) {
|
||||||
auto &buffer = process->audio_outputs[i];
|
auto &buffer = process->audio_outputs[i];
|
||||||
for (uint32_t c = 0; c < buffer.channel_count; ++c) {
|
for (uint32_t c = 0; c < buffer.channel_count; ++c) {
|
||||||
outputBuffers.push_back(buffer.data32[c]);
|
outputBuffers.push_back(buffer.data32[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plugin.effect.process(inputBuffers.data(), outputBuffers.data(), process->frames_count);
|
|
||||||
|
size_t length = process->frames_count;
|
||||||
|
auto inputEventCount = process->in_events->size(process->in_events);
|
||||||
|
size_t offset = 0, nextEventIndex = 0;
|
||||||
|
while (offset < length) {
|
||||||
|
size_t nextEventOffset = length;
|
||||||
|
const clap_event_header *event = nullptr;
|
||||||
|
if (nextEventIndex < inputEventCount) {
|
||||||
|
event = process->in_events->get(process->in_events, nextEventIndex);
|
||||||
|
nextEventOffset = std::max<size_t>(offset, event->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process up until the next event (or end)
|
||||||
|
if (nextEventOffset > offset) {
|
||||||
|
auto delta = nextEventOffset - offset;
|
||||||
|
plugin.effect.process(inputBuffers.data(), outputBuffers.data(), delta);
|
||||||
|
offset = nextEventOffset;
|
||||||
|
for (auto &p : inputBuffers) p += delta;
|
||||||
|
for (auto &p : outputBuffers) p += delta;
|
||||||
|
}
|
||||||
|
if (event) {
|
||||||
|
plugin.processEvent(event);
|
||||||
|
++nextEventIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputBuffers.resize(0);
|
||||||
|
outputBuffers.resize(0);
|
||||||
return CLAP_PROCESS_CONTINUE;
|
return CLAP_PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
static void plugin_on_main_thread(const clap_plugin *obj) {}
|
static void plugin_on_main_thread(const clap_plugin *obj) {}
|
||||||
@ -226,15 +263,75 @@ struct Plugin : public clap_plugin {
|
|||||||
// parameters
|
// parameters
|
||||||
struct Param : public clap_param_info {
|
struct Param : public clap_param_info {
|
||||||
typename Effect::ParamRange *rangeParam = nullptr;
|
typename Effect::ParamRange *rangeParam = nullptr;
|
||||||
std::unique_ptr<RangeParamInfo> rangeInfo;
|
std::optional<RangeParamInfo> rangeInfo;
|
||||||
typename Effect::ParamStepped *steppedParam = nullptr;
|
typename Effect::ParamStepped *steppedParam = nullptr;
|
||||||
std::unique_ptr<SteppedParamInfo> steppedInfo;
|
std::optional<SteppedParamInfo> steppedInfo;
|
||||||
|
|
||||||
|
void setClapInfo() {
|
||||||
|
flags |= CLAP_PARAM_IS_AUTOMATABLE;
|
||||||
|
cookie = this;
|
||||||
|
if (rangeParam) {
|
||||||
|
std::strncpy(name, rangeInfo->name.c_str(), CLAP_NAME_SIZE);
|
||||||
|
// STFX range params are mapped to [0, 1] so we can give them a nonlinear shape
|
||||||
|
min_value = 0;
|
||||||
|
max_value = 1;
|
||||||
|
default_value = rangeInfo->toUnit(rangeInfo->defaultValue);
|
||||||
|
} else {
|
||||||
|
std::strncpy(name, steppedInfo->name.c_str(), CLAP_NAME_SIZE);
|
||||||
|
flags |= CLAP_PARAM_IS_STEPPED;
|
||||||
|
min_value = steppedInfo->low;
|
||||||
|
max_value = steppedInfo->high;
|
||||||
|
default_value = steppedInfo->defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
std::vector<Param> params;
|
std::vector<Param> params;
|
||||||
|
struct ParamScanner {
|
||||||
|
std::vector<Param> ¶ms;
|
||||||
|
Crc32 crc;
|
||||||
|
|
||||||
|
// Do nothing for most types
|
||||||
|
template<class V>
|
||||||
|
void operator()(const char *key, V &v) {
|
||||||
|
LOG_EXPR(key);
|
||||||
|
if constexpr (std::is_void_v<decltype(v.state(*this))>) {
|
||||||
|
LOG_EXPR("recursing");
|
||||||
|
ParamScanner recurse{*this};
|
||||||
|
recurse.crc.addString(key, true);
|
||||||
|
v.state(recurse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra methods we add for STFX storage
|
||||||
|
void info(const char *, const char *) {}
|
||||||
|
int version(int v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
template<class PR>
|
||||||
|
RangeParamInfo & range(const char *key, PR ¶m) {
|
||||||
|
params.emplace_back();
|
||||||
|
auto &entry = params.back();
|
||||||
|
entry.id = crc.copy().addString(key, true).done();
|
||||||
|
entry.rangeParam = ¶m;
|
||||||
|
return entry.rangeInfo.emplace(param);
|
||||||
|
}
|
||||||
|
template<class PS>
|
||||||
|
SteppedParamInfo & stepped(const char *key, PS ¶m) {
|
||||||
|
params.emplace_back();
|
||||||
|
auto &entry = params.back();
|
||||||
|
entry.id = crc.copy().addString(key, true).done();
|
||||||
|
entry.steppedParam = ¶m;
|
||||||
|
return entry.steppedInfo.emplace(param);
|
||||||
|
}
|
||||||
|
};
|
||||||
void scanParams() {
|
void scanParams() {
|
||||||
params.resize(0);
|
params.resize(0);
|
||||||
|
ParamScanner scanner{params};
|
||||||
|
effect.state(scanner);
|
||||||
|
for (auto &entry : params) entry.setClapInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CLAP parameter methods
|
||||||
static uint32_t params_count(const clap_plugin *obj) {
|
static uint32_t params_count(const clap_plugin *obj) {
|
||||||
auto &plugin = *(Plugin *)obj;
|
auto &plugin = *(Plugin *)obj;
|
||||||
return plugin.params.size();
|
return plugin.params.size();
|
||||||
@ -250,7 +347,7 @@ struct Plugin : public clap_plugin {
|
|||||||
for (auto ¶m : plugin.params) {
|
for (auto ¶m : plugin.params) {
|
||||||
if (param.id == paramId) {
|
if (param.id == paramId) {
|
||||||
if (param.rangeParam) {
|
if (param.rangeParam) {
|
||||||
*value = (double)*param.rangeParam;
|
*value = param.rangeInfo->toUnit((double)*param.rangeParam);
|
||||||
} else {
|
} else {
|
||||||
*value = (int)*param.steppedParam;
|
*value = (int)*param.steppedParam;
|
||||||
}
|
}
|
||||||
@ -259,16 +356,47 @@ struct Plugin : public clap_plugin {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static bool params_value_to_text(const clap_plugin *obj, clap_id paramId, double value, char *outBuffer, uint32_t outCapacity) {
|
static bool params_value_to_text(const clap_plugin *obj, clap_id paramId, double value, char *text, uint32_t textCapacity) {
|
||||||
|
auto &plugin = *(Plugin *)obj;
|
||||||
|
for (auto ¶m : plugin.params) {
|
||||||
|
if (param.id == paramId) {
|
||||||
|
if (param.rangeParam) {
|
||||||
|
auto str = param.rangeInfo->toString(value);
|
||||||
|
std::strncpy(text, str.c_str(), textCapacity);
|
||||||
|
} else {
|
||||||
|
auto str = param.steppedInfo->toString(int(std::round(value)));
|
||||||
|
std::strncpy(text, str.c_str(), textCapacity);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static bool params_text_to_value(const clap_plugin *obj, clap_id paramId, const char *text, double *value) {
|
static bool params_text_to_value(const clap_plugin *obj, clap_id paramId, const char *text, double *value) {
|
||||||
|
auto &plugin = *(Plugin *)obj;
|
||||||
|
for (auto ¶m : plugin.params) {
|
||||||
|
if (param.id == paramId) {
|
||||||
|
std::string str = text;
|
||||||
|
if (param.rangeParam) {
|
||||||
|
*value = param.rangeInfo->toUnit(param.rangeInfo->fromString(str));
|
||||||
|
} else {
|
||||||
|
*value = param.steppedInfo->fromString(str);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static void params_flush(const clap_plugin *obj, const clap_input_events *inEvents, const clap_output_events *outEvents) {
|
static void params_flush(const clap_plugin *obj, const clap_input_events *inEvents, const clap_output_events *outEvents) {
|
||||||
// not implemented yet
|
auto &plugin = *(Plugin *)obj;
|
||||||
|
auto count = inEvents->size(inEvents);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
auto *header = inEvents->get(inEvents, i);
|
||||||
|
plugin.processEvent(header);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CLAP audio port methods
|
||||||
static uint32_t audio_ports_count(const clap_plugin *obj, bool inputPorts) {
|
static uint32_t audio_ports_count(const clap_plugin *obj, bool inputPorts) {
|
||||||
auto &plugin = *(Plugin *)obj;
|
auto &plugin = *(Plugin *)obj;
|
||||||
if (!plugin.isConfigured) {
|
if (!plugin.isConfigured) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user