From e3526989c3edc318fec5f1a9801555875fd288fe Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Thu, 11 Jan 2024 15:30:50 +0100 Subject: [PATCH] more and more --- notes | 6 +- templates/lv2/data/.manifest.ttl.swp | Bin 12288 -> 0 bytes templates/lv2/src/.data.h.swp | Bin 12288 -> 0 bytes templates/lv2/src/.lv2.c.swp | Bin 16384 -> 0 bytes templates/lv2/src/data.h | 4 +- templates/lv2/src/lv2.c | 24 ++++++ templates/lv2/tibia-index.js | 12 ++- templates/vst3/src/data.h | 20 ++--- templates/vst3/src/vst3.c | 118 ++++++++++++++++++++------- test/product.json | 4 +- 10 files changed, 137 insertions(+), 51 deletions(-) delete mode 100644 templates/lv2/data/.manifest.ttl.swp delete mode 100644 templates/lv2/src/.data.h.swp delete mode 100644 templates/lv2/src/.lv2.c.swp diff --git a/notes b/notes index bf81a43..5f13ff8 100644 --- a/notes +++ b/notes @@ -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: diff --git a/templates/lv2/data/.manifest.ttl.swp b/templates/lv2/data/.manifest.ttl.swp deleted file mode 100644 index d8cb2752b9c654fdae11de93ca912a673a73dc13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O^6&t6vrz{qLUaE6-B+YBQCp`?U{*2Vw+@>tO*Ik?2?Z~*leI?x@NZ4{-QtD z9hcc$42UL3AO{a3qJoGw%_W}1gLnuYqGu1mgBKAIa}YuQuc~`KcJ||tQ=kTZJ6$!e zUcdUk*RMOI>(!a#uUUKT-3*_H8GG*YkHml5&$GX#7)w&ow(m{d|(m%Ne+Kk|4gl8U#uyW;YcS9~7GrbtpdO}zmJ zW?&RB3fzGLJJ}1nYgKaaZ21}M(MQhSfiJVvC}0#Y3K#{90!9I&fKk9GU=+C96iA~j z>;i(mCl7of|K76dJ0F@aqkvJsC}0#Y3K#{90!9I&fKk9GU=%P47zOS^1-Q%D7xyye zZ$|5{+xDKv@w?PO_f@9!C@b80+-3C8^&%hPX24{c`ZtrC5Pw*A+ z!K+{|cpB^ge?P$3E$|)q61)#0a2}ih4tNs$zJswF;5zseTm_fFn_wQ)!8CBd2-pVx z*v{Bb;2L-bw7>+|3w|y!b{WLr92fx>*aCjLALjw@f*CLkCcsnRF|ZZ%{-)GtK|u|Se6erTP2gz(iM~Q9QBYFN`i?7 zO{`k$;`PDIODPGFoeyRxEyLM>E3J;tm!zNhdQCpq$Xo_}=6bNExvJ>29SLjyeya@e z(m3?W2w0ysY5Vn1R{?UT21Oz0YE)UCM|q#*zEITyyJBo7Sv^5z2CdQRF01wu%1al~ zM7e8Iwjfy4Jz>yuLx*|+N>at?%2=mX1uKInOA#uCaGZ{(5eDoK7)?!OX>U$ly`>U| zez=0y*e|V^)VuGwQO1o$?Qe3X_XAlU%3K-dQ=JY>agJR~pFdYGT7B8m3!dm(C-7cp z&}es)J7m`@{dKO5HLHA+l;uAc$+60L7?cwIn-+g)+7*dx1-e<$&gr$(B7D_zdr~V` zT(!79HFI4eTNYba`KGp}yG`DeYWc9+e5L{&obGu8w$&lqX0x}GfyT3rhIb(y_ z9L|V1p?e})W99s8b^PVI=g--r`e3YLizU&Zn>6h0MQu8UyO_SZwUZ!>2b>g(&)J(S z*VU+QeTfiX9)Qj^daa?&^J#L@-^r) z(5IkJKp%rX0v&-~1^o!I{Q!z%{5FmgFC>5jkN^@u0!RP}{4WUPxpc&k=*z^IPVWh2 zCg&$jI5lbdUZ6sAC|t#Z!h~8^>BLmWKBtyNa|2JRz;knSV*?&LBH#lhJej=nBIQRa zSEQGGt*2AVH+>ecaYH(MqV*<)fwYEmpiGGYjf7O^tG1$vjSYQm5gXpxt@Ud5ey6?L z-|5*q?N+bTZrbgBZ@=H`+O2n}MW-Y$hIG9hy-ML^TAF2+CX8yucQkEOONWb0cml zuRifT$)ys^EflpLW@(PuWWEmcMp2O%HQA(^(hz!oMQ%Ih&!n2;w0Ms!*_ z@d@A6RnutA7mbmXoRLgDRQ}NQm@*6?dC~wta}6P(alc=Z>E*0~Llr~=1=UFM6kG_& z=Vv>eMWax;a-~{aX_6L1Vp3UcGOItM0%JU=2f(zM^Kshb;D(m{m0SL$$rRSwf=6So$e3z&KtE>tKNitVkyDHDCEnz z-QUw#^yYRRSi*7ZJS%e9U#~xtD=wHUS z7+~|DYWF)0BR4CC*%x4EkE?#~`o*pagd8;m6b0-k3m*tR@tJg>XZ$$+Vnl%`Li#!K E4{%aOYXATM diff --git a/templates/lv2/src/.lv2.c.swp b/templates/lv2/src/.lv2.c.swp deleted file mode 100644 index 32f0bce58a9e8d9e380112fe4bd05bad8ad0a3b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI2UuYaf9LLA{r*3Pl+G?My)24(=a=A-V3eq%{q)FRgau<@jk{Z%wvp1J)bGLik z?j4tw+82>3_CYEX9|V2WA_^iX2o?HL1s|#w#8+#@2gOzp)EB?AJ9Bq?xl7U-QDFj~ z-0kdde>3x)-~8E`o9j6?I!>RC^%49%LdcGxH`uLBC&;f!LR^n!4cp;&R{Rro-N&r5 zGvqjn-BZ2$x~KQ`_M{Joo_k&x#*3`rxN*;#vy8aM@`aq?F*lwo_r=|!$v?}10bR}aA!ybE3hv!ECJw3(2v!5837Faw4_Ke)Y#kPF}xaDf4IZ~|!Hx<<&` zpbVx#0z36wqzyT*Y)TJO9DQq|4uzs)GS`)*N0}>8ivLSd>Kgb-3e!!eWP7Mo zNDN;P;lgbyLzI?%CAe&UOXd*RoWMq;zWhg(cX)H^hp}qLOpMRGnSexHe^2m{~k>S>Ux%d6tyHs!0q7EIO z7@V5o9e@B-a6)3H6vE-~pw=tT!sj8UnGAE$Wq&VqC_vDO%smf;Y!Y}YevlhICU zp^YOV>}ts!@@qeSt7UkWNz0Cvp~aFN89UaeA2sYu4h<~aL}|5qg(4i$M-bLU=9P*z zt)R>0(V%(A9;u)}5B~ACg^o= zSU=9J(yKx}#&5=O|B@{#Mje#88uI%ax>JVv;Z&8QHYoio4KAgT4RxpOZJ3@_#!u*) zHM&q=>g zjNkg9ql1aW$QU2TgSjRMLeaWQGc8K$&oaLEhUuY&^QQAd3){8Uz}IAz3RLd00*$^` zD1W1=U;MutP#7$2W@3&<12zk)x{-vNV8-LaPG>lvWWN{ViVW^rpVwp(pSmm_kbJeU zY?S3gAC>}EtEIr2gA+cmR9OEoudBz>UDTsR9M+XK)F)e*hr+h5M3uWPQDbDST%bnl zP#p4wl9+Oee4J{pwLBJ%b$9rxq&mx4e3}q*7lwL&#Ug@91d6}dl#^s_Ca-#s)2H-; zNXi>IjCc{(I>nr9M~jps^ycE&o|Tab6S!^6zLJk00(z`B!WgA_ODP;w0}>s0Gc{=}b7n=ySY0-~UtO<@oY!@psTOW2T(}lprCH@$ zn1(b6+CyemX_i-GFKC@rqh)=6K^yiHZ>hkrPLZ*OHB_5ro4Hbk(cM9S#};%}hdF=$ui%~h2H@}i@_hd~-s|52uYl8F2~@y1 zh=a}GCf@O{f)Bt&a2m{l=fH8W72FiQzvKSZpHe_6pcGIFC 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}} diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index 3bb2ca4..19086b6 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -4,6 +4,11 @@ #include "data.h" #include "plugin.h" +#if defined(__i386__) || defined(__x86_64__) +#include +#include +#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]; diff --git a/templates/lv2/tibia-index.js b/templates/lv2/tibia-index.js index f888b34..039347d 100644 --- a/templates/lv2/tibia-index.js +++ b/templates/lv2/tibia-index.js @@ -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); diff --git a/templates/vst3/src/data.h b/templates/vst3/src/data.h index 6a161b5..f1bc137 100644 --- a/templates/vst3/src/data.h +++ b/templates/vst3/src/data.h @@ -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{{?}} }, {{~}} }; diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index fc54380..706f321 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -16,6 +16,29 @@ # define TRACE(...) printf(__VA_ARGS__) #endif +#if defined(__i386__) || defined(__x86_64__) +#include +#include +#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) diff --git a/test/product.json b/test/product.json index 40bab97..4128589 100644 --- a/test/product.json +++ b/test/product.json @@ -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,