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

    Consint

    @Consint

    16
    Reputation
    6
    Profile views
    47
    Posts
    0
    Followers
    0
    Following
    Joined
    Last Online

    Consint Unfollow Follow

    Best posts made by 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: Different OS Cursors?

      @mmprod A few days ago I made a pull request to update the documentation.:

      Instead of pathIcon, one of the following standard cursors can also be used as a string:

      Property Description
      NoCursor An invisible cursor.
      NormalCursor The standard arrow cursor.
      WaitCursor The normal hourglass or spinning-beachball 'busy' cursor.
      IBeamCursor A vertical I-beam for positioning within text.
      CrosshairCursor A pair of crosshairs.
      CopyingCursor The normal arrow cursor, but with a "+" on it.
      PointingHandCursor A hand with a pointing finger, for clicking on web-links.
      DraggingHandCursor An open flat hand for dragging heavy objects around.
      LeftRightResizeCursor An arrow pointing left and right.
      UpDownResizeCursor An arrow pointing up and down.
      UpDownLeftRightResizeCursor An arrow pointing up, down, left and right.
      TopEdgeResizeCursor A platform-specific cursor for resizing the top-edge of a window.
      BottomEdgeResizeCursor A platform-specific cursor for resizing the bottom-edge of a window.
      LeftEdgeResizeCursor A platform-specific cursor for resizing the left-edge of a window.
      RightEdgeResizeCursor A platform-specific cursor for resizing the right-edge of a window.
      TopLeftCornerResizeCursor A platform-specific cursor for resizing the top-left-corner of a window.
      TopRightCornerResizeCursor A platform-specific cursor for resizing the top-right-corner of a window.
      BottomLeftCornerResizeCursor A platform-specific cursor for resizing the bottom-left-corner of a window.
      BottomRightCornerResizeCursor A platform-specific cursor for resizing the bottom-right-corner of a window.
      // Changes the mouse pointer over the ScriptPanel1 to a hand with a pointing finger
      ScriptPanel1.setMouseCursor("PointingHandCursor", Colours.white, [0, 0]);
      
      posted in General Questions
      C
      Consint
    • RE: HISE Filter Display Inconsistencies

      I also wanted to draw attention to this problem, except that I don't have such good proof, only my auditory impression. The resonance of the SVF LP, despite a Q of 0, is clearly audible. And just like the ladder filter, the Moog filter also makes the signal significantly louder overall.

      I also noticed that the SVF BP and Notch Filter display in Scriptnode is broken.

      (Is the forum actually the right place for bug reports?)

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

      I recently released my first plugin (nothing special, the code is not the best) and on a user's Linux the plugin could not be opened with the following error message:

      X Error of failed request: BadWindow (invalid Window parameter)
      Major opcode of failed request: 20 (X_GetProperty)
      Resource id in failed request: 0x0
      Serial number of failed request: 54
      Current serial number in output stream: 54
      Scan Failed.
      

      While researching, I came across this known bug in Juce 6.3.1 which, if I understand correctly, is the Juce version that Hise uses. So I manually imported the patch into the Juce code that comes with Hise and recompiled Hise and my plugin. And indeed, this fixed the error and the plugin could be loaded.

      Perhaps this is also of interest to someone here. It would be amazing if @Christoph-Hart could import the patch directly into the Hise version of Juce.

      posted in Bug Reports
      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
    • RE: Can't compile plugin after update(v4)

      @d-healey Ok, I have found out. There are two compilerSettings.xml files on my computer. One in .config/HISE which is the wrong one and one in my home folder in .hise (the right one). Thanks for the help!

      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: 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

    Latest posts made by 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