Tonal Balance
-
@Christoph-Hart Thank you for the update. on macOS M1, While compiling the current Hise develop branch, I get
Use of undeclared identifier 'NumVoices'
errors on the below places:SN_POLY_NODE_ID("transport");
void onTransportChange(bool isPlaying, double /*ppqPosition*/) override { value = isPlaying; }
SN_POLY_NODE_ID("ppq");
void updateValue() { value = hmath::fmod(ppqPos, loopLengthQuarters) / loopLengthQuarters; }
-
@Steve-Mohican MacOS? I just compiled it without issues on PC
-
@Matt_SF Yes macOS Monterey, Hise can't be compiled.
-
@Steve-Mohican Xcode 13.1 ?
-
@d-healey Yes Xcode 13.1. I was able to build Hise till the last commits, I did 3 weeks ago.
-
It's fixed now.
-
@Christoph-Hart Legend, Can you hear The very low low frequencies here?
HiseSnippet 1577.3oc6Y0raabCDlqjocjyOnoMonG0gdvAH0vxIMo.8fksrUpQibDrbbSN4RuKkDi1kb6tT1Vosm5kbqmyo1Ggds2xKP.JPdJ5s7FjNy9i2csVKKoDGTDDEf.wgbH+lY9lghia5oL499JOhQocF3xIFWh1ZfT2sVWlPR1bchwUnMX9ZtW4PQqMvk46ysHFFEuGJvnzLjfOudk0X1LoIOQDgrqRXxuuvQnSj1r52Krsqyr36HbRs5aWcSSkrlxV0GvSQ5RDWlYOVG9VLbYEnDiY2vRnUdszLM2mXLyZJqAs5pNTFt9cE9h8s43fJjVvFEJttx1BQL9cRstBaqlw1sOgXPal3EJF5EtFsgvRbr7DuwmDLQ4DMR6OLJjEdEy.uJmF7xARFofzLgP5pzVldBWcxLHdtHcSIDbZy.2dZnDtVhwKn0TvBj5EcX8308fAGqvB2YoktYY3+tw21tuzTKTxxJ4VJM+AxEtw7+77kl+Wmu7Impc6bmCOFOksM2K2owHs2nTbAYem84d2r7AL697iWHX9Y8oyNd9TyPqN0BUxMkB8Cb4QiSHEUxIBPhbav2d3lqyzLLnDICVmK2SKP3XrN+.fgGFhJQWm62SqbAN9PwOf4nr5ayzYoSXNTzDf+HSLDCTRegdP5brSxwl4z8GKkaJPtV6XB2qRaJzlcyGuExAufW67FuQYrWltQ61bScBXmgV+QiL8blwiJcFUOxIUc9nTU37Qfbongkq+nJ4lj9LZRBgqG2k4w2Q0zlMXAeliqMea.u2r791JydsDOkObVjaHDVCWwBlcYRI21eZR1l8cTALx1p9ZgrSCl1SbDThcq9Nsfx5l7ZQnCjYT.yyBGuDNF4Ks3RqfAuA9DMYEbrQzjUhmLUJ5Vb8gJudAginuC1Rnuece2XQqZaqNrlxwUDwdgXPfrlJ6AtcURgIJJbEwHcUGUe3Phf62w72gIrQ59tbO+fMYN5RKB+Cn5aor.mCsNyDbhCZxzcwbFrVDPJ4dKZdL4LCtRyIvsH9JvPOB.GGzLCt.rXphOgbObDjwUHbW2zeWbVSlMYWL1h.kf6YnuI.eANlKSa6w+o87csE5aQNUDGLOAo.MYdv0vvUGXUuBSDjSzDgb7H.HMDxHTl7a.ZvNJqrm8ppszbWj4mtvRqd7CCgMJ8k+x+d2ey4kqfl1EnqwjVkqPFZuCJgK4AYCHXJjLLJ5soEFOs8prWExwHEEdQZcve0mKMGDb4P9ps7HUKNNDySPvNGceFRpOCNyj3uOwwLa3wDZSYNlqSehku6hOwVH6cnP+TOf0Ofjd6KMqtyyeCdDwUAgZBofxoyMQLAktNJ9ty5B6XFP3WQJqzheTb57FPEIK3HBT.2ORFdSgT7l4d2wa.AUi4MoiUY2pp+Q0U6qUNPUw.ylLZRLgLDXf8XXv75UFBLARQvLKM3tjg1YRJtyEnV8cbFbhn57T.mcWzou8IBkAEMgOmZ.rPl.3jj1lmECV2339O1hmiFtACsMjoolWZzSFJea4yi7shmHea4oIeS9w7s+GkuAjuTbmYocPtQlX5EApiGewNSHoYDoZEGsw93WjiwRNgw9mO+4+8vF6K57WWuZngD7z8g14I2OW82qNVG8O9Yq+pnfdKGkR2E9wgCe+L472zuDcatOWmaolbqtt7GqtdFUWOU6hrlR0ygE7CyeqeF8UBmD3OPY5fdTE7Co+7fwk+A1A7x2iCEvwWrVYDso5eF21T4N1so5AlZ332wiI8cU9YCHbGwNJIZiIBenOGq7sM9HjzxqoXd4N0qWoNXj4pSKltuWvqYhenRp2dWbpdva1VRjZ84752YNu5c1609Z712FlhiGbOi9GTJFisD3k4aHOfaCIIAX7Sgrh1r915XoYI4MTRU7SXSX.ayg2e2oCOa4f7LnU0ZlYuDIWq51baNKMa9KqdefEx7ZDTibp7ESdaOyMd8EzP3VFyLK+gQ6yJ9AT6yl.n79nQQuONCGlomZOyv9qgb4KDHAraYve8hRzF33xUHGDdKJE6ZDwApHtmoI5t+Jv+juNKOE5bqoPmaOE570SgN2YJz4tSgNeyH0AuLJ5UFXpHHn4FgOFxXCICXxgO83+.3jGfXL
I added a Gain knob to mute the Upper band, and There is a small leak of Sub & Low frequencies there, and Yeah it is Audible and in meter it shows up.
Just play on low Notes
-
@Natan A linkwitz-riley filter is not a digital brick wall filter so of course you're getting a little bit of leakage. I think they are 12dB/octave so if the crossover is set at 80 Hz, you'll get -12dB for 40Hz and -24dB for 20Hz.
-
@Christoph-Hart said in Tonal Balance:
If anybody has ideas for more templates, let me know, they are pretty easy to add.
Can you add a compressor template with the soft knee option please? Using envelope followers to make a compressor is very hard for those who don't know scriptnode & dsp well.
I think a soft knee option was asked a couples of times. Lots of people would be glad to see this.
-
@Steve-Mohican said in Tonal Balance:
@Christoph-Hart said in Tonal Balance:
If anybody has ideas for more templates, let me know, they are pretty easy to add.
Can you add a compressor template with the soft knee option please? Using envelope followers to make a compressor is very hard for those who don't know scriptnode & dsp well.
I think a soft knee option was asked a couples of times. Lots of people would be glad to see this.
I totally agree that. Yes the current compressor enough for instruments but not enough for the general purpose audio fx compression since it's behavior is very harsh (it is a hard knee comp actually).
Please add a scriptnode compressor node or template with a customizable knee value @Christoph-Hart.
-
@Christoph-Hart There is a basic example of the soft knee compressor here: https://github.com/p-hlp/CTAGDRC
This is beyond my skills but I am sure it won't take to adapt it to Hise scriptnode for you. Please add this, we really need that.
-
@Fortune Well that's a GPL licensed code so you won't be able to use it in a proprietary project.
-
@Christoph-Hart said in Tonal Balance:
@Fortune Well that's a GPL licensed code so you won't be able to use it in a proprietary project.
The soft knee equation is not licensed to anyone, it is universal :) https://dsp.stackexchange.com/questions/73619/how-to-derive-equation-for-second-order-interpolation-of-soft-knee-cutoff-in-a-c
I just gave this example to show how it can be done. You can modify or duplicate the juice compressor or simple compressor with the equation.
The standard hard knee comp equation is this (I believe Hise Simple Compressor and jcompressor uses this):
But the soft knee equation is that:
Soft knee sounds musical and more natural, where hard knee sounds digital and pretty bad on most of the professional mix cases.
-
@Fortune If you're that deep into the subject, you should be able to transform this into C++ or SNEX code, it's basically just rewriting the formula so that the computer understands it.
template <int NV> struct soft_knee_mod { SNEX_NODE(soft_knee_mod); double W = 0.2; double T = 0.5; double R = 4.0; double Xg = 1.0; /** If you define this method, it will create a mod dragger that will send out the value you set the v parameter reference to. This function takes the parameters and applies the formula for the soft-knee curve... */ bool handleModulation(double& v) { if(Xg == 0.0) { v = 1.0; return true; } if(T == 1.0 && W == 0.0) { v = 1.0; return true; } if(2.0 * (Xg - T) < (-1.0 * W)) { v = Xg; } else if (2.0 * Math.abs(Xg - T) <= W) { const double v1 = (1.0 / R - 1.0); const double v2 = (Xg - T + W * 0.5); v = Xg + v1 * v2 * v2 / (2.0 * W); } else { v = T + (Xg - T) / R; } v = Math.range(v / Xg, 0.0, 1.0); return true; } /** You need to add 4 Parameters: - Input - Threshhold - Ratio - Knee Width Then connect the Input knob to the mod output of the envelope follower and connect the mod output of this node to the gain or mul node that attenuates the signal. */ template <int P> void setParameter(double v) { if(P == 0) // Input value Xg = v; if(P == 1) // Threshhold T = Math.range(v, 0.0, 1.0); if(P == 2) // Ratio R = Math.range(v, 1.0, 32.0); if(P == 3) // Knee Width W = Math.range(v, 0.0, 1.0); } void handleHiseEvent(HiseEvent& e){} void setExternalData(const ExternalData& d, int index){} void prepare(PrepareSpecs ps){} void reset(){} template <typename ProcessDataType> void process(ProcessDataType& data){} template <int C> void processFrame(span<float, C>& data){} };
At the moment it's not possible to share snippets with SNEX nodes, so you have to paste this in manually.
-
And here's the XML for the network. Copy this into a file called
softknee_comp.xml
<?xml version="1.0" encoding="UTF-8"?> <Network ID="softknee_comp" Version="0.0.0" AllowCompilation="1"> <Node FactoryPath="container.chain" ID="softknee_comp" Bypassed="0" ShowParameters="1"> <Nodes> <Node ID="frame2_block" FactoryPath="container.frame2_block" Bypassed="0"> <Nodes> <Node ID="converter" FactoryPath="control.converter" Bypassed="0"> <Properties> <Property ID="Mode" Value="db2Gain"/> </Properties> <ModulationTargets> <Connection NodeId="snex_node" ParameterId="Threshold"/> </ModulationTargets> <Parameters> <Parameter MinValue="-100.0" MaxValue="0.0" StepSize="0.1" SkewFactor="5.422270979580217" ID="Value" Automated="1"/> </Parameters> </Node> <Node ID="envelope_follower" FactoryPath="dynamics.envelope_follower" Bypassed="0"> <ModulationTargets> <Connection NodeId="snex_node" ParameterId="Input"/> </ModulationTargets> <ComplexData> <DisplayBuffers> <DisplayBuffer Index="-1"/> </DisplayBuffers> </ComplexData> <Parameters> <Parameter MinValue="0.0" MaxValue="1000.0" StepSize="0.1000000014901161" SkewFactor="0.2313782125711441" ID="Attack" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1000.0" StepSize="0.1000000014901161" SkewFactor="0.2313782125711441" ID="Release" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1.0" ID="ProcessSignal" Value="0.0"/> </Parameters> </Node> <Node ID="snex_node" FactoryPath="core.snex_node" Bypassed="0"> <Properties> <Property ID="ClassId" Value="soft_knee_mod"/> </Properties> <ModulationTargets> <Connection NodeId="mul" ParameterId="Value"/> </ModulationTargets> <ComplexData> <Tables/> <SliderPacks/> <AudioFiles/> <Filters/> <DisplayBuffers/> </ComplexData> <Parameters> <Parameter MinValue="0.0" MaxValue="1.0" ID="Input" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1.0" ID="Threshold" Automated="1"/> <Parameter MinValue="1.0" MaxValue="32.0" ID="Ratio" Automated="1"/> <Parameter MinValue="0.0" MaxValue="1.0" ID="KneeWidth" Automated="1"/> </Parameters> </Node> <Node ID="mul" FactoryPath="math.mul" Bypassed="0"> <Parameters> <Parameter MinValue="0.0" MaxValue="1.0" ID="Value" Automated="1"/> </Parameters> </Node> </Nodes> <Parameters/> <Properties> <Property ID="IsVertical" Value="0"/> </Properties> </Node> </Nodes> <Parameters> <Parameter ID="Threshold" MinValue="-100.0" MaxValue="0.0" StepSize="0.1" SkewFactor="5.422270979580217" Value="0.0"> <Connections> <Connection NodeId="converter" ParameterId="Value"/> </Connections> </Parameter> <Parameter ID="Ratio" MinValue="1.0" MaxValue="32.0" Value="1.0"> <Connections> <Connection NodeId="snex_node" ParameterId="Ratio"/> </Connections> </Parameter> <Parameter ID="Attack" MinValue="0.0" MaxValue="1000.0" StepSize="0.1000000014901161" SkewFactor="0.2313782125711441" Value="13.60000020265579"> <Connections> <Connection NodeId="envelope_follower" ParameterId="Attack"/> </Connections> </Parameter> <Parameter ID="Release" MinValue="0.0" MaxValue="1000.0" StepSize="0.1000000014901161" SkewFactor="0.2313782125711441" Value="28.80000042915344"> <Connections> <Connection NodeId="envelope_follower" ParameterId="Release"/> </Connections> </Parameter> <Parameter ID="KneeWidth" MinValue="0.0" MaxValue="1.0" Value="0.1531573486328126"> <Connections> <Connection NodeId="snex_node" ParameterId="KneeWidth"/> </Connections> </Parameter> </Parameters> </Node> </Network>
I've also updated the SNEX code - I had to convert the output to a gain ratio and add some edge case handlings, but if you save this code as
soft_knee_mod
it should work. -
Oh and BTW: no idea if it sounds good, I did this on my laptop without headphones. The curve looks alright though, but if you increase the knee width it will start acting like a noise gate (I think the knee width has to be relative to the threshold or it will nudge small values to zero real quick).
-
@Christoph-Hart Thank you so much mate, I really appreciate your help!
I know the theory well but don't have a deep C++ know-how as even 1/1000 of you. I woke up and saw your message and I've been on this for 3 hours with tons of tests, first code wasn't working well but your updated code sounds great!
Below is the dynamics test on the PluginDoctor. Like you said the Knee Width depends on the Threshold value (maybe I need to modify it with a pma node to fix the value), but if it is set, you can get awesome curves and tones.
Also even I put all of them into a frame2 block, the compiled network is incredibly fast and cpu effective! I've never seen this kind of thing, congrats Christoph, that is showing that you're a real Genius.
Maybe you can add this to the templates.
-
So Sweet! Thank you so much guys, it sounds GREAT.
-
@Christoph-Hart I've been waiting this for a long time, thank you very much!
-
@Fortune You don't need to split the signal, if ProcessSignal is deactivated, it can all flow just through the default chain container.