HISE Logo Forum
    • Categories
    • Register
    • Login
    1. HISE
    2. Consint
    3. Posts
    C
    • Profile
    • Following 0
    • Followers 0
    • Topics 7
    • Posts 55
    • Groups 0

    Posts

    Recent Best Controversial
    • RE: Best Practice for Getting RMS/Peak on an audio buffer

      @griffinboy That's fantastic, thank you very much!

      posted in General Questions
      C
      Consint
    • RE: Best Practice for Getting RMS/Peak on an audio buffer

      @griffinboy That would be amazing!

      posted in General Questions
      C
      Consint
    • RE: Best Practice for Getting RMS/Peak on an audio buffer

      @griffinboy Many thanks also for this node. Unfortunately, I get this error message when compiling and don't know what to do with it:

      ../../Source/../../ThirdParty/Griffin_Rms.h:75:70: error: expected primary-expression before ‘>’ token
         75 |          auto& fixData = data.as<ProcessData<getFixChannelAmount()>>();
      

      Do you (or anyone else) have any idea why this might be?

      posted in General Questions
      C
      Consint
    • RE: Is there a guide for the SVG to path converter?

      @d-healey They are now in the docs: https://docs.hise.audio/scripting/scripting-api/scriptpanel/index.html#setmousecursor

      posted in Scripting
      C
      Consint
    • RE: Retro 80s Tape Wow & Flutter with faust

      @griffinboy Many thanks for the JG Tape Model node. Have you been able to build a more stable version in the meantime that you would like to share with us?

      posted in Presets / Scripts / Ideas
      C
      Consint
    • RE: FFT Analyser Path - Need help drawing the magnitude to height

      @HISEnberg I couldn't make a better example snippet than @ustk has already done above. Maybe you can post your code and we can see if we can get it to work.

      posted in Scripting
      C
      Consint
    • RE: FFT Analyser Path - Need help drawing the magnitude to height

      @HISEnberg I tried it and it fixed the problem. It doesn't seem to have caused any other problems either. I did exactly as @ustk suggested and simply moved the path creation to a background task.

      posted in Scripting
      C
      Consint
    • RE: FFT Analyser Path - Need help drawing the magnitude to height

      @HISEnberg @oskarsh Has handling the FFT path in a background task solved the problem for you? A user described exactly the same problem to me with one of my plugins and I can't reproduce it. In Studio One on Windows 11, the plugin has so much lag that it is unusable for him and sometimes even crashes, whereas in Mixcraft it runs without any problems. I then installed Studio One in a Windows 10 VM for testing and the plugin runs without any problems.

      posted in Scripting
      C
      Consint
    • RE: The big bug tier list

      @Christoph-Hart Two tick marks in a combobox popup. This has already been mentioned here somewhere. A screenshot and a snippet are in the GitHub issue.

      Link Preview Image
      Two tick marks in combobox popup · Issue #739 · christophhart/HISE

      In a combobox with custom popup there are always two tick marks. One for the main item with the most submenus and one for the actually selected menu item. Snippet: HiseSnippet 778.3ocsUkzaZCDEdFBNp3tnDodnmp3RkRphpv.g.zCkxVKpkDTIMp2hFFONd...

      favicon

      GitHub (github.com)

      posted in Bug Reports
      C
      Consint
    • RE: How to turn an Airwindows effect into a Scriptnode

      @Morphoice I tried it with my plugin and was able to compile it in my Windows 10 VM with Visual Studio 2022 without any problems.

      posted in General Questions
      C
      Consint
    • RE: How to turn an Airwindows effect into a Scriptnode

      @Morphoice I have only compiled it on Linux so far.

      posted in General Questions
      C
      Consint
    • RE: How to turn an Airwindows effect into a Scriptnode

      @Christoph-Hart Oh, great, I didn't know that existed.

      posted in General Questions
      C
      Consint
    • RE: How to turn an Airwindows effect into a Scriptnode

      @Morphoice I found the solution some time ago in the code of a plugin from @oskarsh. You have to copy the .cpp and .h files of the plugin from Airwindows into the folder .../DspNetworks/ThirdParty/src (actually any path works but as far as I know this is the one Hise intended). Using Tube2 as an example, this is Tube2.cpp, Tube2.h and Tube2Proc.cpp.

      In the same directory you must also place the file AirWindows.h:

      #pragma once
      
      #include <math.h>
      #include <set>
      #include <string>
      
      #include <JuceHeader.h>
      
      #define __audioeffect__
      #define VstInt32             int32_t
      #define AudioEffect          ::airwindows::AirWindowsBase
      #define AudioEffectX         ::airwindows::AirWindowsBase
      #define audioMasterCallback  ::airwindows::SampleRateCallback*
      #define VstPlugCategory      int
      #define kPlugCategEffect     1
      #define kVstMaxProgNameLen   64
      #define kVstMaxParamStrLen   64
      #define kVstMaxProductStrLen 64
      #define kVstMaxVendorStrLen  64
      #define vst_strncpy          strncpy
      
      namespace airwindows {
      inline auto float2string(float f, char* text, int len) -> void
      {
          int decimals = 0;
          if (std::fabs(f) >= 10.0) {
              decimals = 1;
          } else if (std::fabs(f) > 1.0) {
              decimals = 2;
          } else {
              decimals = 3;
          }
      
          juce::String str(f, decimals);
          str.copyToUTF8(text, (size_t)len);
      }
      
      inline auto int2string(float i, char* text, int len) -> void
      {
          juce::String str(i);
          str.copyToUTF8(text, (size_t)len);
      }
      
      inline auto dB2string(float value, char* text, int maxLen) -> void
      {
          if (value <= 0) {
              vst_strncpy(text, "-oo", (size_t)maxLen);
          } else {
              float2string((float)(20. * log10(value)), text, maxLen);
          }
      }
      
      struct SampleRateCallback
      {
          SampleRateCallback() = default;
      
          auto getSampleRate() const noexcept -> double { return sampleRate; }
      
          double sampleRate{0.0};
      };
      
      class AirWindowsBase
      {
      public:
          AirWindowsBase(SampleRateCallback* c, int prog, int param)
              : numPrograms(prog)
              , numParams(param)
              , callback(c)
          {}
      
          int getNumInputs() { return numInputs; }
      
          int getNumOutputs() { return numOutputs; }
      
          int getNumParameters() { return numParams; }
      
          virtual bool getEffectName(char* name)                                                        = 0;
          virtual VstPlugCategory getPlugCategory()                                                     = 0;
          virtual bool getProductString(char* text)                                                     = 0;
          virtual bool getVendorString(char* text)                                                      = 0;
          virtual VstInt32 getVendorVersion()                                                           = 0;
          virtual void processReplacing(float** inputs, float** outputs, VstInt32 sampleFrames)         = 0;
          virtual void processDoubleReplacing(double** inputs, double** outputs, VstInt32 sampleFrames) = 0;
          virtual void getProgramName(char* name)                                                       = 0;
          virtual void setProgramName(char* name)                                                       = 0;
      
          virtual VstInt32 getChunk(void** data, bool isPreset)
          {
              juce::ignoreUnused(data, isPreset);
              return 0;
          };
      
          virtual VstInt32 setChunk(void* data, VstInt32 byteSize, bool isPreset)
          {
              juce::ignoreUnused(data, byteSize, isPreset);
              return 0;
          };
      
          virtual float getParameter(VstInt32 index)
          {
              juce::ignoreUnused(index);
              return 0;
          }
      
          virtual void setParameter(VstInt32 index, float value) { juce::ignoreUnused(index, value); }
      
          virtual void getParameterLabel(VstInt32 index, char* text) { juce::ignoreUnused(index, text); }
      
          virtual void getParameterName(VstInt32 index, char* text) { juce::ignoreUnused(index, text); }
      
          virtual void getParameterDisplay(VstInt32 index, char* text) { juce::ignoreUnused(index, text); }
      
          virtual VstInt32 canDo(char* text) = 0;
      
      protected:
          void setNumInputs(int numIn) { numInputs = numIn; }
      
          void setNumOutputs(int numOut) { numOutputs = numOut; }
      
          void setUniqueID(int) {}
      
          void canProcessReplacing() {}
      
          void canDoubleReplacing() {}
      
          void programsAreChunks(bool) {}
      
          int numInputs = 0, numOutputs = 0, numPrograms = 0, numParams = 0;
      
          SampleRateCallback* callback;
      
          double getSampleRate() { return callback->getSampleRate(); }
      };
      
      }  // namespace airwindows
      
      #define DECLARE_AIRWINDOWS_NODE(ClassName, Namespace)                                                \
          template<int NV>                                                                                 \
          struct ClassName final : public data::base                                                       \
          {                                                                                                \
              SNEX_NODE(ClassName);                                                                        \
              struct MetadataClass                                                                         \
              {                                                                                            \
                  SN_NODE_ID(#ClassName);                                                                  \
              };                                                                                           \
                                                                                                           \
              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;                                                  \
              void prepare(PrepareSpecs specs)                                                             \
              {                                                                                            \
                  _sampleRateSource.sampleRate = specs.sampleRate;                                         \
                  _tmp.setSize(specs.numChannels, specs.blockSize);                                        \
              }                                                                                            \
              void reset() {}                                                                              \
              void handleHiseEvent(HiseEvent& e) {}                                                        \
              template<typename T>                                                                         \
              void process(T& data)                                                                        \
              {                                                                                            \
                  auto buffer = juce::AudioBuffer<float>(                                                  \
                      data.getRawChannelPointers(),                                                        \
                      data.getNumChannels(),                                                               \
                      data.getNumSamples()                                                                 \
                  );                                                                                       \
                  processInternal(buffer);                                                                 \
              }                                                                                            \
              template<typename T>                                                                         \
              void processFrame(T& data)                                                                   \
              {                                                                                            \
                  auto** ptr = (float**)alloca(data.size() * sizeof(float*));                              \
                  for (int i = 0; i < data.size(); i++) {                                                  \
                      ptr[i] = data.begin() + i;                                                           \
                  }                                                                                        \
                  auto buffer = juce::AudioBuffer<float>(ptr, data.size(), 1);                             \
                  processInternal(buffer);                                                                 \
              }                                                                                            \
              auto processInternal(juce::AudioBuffer<float>& buffer) -> void                               \
              {                                                                                            \
                  _tmp.makeCopyOf(buffer);                                                                 \
                  _engine.processReplacing(                                                                \
                      _tmp.getArrayOfWritePointers(),                                                      \
                      buffer.getArrayOfWritePointers(),                                                    \
                      buffer.getNumSamples()                                                               \
                  );                                                                                       \
              }                                                                                            \
              int handleModulation(double& value) { return 0; }                                            \
              void setExternalData(ExternalData const& data, int index) {}                                 \
              template<int P>                                                                              \
              void setParameter(double v)                                                                  \
              {                                                                                            \
                  _engine.setParameter(P, static_cast<float>(v));                                          \
              }                                                                                            \
              void createParameters(ParameterDataList& data)                                               \
              {                                                                                            \
                  for (auto i{0}; i < airwindows::Namespace::kNumParameters; ++i) {                        \
                      char name[kVstMaxParamStrLen]{};                                                     \
                      _engine.getParameterName(i, name);                                                   \
                      auto parameter = parameter::data(name, {0.0, 1.0});                                  \
                      registerCallback(parameter, i);                                                      \
                      parameter.setDefaultValue(_engine.getParameter(i));                                  \
                      data.add(std::move(parameter));                                                      \
                  }                                                                                        \
              }                                                                                            \
                                                                                                           \
          private:                                                                                         \
              template<typename Param>                                                                     \
              auto registerCallback(Param& parameter, int i) -> void                                       \
              {                                                                                            \
                  switch (i) {                                                                             \
                      case 0: registerCallback<0>(parameter); break;                                       \
                      case 1: registerCallback<1>(parameter); break;                                       \
                      case 2: registerCallback<2>(parameter); break;                                       \
                      case 3: registerCallback<3>(parameter); break;                                       \
                      case 4: registerCallback<4>(parameter); break;                                       \
                      case 5: registerCallback<5>(parameter); break;                                       \
                      case 6: registerCallback<6>(parameter); break;                                       \
                      case 7: registerCallback<7>(parameter); break;                                       \
                      case 8: registerCallback<8>(parameter); break;                                       \
                      case 9: registerCallback<9>(parameter); break;                                       \
                      case 10: registerCallback<10>(parameter); break;                                     \
                      case 11: registerCallback<11>(parameter); break;                                     \
                      case 12: registerCallback<12>(parameter); break;                                     \
                      case 13: registerCallback<13>(parameter); break;                                     \
                      case 14: registerCallback<14>(parameter); break;                                     \
                      case 15: registerCallback<15>(parameter); break;                                     \
                      case 16: registerCallback<16>(parameter); break;                                     \
                      case 17: registerCallback<17>(parameter); break;                                     \
                      case 18: registerCallback<18>(parameter); break;                                     \
                      case 19: registerCallback<19>(parameter); break;                                     \
                      case 20: registerCallback<20>(parameter); break;                                     \
                      case 21: registerCallback<21>(parameter); break;                                     \
                      case 22: registerCallback<22>(parameter); break;                                     \
                      case 23: registerCallback<23>(parameter); break;                                     \
                      case 24: registerCallback<24>(parameter); break;                                     \
                      default: break;                                                                      \
                  }                                                                                        \
                  jassert(false);                                                                          \
              }                                                                                            \
              airwindows::SampleRateCallback _sampleRateSource{};                                          \
              airwindows::Namespace::ClassName _engine{&_sampleRateSource};                                \
              juce::AudioBuffer<float> _tmp;                                                               \
          }
      

      You must then save the file Tube2.h in the directory .../DspNetworks/ThirdParty. In this file you have to set the paths to the files in the src folder and define the name, in this case Tube2, in several places. This is also the only file you need to edit if you want to include another Airwindows plugin:

      
      #pragma once
      
      #include <JuceHeader.h>
      
      #include "src/AirWindows.h"
      
      namespace airwindows::tube2_ns {
      JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wmultichar")
      #include "src/Tube2.h"
      
      #include "src/Tube2.cpp"
      #include "src/Tube2Proc.cpp"
      JUCE_END_IGNORE_WARNINGS_GCC_LIKE
      }  // namespace airwindows::tube2_ns
      
      namespace project {
      
      using namespace juce;
      using namespace hise;
      using namespace scriptnode;
      
      DECLARE_AIRWINDOWS_NODE(Tube2, tube2_ns);
      
      }  // namespace project
      

      And that's it. Then start Hise and press Compile DSP networks as DLL. This has worked for me for several (rather simple) Airwindows plugins.

      posted in General Questions
      C
      Consint
    • RE: The big bug tier list

      @Christoph-Hart Shape FX shows no graph except for 'Curve':

      Link Preview Image
      Shape FX shows no graph except for 'Curve' · Issue #712 · christophhart/HISE

      Except for the ‘Curve’ algorithm, the Shape FX module does not display a graph of the waveshaping function.

      favicon

      GitHub (github.com)

      posted in Bug Reports
      C
      Consint
    • RE: ComboBox Challenge. Oblivious Checkmark.

      @CyberGen I have the same problem on Linux.

      posted in Scripting
      C
      Consint
    • RE: Crash when compiling dsp to dll

      @HISEnberg @ulrik Yes, but please be aware that I am only a amateur. I hope that people who are really familiar with it will intervene here if I have described something incorrectly or badly.

      SNEX nodes and C++ nodes look very similar and work almost the same. If you create a C++ template under ‘Tools -> Create C++ third party node template’ and view the C++ file in an editor, you will see that the basic functions correspond to those of the SNEX node. I have essentially just copied the code from the SNEX node into the respective functions of the C++ node.

      When doing this, you must pay attention to the following:

      • The variables declared in the function header must be named as they are used (for example, sometimes data and sometimes just d)
      • The conversion of the data to FrameData in the process function must happen as it is already in the C++ template (I don't know why).

      Specific C++ node specifications must then be made. In the ‘Metadata Definitions’ at the top, static constexpr int NumAudioFiles = 1 must be set, as we want to play an audio file. In addition, the ‘Play’ knob must be created in the createParameters function at the bottom.

      Once all this is done, the node can be compiled via ‘Export -> Compile DSP networks as dll’. After restarting Hise, the SNEX node in ‘Script FX1’ can be replaced by the C++ node. The entire Scriptnode can then be compiled.

      Here is my C++ Node version of the SNEX simple_player:

      // ==================================| Third Party Node Template |==================================
      
      #pragma once
      #include <JuceHeader.h>
      
      namespace project
      {
      using namespace juce;
      using namespace hise;
      using namespace scriptnode;
      
      // ==========================| The node class with all required callbacks |==========================
      
      template <int NV> struct s_player: public data::base
      {
      	// Metadata Definitions ------------------------------------------------------------------------
      	
      	SNEX_NODE(s_player);
      	
      	struct MetadataClass
      	{
      		SN_NODE_ID("s_player");
      	};
      	
      	// set to true if you want this node to have a modulation dragger
      	static constexpr bool isModNode() { return false; };
      	static constexpr bool isPolyphonic() { return NV > 1; };
      	// set to true if your node produces a tail
      	static constexpr bool hasTail() { return false; };
      	// set to true if your doesn't generate sound from silence and can be suspended when the input signal is silent
      	static constexpr bool isSuspendedOnSilence() { return false; };
      	// Undefine this method if you want a dynamic channel count
      	static constexpr int getFixChannelAmount() { return 2; };
      	
      	// Define the amount and types of external data slots you want to use
      	static constexpr int NumTables = 0;
      	static constexpr int NumSliderPacks = 0;
      	static constexpr int NumAudioFiles = 1;
      	static constexpr int NumFilters = 0;
      	static constexpr int NumDisplayBuffers = 0;
      	
      	// Global Variables -------------------------------------------------------------------------
      	span<float, 8> dummy = { 0.0f };
      	
      	ExternalData ed;
      		
      	// this is an array of two dynamic float buffers that will 
      	// hold the recorded data
      	span<dyn<float>, 2> stereoData;
      	
      	int currentIndex = 0;
      	int isPlaying = 0;
      
      	// Scriptnode Callbacks ------------------------------------------------------------------------
      	void prepare(PrepareSpecs specs){}
      	
      	void reset(){}
      	
      	void handleHiseEvent(HiseEvent& e){}
      	
      	template <typename T> void processFrame(T& data)
      	{
      		// No interpolation necessary, just copy the
      		// recorded buffer
      		data[0] = stereoData[0][currentIndex];
      		data[1] = stereoData[1][currentIndex];
      
      		currentIndex++;
      							
      		if(currentIndex >= ed.numSamples)
      			currentIndex = 0;
      	}
      
      	template <typename T> void process(T& data)
      	{
      		// We need to make sure that the audio render thread
      		// isn't processing this function while the external data slot 
      		// is modified, so we use a DataReadLock with a try read access
      		DataReadLock sl(ed, true);
      		
      		// check if the data lock was grabbed successfully, the playback
      		// is enabled and the data slot is not empty
      		if(sl.isLocked() && isPlaying && ed.numSamples > 0)
      		{
      			static constexpr int NumChannels = getFixChannelAmount();
      			// Cast the dynamic channel data to a fixed channel amount
      			auto& fixData = data.template as<ProcessData<NumChannels>>();
      			
      			auto fd = fixData.toFrameData();
      										
      			while(fd.next())
      				processFrame(fd.toSpan());
      				
      			// set the display position
      			ed.setDisplayedValue((double)currentIndex);
      		}
      	}
      	
      	int handleModulation(double& value)
      	{
      		return 0;
      	}
      	
      	void setExternalData(const ExternalData& d, int index)
      	{
      		ed = d;
      		
      		if(ed.numSamples > 0)
      		{
      			// refer the stereo data object to the audio buffer
      			ed.referBlockTo(stereoData[0], 0);		
      			ed.referBlockTo(stereoData[1], Math.min(d.numChannels-1, 1));
      		}
      		else
      		{
      			// route it to a dummy buffer if the slot is empty
      			// (that's not required but otherwise the stereo data
      			//  might point to a dangling buffer)
      			stereoData[0].referTo(dummy, 8, 0);
      			stereoData[1].referTo(dummy, 8, 0);
      		}
      	}
      
      	// Parameter Functions -------------------------------------------------------------------------
      	template <int P> void setParameter(double v)
      	{
      		auto shouldBePlaying = v > 0.5;
      		
      		if(isPlaying != shouldBePlaying)
      		{
      			isPlaying = shouldBePlaying;
      			currentIndex = 0;
      		}
      	}
      	
      	void createParameters(ParameterDataList& data)
      	{
      		{
      			// Create a parameter like this
      			parameter::data p("Play", { 0.0, 1.0});
      			// The template parameter (<0>) will be forwarded to setParameter<P>()
      			registerCallback<0>(p);
      			p.setDefaultValue(0);
      			data.add(std::move(p));
      		}
      	}
      };
      }
      
      posted in ScriptNode
      C
      Consint
    • RE: Crash when compiling dsp to dll

      @ulrik I got it to run by transferring my snex code into a third party c++ node.

      posted in ScriptNode
      C
      Consint
    • RE: Crash when compiling dsp to dll

      @ulrik Have you found a solution for this? I am currently getting the same error.

      posted in ScriptNode
      C
      Consint
    • CustomSampleImport without sampler or loop player with x-fades

      The CustomSampleImport example shows how you can enable the user to import their own samples into a sampler. To do this, a samplemap is created using the JSON samplemap functions and then loaded into a sampler. This is exactly what I need for an FX plugin in which there must not be a sampler. I want the user to be able to import their own samples which can then be played in scriptnode by a file_player. A samplemap is necessary because x-fades are also required. So my question is whether a sample import using a samplemap is also possible without a sampler?

      A possible alternative would be to create a loop player with x-fades in scriptnode. Has anyone ever done this and can give me a few tips?

      posted in Scripting
      C
      Consint
    • RE: Bug in Juce 6.1.3 (used by Hise) that sometimes prevents the plugin from loading under Linux

      @d-healey That's great, thank you.

      posted in Bug Reports
      C
      Consint