Split processing up according to events
This commit is contained in:
parent
89aebf5d9e
commit
4dd9d55c62
@ -5,6 +5,7 @@
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
|
||||
#include "./param-info.h"
|
||||
|
||||
@ -104,6 +105,10 @@ struct Crc32 {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Crc32 copy() {
|
||||
return {*this};
|
||||
}
|
||||
|
||||
uint32_t done() const {
|
||||
return crc^0xFFFFFFFFu;
|
||||
}
|
||||
@ -132,12 +137,25 @@ struct Plugin : public clap_plugin {
|
||||
this->process = plugin_process;
|
||||
this->get_extension = plugin_get_extension;
|
||||
this->on_main_thread = plugin_on_main_thread;
|
||||
|
||||
scanParams();
|
||||
}
|
||||
|
||||
// Configuration state, used by multiple extensions
|
||||
// plugin state
|
||||
bool isConfigured = false;
|
||||
// for library STFX, all inputs/outputs (main and aux) get concatenated together
|
||||
std::vector<const float *> inputBuffers;
|
||||
std::vector<float *> outputBuffers;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Main plugin methods
|
||||
// CLAP plugin methods
|
||||
static bool plugin_init(const clap_plugin *obj) {
|
||||
auto &plugin = *(Plugin *)obj;
|
||||
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) {
|
||||
auto &plugin = *(Plugin *)obj;
|
||||
auto &config = plugin.effect.config;
|
||||
if (!plugin.isConfigured || sampleRate != plugin.effect.config.sampleRate) {
|
||||
auto prevConfig = plugin.effect.config;
|
||||
auto prevConfig = config;
|
||||
plugin.isConfigured = plugin.effect.configure();
|
||||
if (!plugin.isConfigured) {
|
||||
// Can't change config (e.g. sample-rate/ports/etc.) here
|
||||
plugin.effect.config = prevConfig;
|
||||
// Can't change config (e.g. sample-rate/ports/etc.) here, return to previous
|
||||
config = prevConfig;
|
||||
}
|
||||
}
|
||||
auto &inputBuffers = plugin.inputBuffers;
|
||||
inputBuffers.resize(plugin.effect.config.inputChannels);
|
||||
for (auto &a : plugin.effect.config.auxInputs) {
|
||||
inputBuffers.resize(inputBuffers.size() + a);
|
||||
}
|
||||
auto &outputBuffers = plugin.outputBuffers;
|
||||
outputBuffers.resize(plugin.effect.config.outputChannels);
|
||||
for (auto &a : plugin.effect.config.auxOutputs) {
|
||||
outputBuffers.resize(outputBuffers.size() + a);
|
||||
}
|
||||
size_t inputChannels = config.inputChannels;
|
||||
for (auto &a : config.auxInputs) inputChannels += a;
|
||||
plugin.inputBuffers.reserve(inputChannels);
|
||||
size_t outputChannels = config.outputChannels;
|
||||
for (auto &a : config.auxOutputs) a += outputChannels;
|
||||
plugin.outputBuffers.reserve(outputChannels);
|
||||
return plugin.isConfigured;
|
||||
}
|
||||
static void plugin_deactivate(const clap_plugin *obj) {}
|
||||
@ -198,12 +213,9 @@ struct Plugin : public clap_plugin {
|
||||
}
|
||||
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) {
|
||||
auto &plugin = *(Plugin *)obj;
|
||||
auto &inputBuffers = plugin.inputBuffers;
|
||||
inputBuffers.resize(0);
|
||||
for (uint32_t i = 0; i < process->audio_inputs_count; ++i) {
|
||||
auto &buffer = process->audio_inputs[i];
|
||||
for (uint32_t c = 0; c < buffer.channel_count; ++c) {
|
||||
@ -211,14 +223,39 @@ struct Plugin : public clap_plugin {
|
||||
}
|
||||
}
|
||||
auto &outputBuffers = plugin.outputBuffers;
|
||||
outputBuffers.resize(0);
|
||||
for (uint32_t i = 0; i < process->audio_outputs_count; ++i) {
|
||||
auto &buffer = process->audio_outputs[i];
|
||||
for (uint32_t c = 0; c < buffer.channel_count; ++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;
|
||||
}
|
||||
static void plugin_on_main_thread(const clap_plugin *obj) {}
|
||||
@ -226,15 +263,75 @@ struct Plugin : public clap_plugin {
|
||||
// parameters
|
||||
struct Param : public clap_param_info {
|
||||
typename Effect::ParamRange *rangeParam = nullptr;
|
||||
std::unique_ptr<RangeParamInfo> rangeInfo;
|
||||
std::optional<RangeParamInfo> rangeInfo;
|
||||
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;
|
||||
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() {
|
||||
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) {
|
||||
auto &plugin = *(Plugin *)obj;
|
||||
return plugin.params.size();
|
||||
@ -250,7 +347,7 @@ struct Plugin : public clap_plugin {
|
||||
for (auto ¶m : plugin.params) {
|
||||
if (param.id == paramId) {
|
||||
if (param.rangeParam) {
|
||||
*value = (double)*param.rangeParam;
|
||||
*value = param.rangeInfo->toUnit((double)*param.rangeParam);
|
||||
} else {
|
||||
*value = (int)*param.steppedParam;
|
||||
}
|
||||
@ -259,16 +356,47 @@ struct Plugin : public clap_plugin {
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
auto &plugin = *(Plugin *)obj;
|
||||
if (!plugin.isConfigured) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user