more and more

This commit is contained in:
Stefano D'Angelo 2024-01-11 15:30:50 +01:00
parent 468826463b
commit e3526989c3
10 changed files with 137 additions and 51 deletions

6
notes
View File

@ -47,16 +47,16 @@ product {
VST3: TBD
LV2: manifest.ttl lv2:port, run() (set parameter)
defaultValue:
default value, number, mapped, required for non-bypass input
default value, number, mapped, required for non-bypass
VST3: ParameterInfo defaultNormalizedValue, controller initialize
LV2: manifest.ttl lv2:port lv2:default, activate() (set initial parameter)
minimum:
minimum value, number, mapped, required for non-bypass input
minimum value, number, mapped, required for non-bypass
VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped)
LV2: manifest.ttl lv2:port lv2:minimum, run() (set parameter, value clamped)
LV2:
maximum:
maximum value, number, mapped, required for non-bypass input
maximum value, number, mapped, required for non-bypass
VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped)
LV2: manifest.ttl lv2:port lv2:maximum, run() (set parameter, value clamped)
toggled:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
#define DATA_LV2_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.uri))}}"
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels, 0)}}
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_CONTROL_INPUTS_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_CONTROL_OUTPUTS_N {{=it.product.parameters.filter(x => x.direction == "output").length}}

View File

