Adventures in Script Node - performance...I think
-
So I have my all new distortion SNEX node set up - I've compiled it (along with its co-stars) into a DLL, I've replaced it using HardCodedMasterFX, I've compiled my project -- all good....
..but....
When I run my plug-in this fx introduces a considerable delay in the signal- such that mixing it back with the dry signal seems like its using an 0.5 second fixed delay (it isnt)
.. what am I doing wrong?
-
@Lindon said in Adventures in Script Node - performance...I think:
So I have my all new distortion SNEX node set up - I've compiled it (along with its co-stars) into a DLL, I've replaced it using HardCodedMasterFX, I've compiled my project -- all good....
..but....
When I run my plug-in this fx introduces a considerable delay in the signal- such that mixing it back with the dry signal seems like its using an 0.5 second fixed delay (it isnt)
.. what am I doing wrong?
Have you used Oversampling? If yes, this is normal. Firstly you need to find out empirically what is the delay amount in samples. You can do it with null test using free tools, I use: https://www.forward-audio.com/phase-alignment-plugin-free-fasampledelay/
After you know the sample delay value, insert a Script FX at the end of your module tree. Then use that delay value in
Engine.setLatencySamples(int latency);
on the prepareToPlay function of the ScriptFX. This will apply the delay compensation for the DAW. It will declare to the DAW on initialization that this plugin have x sample delay, so the DAW will compensate it. -
@orange yeah but 0.5 seconds is way too long for oversample delay which is usually a couple of samples. There must be something else.
-
@Christoph-Hart said in Adventures in Script Node - performance...I think:
@orange yeah but 0.5 seconds is way too long for oversample delay which is usually a couple of samples. There must be something else.
Yeah @orange - I'm not using oversampling, and the dry/wet mix is inside the plug so that wouldnt be it....
@Christoph-Hart I've tried turning all teh other FX off and it seems its my Dist module, as theres no delay when I turn it off and use only one of the other FX...
Here's my XML
<?xml version="1.0" encoding="UTF-8"?> <Network ID="DistNode" Version="0.0.0" AllowCompilation="1"> <Node FactoryPath="container.chain" ID="DistNode" Bypassed="0" ShowParameters="1"> <Nodes> <Node ID="xfader" FactoryPath="control.xfader" Bypassed="0"> <Properties> <Property ID="NumParameters" Value="2"/> <Property ID="Mode" Value="Switch"/> </Properties> <SwitchTargets> <SwitchTarget> <Connections> <Connection NodeId="FuzzPre" ParameterId="Bypassed"/> <Connection NodeId="FuzzPost" ParameterId="Bypassed"/> </Connections> </SwitchTarget> <SwitchTarget> <Connections> <Connection NodeId="OverDrivePre" ParameterId="Bypassed"/> <Connection NodeId="OverDrivePost" ParameterId="Bypassed"/> </Connections> </SwitchTarget> </SwitchTargets> <Parameters> <Parameter MinValue="0.0" MaxValue="1.0" ID="Value" Automated="1"/> </Parameters> </Node> <Node ID="FuzzPre" FactoryPath="container.soft_bypass" Bypassed="0"> <Nodes> <Node ID="svf_eq" FactoryPath="filters.svf_eq" Bypassed="0"> <ComplexData> <Filters> <Filter Index="-1" EmbeddedData=""/> </Filters> </ComplexData> <Parameters> <Parameter MinValue="20.0" MaxValue="20000.0" SkewFactor="0.2299045622348785" ID="Frequency" Automated="1"/> <Parameter MinValue="0.300000011920929" MaxValue="9.899999618530273" SkewFactor="0.2647178173065186" ID="Q" Value="1.0"/> <Parameter MinValue="-18.0" MaxValue="18.0" ID="Gain" Value="12.384"/> <Parameter MinValue="0.0" MaxValue="1.0" SkewFactor="0.3010300099849701" ID="Smoothing" Value="0.009999999776482582"/> <Parameter MinValue="0.0" MaxValue="4.0" StepSize="1.0" ID="Mode" Value="2.0"/> <Parameter MinValue="0.0" MaxValue="1.0" StepSize="1.0" ID="Enabled" Value="1.0"/> </Parameters> </Node> </Nodes> <Parameters/> </Node> <Node ID="OverDrivePre" FactoryPath="container.soft_bypass" Bypassed="0"> <Nodes> <Node ID="svf_eq1" FactoryPath="filters.svf_eq" Bypassed="0"> <ComplexData> <Filters> <Filter Index="-1" EmbeddedData=""/> </Filters> </ComplexData> <Parameters> <Parameter MinValue="20.0" MaxValue="20000.0" SkewFactor="0.2299045622348785" ID="Frequency" Automated="1"/> <Parameter MinValue="0.300000011920929" MaxValue="9.899999618530273" SkewFactor="0.2647178173065186" ID="Q" Value="1.0"/> <Parameter MinValue="-18.0" MaxValue="18.0" ID="Gain" Value="-13.104"/> <Parameter MinValue="0.0" MaxValue="1.0" SkewFactor="0.3010300099849701" ID="Smoothing" Value="0.009999999776482582"/> <Parameter MinValue="0.0" MaxValue="4.0" StepSize="1.0" ID="Mode" Value="2.0"/> <Parameter MinValue="0.0" MaxValue="1.0" StepSize="1.0" ID="Enabled" Value="1.0"/> </Parameters> </Node> </Nodes> <Parameters/> </Node> <Node ID="snex_shaper1" FactoryPath="core.snex_shaper" Bypassed="0"> <Properties> <Property ID="ClassId" Value="ShaperCode01"/> </Properties> <ComplexData> <Tables/> <SliderPacks/> <AudioFiles/> <Filters/> <DisplayBuffers> <DisplayBuffer Index="-1" EmbeddedData=""/> </DisplayBuffers> </ComplexData> <Parameters> <Parameter MinValue="0.2" MaxValue="5.0" ID="Gain" Automated="1"/> <Parameter MinValue="1.0" MaxValue="8.0" ID="Mode" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1.0" ID="Feedback" Automated="1"/> </Parameters> </Node> <Node ID="FuzzPost" FactoryPath="container.soft_bypass" Bypassed="0"> <Nodes> <Node ID="svf_eq2" FactoryPath="filters.svf_eq" Bypassed="0"> <ComplexData> <Filters> <Filter Index="-1" EmbeddedData=""/> </Filters> </ComplexData> <Parameters> <Parameter MinValue="20.0" MaxValue="20000.0" SkewFactor="0.2299045622348785" ID="Frequency" Automated="1"/> <Parameter MinValue="0.300000011920929" MaxValue="9.899999618530273" SkewFactor="0.2647178173065186" ID="Q" Value="1.0"/> <Parameter MinValue="-18.0" MaxValue="18.0" ID="Gain" Value="-10.512"/> <Parameter MinValue="0.0" MaxValue="1.0" SkewFactor="0.3010300099849701" ID="Smoothing" Value="0.009999999776482582"/> <Parameter MinValue="0.0" MaxValue="4.0" StepSize="1.0" ID="Mode" Value="2.0"/> <Parameter MinValue="0.0" MaxValue="1.0" StepSize="1.0" ID="Enabled" Value="1.0"/> </Parameters> </Node> </Nodes> <Parameters/> </Node> <Node ID="OverDrivePost" FactoryPath="container.soft_bypass" Bypassed="0"> <Nodes> <Node ID="svf_eq3" FactoryPath="filters.svf_eq" Bypassed="0"> <ComplexData> <Filters> <Filter Index="-1" EmbeddedData=""/> </Filters> </ComplexData> <Parameters> <Parameter MinValue="20.0" MaxValue="20000.0" SkewFactor="0.2299045622348785" ID="Frequency" Automated="1"/> <Parameter MinValue="0.300000011920929" MaxValue="9.899999618530273" SkewFactor="0.2647178173065186" ID="Q" Value="1.0"/> <Parameter MinValue="-18.0" MaxValue="18.0" ID="Gain" Value="13.824"/> <Parameter MinValue="0.0" MaxValue="1.0" SkewFactor="0.3010300099849701" ID="Smoothing" Value="0.009999999776482582"/> <Parameter MinValue="0.0" MaxValue="4.0" StepSize="1.0" ID="Mode" Value="2.0"/> <Parameter MinValue="0.0" MaxValue="1.0" StepSize="1.0" ID="Enabled" Value="1.0"/> </Parameters> </Node> </Nodes> <Parameters/> </Node> <Node ID="gain" FactoryPath="core.gain" Bypassed="0"> <Parameters> <Parameter MinValue="-100.0" MaxValue="24.0" StepSize="0.1000000014901161" SkewFactor="5.422270774841309" ID="Gain" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1000.0" StepSize="0.1000000014901161" SkewFactor="0.3010300099849701" ID="Smoothing" Value="20.0"/> <Parameter MinValue="-100.0" MaxValue="0.0" StepSize="0.1000000014901161" SkewFactor="5.422270774841309" ID="ResetValue" Value="0.0"/> </Parameters> </Node> <Node ID="limiter" FactoryPath="dynamics.limiter" Bypassed="0"> <ComplexData> <DisplayBuffers> <DisplayBuffer Index="-1"/> </DisplayBuffers> </ComplexData> <Parameters> <Parameter MinValue="-100.0" MaxValue="0.0" StepSize="0.1000000014901161" SkewFactor="5.422270774841309" ID="Threshhold" Value="-1.29999852925539"/> <Parameter MinValue="0.0" MaxValue="250.0" StepSize="0.1000000014901161" SkewFactor="0.4306765496730804" ID="Attack" Value="0.0"/> <Parameter MinValue="0.0" MaxValue="250.0" StepSize="0.1000000014901161" SkewFactor="0.4306765496730804" ID="Release" Value="84.90000126510859"/> <Parameter MinValue="1.0" MaxValue="32.0" StepSize="0.1000000014901161" SkewFactor="0.2968033850193024" ID="Ratio" Value="1.100000001490116"/> </Parameters> </Node> </Nodes> <Parameters> <Parameter ID="Frequency" MinValue="20.0" MaxValue="20000.0" SkewFactor="0.2299045622348785" Value="761.679568885437"> <Connections> <Connection NodeId="svf_eq" ParameterId="Frequency"/> <Connection NodeId="svf_eq1" ParameterId="Frequency"/> <Connection NodeId="svf_eq2" ParameterId="Frequency"/> <Connection NodeId="svf_eq3" ParameterId="Frequency"/> </Connections> </Parameter> <Parameter ID="MakeUp" MinValue="-100.0" MaxValue="24.0" StepSize="0.1000000014901161" SkewFactor="5.422270774841309" Value="14.90000171214341"> <Connections> <Connection NodeId="gain" ParameterId="Gain"/> </Connections> </Parameter> <Parameter ID="Depth" MinValue="0.2" MaxValue="5.0" Value="4.5712"> <Connections> <Connection NodeId="snex_shaper1" ParameterId="Gain"/> </Connections> </Parameter> <Parameter ID="Mode" MinValue="1.0" MaxValue="8.0" StepSize="1" Value="5.0"> <Connections> <Connection NodeId="snex_shaper1" ParameterId="Mode"/> </Connections> </Parameter> <Parameter ID="Feedback" MinValue="0.0" MaxValue="0.8" Value="0.5312"> <Connections> <Connection NodeId="snex_shaper1" ParameterId="Feedback"/> </Connections> </Parameter> <Parameter ID="FuzzOverDrive" MinValue="0.0" MaxValue="1.0" StepSize="1" Value="0.0"> <Connections> <Connection NodeId="xfader" ParameterId="Value"/> </Connections> </Parameter> </Parameters> </Node> </Network>
and the code I'm running in the SNEX shaper - where you can see I'm doing some fairly simple but "silly" stuff...it doenst matter which mode I use - they all introduce the delay...:
template <int NumVoices> struct ShaperCode01 { SNEX_NODE(ShaperCode01); float a = 0.0f; float mode = 0.0f; float q = 0.0f; float spare = 0.0f; float fback = 0.0f; float fbacksig = 0.0f; float tsig = 0.0f; // Implement the Waveshaper here... float getSample(float input) { if(mode == 1) { // just abs fbacksig = Math.abs(input*a)*fback; tsig = Math.abs(input*a) + fbacksig; tsig = tsig / (1.0+fback); if(input < 0.0) { tsig = tsig * -1.0; } if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; }; }; }; if(mode == 2) { // attenuated sin spare = 1.8 + (a*0.4); //q = (a*a)/2; //input = Math.sin(input*q); q = (spare*spare)/2.0; fbacksig = Math.sin(input * q); tsig = Math.sin(input * q) + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; }; }; }; if(mode == 3) { // attenuated sqr spare = 1.0 + (a *0.8); fbacksig = Math.sqr(input*spare); tsig = Math.sqr(input*spare) + fbacksig; tsig = tsig / (1.0+fback); if(input < 0.0) { tsig = tsig * -1.0; } if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; }; }; //input = Math.sqr(input*spare); //input = Math.sqr(input*a); }; if(mode == 4) { //attenuated sqr root spare = a * 0.6; fbacksig = Math.sqrt(input*spare); tsig = Math.sqrt(input*spare) + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; } } //input = Math.sqrt(input*spare); //input = Math.sqrt(input*a); }; if(mode == 5) { //tanh fbacksig = Math.tanh(input*a); tsig = Math.tanh(input*a) + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; } } //input = Math.tanh(input*a); }; if(mode == 6) { //sat q = (a*0.2) + Math.tanh(input*input*input*input*input); fbacksig = Math.tanh(input + q); tsig = Math.tanh(input + q) + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; } } //input = Math.tanh(input + q); }; if(mode == 7) { // oversat spare = Math.tanh(input*(1.1+ (a*0.1))*2.0); fbacksig = fbacksig - Math.tanh(spare); tsig = input - Math.tanh(spare) + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input = 0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; } } //input = input - Math.tanh(spare); // - input; }; if(mode == 8) { // rect ifier if (input > 0.0) { spare = 1.0; }else{ spare = -1.0; }; fbacksig = input * spare; if (fbacksig > 0.6) { q = (fbacksig - (a*0.2)); fbacksig = (a*0.2) - q; if(fbacksig < 0.0) { fbacksig = fbacksig * -1.0; } }; fbacksig = fbacksig * spare; input = input * spare; if (input > 0.6) { q = (input - (a*0.2)); input = (a*0.2) - q; if(input < 0.0) { input = input * -1.0; } }; input = input * spare; tsig = input + fbacksig; tsig = tsig / (1.0+fback); if(tsig > 1.0) { input =0.9; }else{ if(tsig < -1.0) { input = -0.9; }else{ input = tsig; } } } return input; } // These functions are the glue code that call the function above template <typename T> void process(T& data) { for(auto ch: data) { for(auto& s: data.toChannelData(ch)) { s = getSample(s); } } } template <typename T> void processFrame(T& data) { for(auto& s: data) s = getSample(s); } void reset() { } void prepare(PrepareSpecs ps) { } void setExternalData(const ExternalData& d, int index) { } template <int P> void setParameter(double v) { if(P == 0) { a = (float)v; }; if(P == 1) { mode = (float)v; }; if(P == 2) { fback = (float)v; }; } };
any pointers appreciated....
-
Check the limiter attack time, I think if it's zero it goes into lookahead mode with a considerable delay.
-
@Christoph-Hart ok will do...
-
@Christoph-Hart Yes limiter's attack time causes latency since it has a lookahead mode.
-