HISE Logo Forum
    • Categories
    • Register
    • Login

    C++/SNEX smooth parameter

    Scheduled Pinned Locked Moved C++ Development
    12 Posts 4 Posters 499 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.
    • ustkU
      ustk
      last edited by ustk

      What would be the way to smooth a parameter in C++ node or SNEX?
      Well in SNEX I could probably go with a sfloat or sdouble, but?

      Can't help pressing F5 in the forum...

      griffinboyG orangeO 2 Replies Last reply Reply Quote 0
      • griffinboyG
        griffinboy @ustk
        last edited by

        @ustk

        C++ has sfloat as well.
        But I'm actually finding issues with it when imbedded deep in a sctiptnode network that has oversampling / softbypass nodes.

        I need to do more tests and figure out what's up, but in general sfloat works.

        ustkU 2 Replies Last reply Reply Quote 1
        • ustkU
          ustk @griffinboy
          last edited by

          @griffinboy oh ok! I need this in an oversampling context too, because the more the DSP processing required, the more the crackles...

          Can't help pressing F5 in the forum...

          1 Reply Last reply Reply Quote 0
          • orangeO
            orange @ustk
            last edited by

            @ustk Math.smoothstep maybe?

            develop Branch / XCode 13.1
            macOS Monterey / M1 Max

            ustkU 1 Reply Last reply Reply Quote 0
            • ustkU
              ustk @griffinboy
              last edited by

              @griffinboy What kind of issues? Compile errors?

              Can't help pressing F5 in the forum...

              griffinboyG 1 Reply Last reply Reply Quote 0
              • ustkU
                ustk @orange
                last edited by ustk

                @orange Smooth step is to "de-linearise" a value and make it more "sigmoid like" curve

                Can't help pressing F5 in the forum...

                1 Reply Last reply Reply Quote 0
                • griffinboyG
                  griffinboy @ustk
                  last edited by

                  @ustk

                  No, it just becomes "not smooth" anymore.
                  I need to look into the code for sfloat because maybe I'm just using it wrong, but it works fine in a simpler context.

                  Perhaps do a custom implementation for now, or look at how to use the one in Juce.

                  ustkU 1 Reply Last reply Reply Quote 0
                  • ustkU
                    ustk @griffinboy
                    last edited by

                    @griffinboy I used this a few days ago but I am confused about set

                    The doc says

                    Sets a new target value and resets the ramp position to the beginning.

                    The beginning of what? If the value has not yet reached the target, would that cause a jump?
                    Or the new ramp is always calculated between the current position and the new target?

                    Can't help pressing F5 in the forum...

                    Christoph HartC griffinboyG 2 Replies Last reply Reply Quote 0
                    • Christoph HartC
                      Christoph Hart @ustk
                      last edited by

                      Or the new ramp is always calculated between the current position and the new target

                      Yes this.

                      There‘s no reason why it shouldn‘t work within oversampling but you have to adjust the smoothing rate in the prepare callback.

                      griffinboyG ustkU 2 Replies Last reply Reply Quote 2
                      • griffinboyG
                        griffinboy @Christoph Hart
                        last edited by

                        @Christoph-Hart

                        Bingo that's probably what I missed. I had a teeny tiny smoothing rate.
                        With oversampling that now becomes very short!
                        Thx

                        1 Reply Last reply Reply Quote 0
                        • griffinboyG
                          griffinboy @ustk
                          last edited by

                          @ustk

                          Here is one of my older c++ templates. Take a look at sfloat here:

                          // This is an example template. The functions that appear in this code must not be deleted, many of these are templated and as such are expected by the compiler. Other programs connected to this one supply each of the functions with data. 
                          // When taking this template and adapting it for our unique program we are trying to code, feel free to change the EFFECT class into one that is specific for our effect! That class is not templated and can be changed. 
                          // Block processing is preferred, and using a class like this for it is also good practice. Feel free to remove the gain effect, as that is only there to show you proper usage of the framework. 
                          
                          #pragma once
                          #include <JuceHeader.h>
                          
                          namespace project
                          {
                              using namespace juce;
                              using namespace hise;
                              using namespace scriptnode;
                          
                              template <int NV>
                              // Name 
                              struct ExternalNodeTemplate : public data::base
                              {          // Name
                                  SNEX_NODE(ExternalNodeTemplate);
                          
                                  struct MetadataClass
                                  {            // Name
                                      SN_NODE_ID("ExternalNodeTemplate");
                                  };
                          
                                  // Node properties
                                  static constexpr bool isModNode() { return false; }
                                  static constexpr bool isPolyphonic() { return NV > 1; }
                                  static constexpr bool hasTail() { return false; }
                                  static constexpr bool isSuspendedOnSilence() { return false; }
                                  static constexpr int getFixChannelAmount() { return 2; }
                          
                                  static constexpr int NumTables = 0;
                                  static constexpr int NumSliderPacks = 0;
                                  static constexpr int NumAudioFiles = 0;
                                  static constexpr int NumFilters = 0;
                                  static constexpr int NumDisplayBuffers = 0;
                          
                                  // Prepare: Called on init, and when sample rate changes
                                  void prepare(PrepareSpecs specs) {
                          
                                      float sampleRate = specs.sampleRate;
                                      float numChannels = specs.numChannels;
                          
                                      leftChannelEffect.prepare(sampleRate, 5.0); // 5ms smoothing on the gain parameter
                                      rightChannelEffect.prepare(sampleRate, 5.0);
                                  }
                          
                                  // Reset: Called when the plugin is reloaded
                                  void reset() {}
                          
                                  // Process: Audioblocks enter the script here
                                  template <typename ProcessDataType>
                                  void process(ProcessDataType& data)
                                  {
                                      auto& fixData = data.template as<ProcessData<getFixChannelAmount()>>();
                                      auto audioBlock = fixData.toAudioBlock();
                          
                                      // Get pointers to channel data
                                      auto* leftChannelData = audioBlock.getChannelPointer(0);
                                      auto* rightChannelData = audioBlock.getChannelPointer(1);
                          
                                      float blockSize = data.getNumSamples();
                          
                                      // Send each channel to the appropiate AudioEffect class
                                      leftChannelEffect.process(leftChannelData, blockSize);
                                      rightChannelEffect.process(rightChannelData, blockSize);
                                      // We use blocks rather than frames becuase there are more samples than channels (Better SIMD)
                                  }
                          
                          
                          
                                  // AudioEffect class: Handles audio processing
                                  class AudioEffect
                                  {
                                  public:
                                      // Constructor to initialize gain
                                      AudioEffect(float initialGain = 1.0f)
                                      {
                                          smoothGain.set(initialGain); // Initialize sfloat with initial gain
                                      }
                          
                                      // Prepare the smoothedFloat with sample rate and time
                                      void prepare(double sampleRate, double timeInMilliseconds)
                                      {
                                          smoothGain.prepare(sampleRate, timeInMilliseconds);
                                      }
                          
                                      // Process function: Recieves a block of samples
                                      void process(float* samples, int numSamples)
                                      {
                                          // Iterate over each sample in the block
                                          for (int i = 0; i < numSamples; ++i)
                                          {
                                              samples[i] *= smoothGain.advance(); // Apply the effect using the smoothed parameter
                                          }
                          
                                      }
                          
                                      // Update Gain: Called by setParameter function
                                      void updateGain(float newGain)
                                      {
                                          smoothGain.set(newGain);
                                      }
                          
                                  private:
                                      sfloat smoothGain; // Instance of sfloat for smooth gain
                                  };
                          
                          
                                  template <int P>
                                  void setParameter(double v)
                                  {
                                      if (P == 0)
                                          leftChannelEffect.updateGain(static_cast<float>(v)); // Update gain for left channel
                                      else if (P == 1)
                                          rightChannelEffect.updateGain(static_cast<float>(v)); // Update gain for right channel
                                  }
                          
                          
                                  // Create parameters on the GUI
                                  void createParameters(ParameterDataList& data)
                                  {
                                      {                              //  { min, max,  step }                   < id >
                                          parameter::data p("Left Gain", { 0.1, 2.0,  0.01 }); registerCallback< 0 >(p);
                                          p.setDefaultValue(1.0);
                                          data.add(std::move(p));
                                      }
                                      {
                                          parameter::data p("Right Gain", { 0.1, 2.0,  0.01 }); registerCallback< 1 >(p);
                                          p.setDefaultValue(1.0);
                                          data.add(std::move(p));
                                      }
                                  }
                          
                                  // // Interact with external data (eg. an external buffer)
                                  void setExternalData(const ExternalData& data, int index) {}
                          
                                  // Handle HISE events: Process MIDI or other events
                                  void handleHiseEvent(HiseEvent& e) {}
                          
                                  // Handle external modulation slot ( first enable isModNode() )  
                                  /*
                                      ModValue modValue;
                                      int handleModulation(double& value)
                                      {
                                          return modValue.getChangedValue(value);
                                      }
                                      // setting modValue updates the external modulation
                                      modValue.setModValue(0);
                                  */
                          
                                  // processFrame: Needed for compiler, does nothing
                                  template <typename FrameDataType>
                                  void processFrame(FrameDataType& data) {}
                          
                          
                              private:
                                  // Create instances of AudioEffect for left and right channels
                                  AudioEffect leftChannelEffect;
                                  AudioEffect rightChannelEffect;
                              };
                          }
                          
                          
                          1 Reply Last reply Reply Quote 1
                          • ustkU
                            ustk @Christoph Hart
                            last edited by

                            @Christoph-Hart Yeah I have noticed it was necessary to update the timing as samplerate changes

                            @griffinboy Perfect thanks mate!

                            Can't help pressing F5 in the forum...

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            26

                            Online

                            1.7k

                            Users

                            11.9k

                            Topics

                            103.3k

                            Posts