@ -4,6 +4,11 @@
#include "data.h"
#include "plugin.h"
#if defined(__i386__) || defined(__x86_64__)
#include <xmmintrin.h>
#include <pmmintrin.h>
#endif
typedef struct {
plugin p;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
@ -104,8 +109,27 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
}
#endif
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
__asm__ __volatile__ ("msr fpcr, %0" :: "r"(fpcr | 0x1000000)); // enable FZ
#elif defined(__i386__) || defined(__x86_64__)
const unsigned int flush_zero_mode = _MM_GET_FLUSH_ZERO_MODE();
const unsigned int denormals_zero_mode = _MM_GET_DENORMALS_ZERO_MODE();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#endif
plugin_process(&i->p, i->x, i->y, sample_count);
#if defined(__aarch64__)
__asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr));
#elif defined(__i386__) || defined(__x86_64__)
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_OUTPUTS_N; j++) {
uint32_t k = param_out_index[j];

View File

@ -67,16 +67,22 @@ module.exports = function (data, api) {
var audioBuses = data.product.buses.filter(x => x.type == "audio");
for (var i = 0; i < audioBuses.length; i++) {
var b = audioBuses[i];
for (var j = 0; j < b.channels; j++) {
if (b.channels == "mono") {
var e = { type: "audio", direction: b.direction, name: b.name, sidechain: b.sidechain, cv: b.cv };
e.symbol = data.lv2.busSymbols[i] + "_" + j;
e.symbol = data.lv2.busSymbols[i];
data.tibia.lv2.ports.push(e);
} else {
var e = { type: "audio", direction: b.direction, name: b.name + " Left", shortName: b.shortName + " L", sidechain: b.sidechain, cv: b.cv };
e.symbol = data.lv2.busSymbols[i] + "_L";
data.tibia.lv2.ports.push(e);
var e = { type: "audio", direction: b.direction, name: b.name + " Right", shortName: b.shortName + " R", sidechain: b.sidechain, cv: b.cv };
e.symbol = data.lv2.busSymbols[i] + "_R";
data.tibia.lv2.ports.push(e);
}
}
data.tibia.lv2.ports.sort((a, b) => a.type != b.type ? (a.type == "audio" ? -1 : 1) : (a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0));
api.generateFileFromTemplateFile(`data${sep}manifest.ttl`, `data${sep}manifest.ttl`, data);
api.copyFile(`src${sep}lv2.c`, `src${sep}lv2.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);

View File

@ -39,10 +39,10 @@ static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_AUDIO_I
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ {{=b.channels}},
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.aux}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ {{?b.cv}}Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{??}}Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -54,10 +54,10 @@ static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PRODUCT_BUSES_AUDIO_
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ {{=b.channels}},
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.aux}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ {{?b.cv}}Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{??}}Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -69,10 +69,10 @@ static struct Steinberg_Vst_BusInfo busInfoEventInput[DATA_PRODUCT_BUSES_EVENT_I
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ {{=b.channels}},
/* .channelCount = */ 1,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ Steinberg_Vst_BusTypes_kMain,
/* .flags = */ Steinberg_Vst_BusInfo_BusFlags_kDefaultActive
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -84,10 +84,10 @@ static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_EVENT_O
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ {{=b.channels}},
/* .channelCount = */ 1,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ Steinberg_Vst_BusTypes_kMain,
/* .flags = */ Steinberg_Vst_BusInfo_BusFlags_kDefaultActive
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};

View File

@ -16,6 +16,29 @@
# define TRACE(...) printf(__VA_ARGS__)
#endif
#if defined(__i386__) || defined(__x86_64__)
#include <xmmintrin.h>
#include <pmmintrin.h>
#endif
static double clamp(double x, double m, double M) {
return x < m ? m : (x > M ? M : x);
}
static double parameterMap(Steinberg_Vst_ParamID id, double v) {
return parameterData[id].min + (parameterData[id].max - parameterData[id].min) * v;
}
static double parameterUnmap(Steinberg_Vst_ParamID id, double v) {
return (v - parameterData[id].min) / (parameterData[id].max - parameterData[id].min);
}
static double parameterAdjust(Steinberg_Vst_ParamID id, double v) {
v = parameterData[id].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? v >= 0.5 ? 1.0 : 0.0
: (parameterData[id].flags & DATA_PARAM_INTEGER ? (int32_t)(v + 0.5) : v);
return clamp(v, parameterData[id].min, parameterData[id].max);
}
typedef struct pluginInstance {
Steinberg_Vst_IComponentVtbl * vtblIComponent;
Steinberg_Vst_IAudioProcessorVtbl * vtblIAudioProcessor;
@ -93,7 +116,13 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
return Steinberg_kResultFalse;
p->context = context;
plugin_init(&p->p);
// TODO: set param defaults
#if DATA_PRODUCT_PARAMETERS_N > 0
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
p->parameters[i] = parameterData[i].def;
if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly))
plugin_set_parameter(&p->p, parameterData[i].index, parameterData[i].def);
}
#endif
return Steinberg_kResultOk;
}
@ -189,14 +218,12 @@ static Steinberg_tresult pluginActivateBus(void* thisInterface, Steinberg_Vst_Me
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
}
@ -205,14 +232,12 @@ static Steinberg_tresult pluginActivateBus(void* thisInterface, Steinberg_Vst_Me
#if DATA_PRODUCT_BUSES_EVENT_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PRODUCT_BUSES_EVENT_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
}
@ -225,10 +250,7 @@ static Steinberg_tresult pluginSetActive(void* thisInterface, Steinberg_TBool st
pluginInstance *p = (pluginInstance *)thisInterface;
if (state) {
plugin_set_sample_rate(&p->p, p->sampleRate);
// TODO: mem
plugin_reset(&p->p);
} else {
// TODO: mem
}
return Steinberg_kResultOk;
}
@ -254,9 +276,8 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_I
return Steinberg_kResultFalse;
if (IS_BIG_ENDIAN)
v.u = SWAP_UINT32(v.u);
p->parameters[i] = v.f;
//XXX
plugin_set_parameter(&p->p, i, v.f);
p->parameters[i] = parameterAdjust(i, v.f);
plugin_set_parameter(&p->p, parameterData[i].index, p->parameters[i]);
}
#endif
return Steinberg_kResultOk;
@ -323,15 +344,46 @@ static Steinberg_uint32 pluginIAudioProcessorRelease(void *thisInterface) {
static Steinberg_tresult pluginSetBusArrangements(void* thisInterface, Steinberg_Vst_SpeakerArrangement* inputs, Steinberg_int32 numIns, Steinberg_Vst_SpeakerArrangement* outputs, Steinberg_int32 numOuts) {
TRACE("plugin IAudioProcessor set bus arrangements\n");
if (numIns < 0 || numOuts < 0)
return Steinberg_kInvalidArgument;
if (numIns != DATA_PRODUCT_BUSES_AUDIO_INPUT_N || numOuts != DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kResultFalse;
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
for (Steinberg_int32 i = 0; i < numIns; i++)
if ((busInfoAudioInput[i].channelCount == 1 && inputs[i] != Steinberg_Vst_SpeakerArr_kMono)
|| (busInfoAudioInput[i].channelCount == 2 && inputs[i] != Steinberg_Vst_SpeakerArr_kStereo))
return Steinberg_kResultFalse;
#endif
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
for (Steinberg_int32 i = 0; i < numOuts; i++)
if ((busInfoAudioOutput[i].channelCount == 1 && outputs[i] != Steinberg_Vst_SpeakerArr_kMono)
|| (busInfoAudioOutput[i].channelCount == 2 && outputs[i] != Steinberg_Vst_SpeakerArr_kStereo))
return Steinberg_kResultFalse;
#endif
return Steinberg_kResultTrue;
}
static Steinberg_tresult pluginGetBusArrangement(void* thisInterface, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_Vst_SpeakerArrangement* arr) {
TRACE("plugin IAudioProcessor get bus arrangement\n");
//TBD!
return Steinberg_kNotImplemented;
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
if (dir == Steinberg_Vst_BusDirections_kInput && index >= 0 && index < DATA_PRODUCT_BUSES_AUDIO_INPUT_N) {
*arr = busInfoAudioInput[index].channelCount == 1 ? Steinberg_Vst_SpeakerArr_kMono : Steinberg_Vst_SpeakerArr_kStereo;
return Steinberg_kResultTrue;
}
#endif
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
if (dir == Steinberg_Vst_BusDirections_kOutput && index >= 0 && index < DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N) {
*arr = busInfoAudioOutput[index].channelCount == 1 ? Steinberg_Vst_SpeakerArr_kMono : Steinberg_Vst_SpeakerArr_kStereo;
return Steinberg_kResultTrue;
}
#endif
return Steinberg_kInvalidArgument;
}
static Steinberg_tresult pluginCanProcessSampleSize(void* thisInterface, Steinberg_int32 symbolicSampleSize) {
@ -359,8 +411,30 @@ static Steinberg_tresult pluginSetProcessing(void* thisInterface, Steinberg_TBoo
static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst_ProcessData* data) {
TRACE("plugin IAudioProcessor process\n");
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
__asm__ __volatile__ ("msr fpcr, %0" :: "r"(fpcr | 0x1000000)); // enable FZ
#elif defined(__i386__) || defined(__x86_64__)
const unsigned int flush_zero_mode = _MM_GET_FLUSH_ZERO_MODE();
const unsigned int denormals_zero_mode = _MM_GET_DENORMALS_ZERO_MODE();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#endif
//TBD
#if defined(__aarch64__)
__asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr));
#elif defined(__i386__) || defined(__x86_64__)
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
// IComponentHandler::restartComponent (kLatencyChanged), see https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Workflow+Diagrams/Get+Latency+Call+Sequence.html
return Steinberg_kResultOk;
}
@ -482,24 +556,6 @@ static Steinberg_tresult controllerTerminate(void* thisInterface) {
return Steinberg_kResultOk;
}
static double clamp(double x, double m, double M) {
return x < m ? m : (x > M ? M : x);
}
static double parameterMap(Steinberg_Vst_ParamID id, double v) {
return parameterData[id].min + (parameterData[id].max - parameterData[id].min) * v;
}
static double parameterUnmap(Steinberg_Vst_ParamID id, double v) {
return (v - parameterData[id].min) / (parameterData[id].max - parameterData[id].min);
}
static double parameterAdjust(Steinberg_Vst_ParamID id, double v) {
v = parameterData[id].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? v >= 0.5 ? 1.0 : 0.0
: (parameterData[id].flags & DATA_PARAM_INTEGER ? (int32_t)(v + 0.5) : v);
return clamp(v, parameterData[id].min, parameterData[id].max);
}
static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct Steinberg_IBStream* state) {
TRACE("controller set component state %p %p\n", thisInterface, (void *)state);
if (state == NULL)

View File

@ -8,7 +8,7 @@
{
"type": "audio",
"direction": "input",
"channels": 1,
"channels": "mono",
"name": "Input",
"shortName": "Input",
"sidechain": false,
@ -18,7 +18,7 @@
{
"type": "audio",
"direction": "output",
"channels": 1,
"channels": "mono",
"name": "Output",
"shortName": "Output",
"sidechain": false,