HISE Logo Forum
    • Categories
    • Register
    • Login

    Tonal Balance

    Scheduled Pinned Locked Moved General Questions
    48 Posts 12 Posters 3.1k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Christoph HartC
      Christoph Hart @Fortune
      last edited by

      @Fortune Well that's a GPL licensed code so you won't be able to use it in a proprietary project.

      FortuneF 1 Reply Last reply Reply Quote 0
      • FortuneF
        Fortune @Christoph Hart
        last edited by Fortune

        @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):
        Screen Shot 2022-08-10 at 08.38.21.png

        But the soft knee equation is that:

        Screen Shot 2022-08-10 at 08.38.49.png

        Soft knee sounds musical and more natural, where hard knee sounds digital and pretty bad on most of the professional mix cases.

        alt text

        Christoph HartC 1 Reply Last reply Reply Quote 0
        • Christoph HartC
          Christoph Hart @Fortune
          last edited by Christoph Hart

          @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.

          1 Reply Last reply Reply Quote 5
          • Christoph HartC
            Christoph Hart
            last edited by

            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.

            Christoph HartC 1 Reply Last reply Reply Quote 3
            • Christoph HartC
              Christoph Hart @Christoph Hart
              last edited by

              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).

              FortuneF ? ? 3 Replies Last reply Reply Quote 1
              • FortuneF
                Fortune @Christoph Hart
                last edited by Fortune

                @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.

                CMPPPPP.gif

                1 Reply Last reply Reply Quote 3
                • ?
                  A Former User @Christoph Hart
                  last edited by

                  @Christoph-Hart @Fortune

                  So Sweet! Thank you so much guys, it sounds GREAT.

                  1 Reply Last reply Reply Quote 0
                  • ?
                    A Former User @Christoph Hart
                    last edited by

                    @Christoph-Hart I've been waiting this for a long time, thank you very much!

                    1 Reply Last reply Reply Quote 0
                    • Christoph HartC
                      Christoph Hart
                      last edited by

                      @Fortune You don't need to split the signal, if ProcessSignal is deactivated, it can all flow just through the default chain container.

                      FortuneF 1 Reply Last reply Reply Quote 1
                      • FortuneF
                        Fortune @Christoph Hart
                        last edited by Fortune

                        @Christoph-Hart The ProcessSignal of the Envelope follower, right? Ok Thank you it is good to know that.

                        One last thing, is it possible to display the gain reduction amount (in dB) with a knob?

                        I would follow this guide but don't know how to get the External Buffer from SNEX: https://forum.hise.audio/topic/6324/scriptnode-compressor-gain-reduction/2

                        Christoph HartC 1 Reply Last reply Reply Quote 0
                        • Christoph HartC
                          Christoph Hart @Fortune
                          last edited by

                          @Fortune just send the mod output of the snex node to an add node in a modchain, put a peak node behind it and use that instead.

                          FortuneF 1 Reply Last reply Reply Quote 1
                          • FortuneF
                            Fortune @Christoph Hart
                            last edited by

                            @Christoph-Hart I will do that, Thank you!

                            Christoph HartC 1 Reply Last reply Reply Quote 0
                            • Christoph HartC
                              Christoph Hart @Fortune
                              last edited by

                              Oh and if you want to make the knee width relative to the threshold, don't use a pma node, but just this line in the beginning of the handleModulation() method:

                              const double Wt = W * T * 2.0;
                              

                              And then use this value in the handleModulation method instead of W. The 2.0 makes the knee a bit more noticeable but you can play around with values.

                              FortuneF orangeO pluginboiP 3 Replies Last reply Reply Quote 2
                              • FortuneF
                                Fortune @Christoph Hart
                                last edited by Fortune

                                @Christoph-Hart

                                Yesss, that's it!!! Knee Width can be adjustable sensitively, both hard and soft knee settings are available in one compressor 😍

                                Thank you so much for your help mate!

                                By the way, I set the Release time of the envelope 10000 ms, it has a very smooth sound now :)

                                NOTE: Yellow flicking vertical slider is the reduction meter.

                                Kneeee.gif !

                                1 Reply Last reply Reply Quote 1
                                • orangeO
                                  orange @Christoph Hart
                                  last edited by

                                  @Christoph-Hart @Fortune It's super useful, now the compressor sounds much better. Thank you!

                                  develop Branch / XCode 13.1
                                  macOS Monterey / M1 Max

                                  1 Reply Last reply Reply Quote 0
                                  • pluginboiP
                                    pluginboi @Christoph Hart
                                    last edited by

                                    This post is deleted!
                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post

                                    45

                                    Online

                                    1.7k

                                    Users

                                    11.7k

                                    Topics

                                    101.8k

                                    Posts