Forum
    • Categories
    • Register
    • Login
    1. Home
    2. Orvillain
    • Profile
    • Following 1
    • Followers 0
    • Topics 91
    • Posts 687
    • Groups 0

    Orvillain

    @Orvillain

    169
    Reputation
    86
    Profile views
    687
    Posts
    0
    Followers
    1
    Following
    Joined
    Last Online

    Orvillain Unfollow Follow

    Best posts made by Orvillain

    • I wrote a reverb

      Don't know if this is the done thing really, but I wanted to show off:
      https://youtu.be/1kMHloRQLcM

      posted in C++ Development
      OrvillainO
      Orvillain
    • I wrote a bbd delay

      Again, wasn't sure where to put this. But I created my own node.

      https://youtu.be/-siB1UJfrD0

      Modelled analog bucket brigade delay. I'm starting to build up quite a nice collection of delay and reverb utilities now!

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: I wrote a reverb

      @Chazrox I might do a video or two on everything I've learned!

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Need filmstrip animations

      @d-healey I really like that UI. Very simple, accessible, and smooth looking - for lack of a better word!

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Transient detection within a loaded sampler - SNEX ????

      @HISEnberg
      Yes I wrote a custom transient detector in a c++ node, and made sure it utilised an audio file, which I can load in my UI using the audio waveform floating tile.

      I implemented spectral flux extraction:

      • Take your audio.
      • Perform an FFT on it.
      • Extract the spectral flux envelope from the FFT.
      • Downsample the spectral flux envelope (optional but can help accuracy)
      • Perform peak picking on the spectral flux envelope.

      I used the stock JUCE FFT processor.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Can We PLEASE Just Get This Feature DONE

      Free mankini with every commercial license???

      posted in Feature Requests
      OrvillainO
      Orvillain
    • RE: I wrote a reverb

      @Chazrox said in I wrote a reverb:

      @Orvillain Please. 🙏 I've been waiting for some dsp videos! I've been watching ADC's everyday on baby topics just to familiarize myself with the lingo and what nots. I think im ready to start diving in! There are some pretty wicked dsp guys in here for sure and I'd love to get some tutuorials for writing c++ nodes.

      There's two guys who got me started in this. One is a dude called Geraint Luff aka SignalSmith. This is probably his most accessible video:
      https://youtu.be/6ZK2Goiyotk

      Then the other guy of course is Sean Costello of ValhallaDSP fame:
      https://valhalladsp.com/2021/09/22/getting-started-with-reverb-design-part-2-the-foundations/
      https://valhalladsp.com/2021/09/23/getting-started-with-reverb-design-part-3-online-resources/

      In essence, here's the journey; assuming you know at least a little bit of C++

      1. Learn how to create a ring buffer (aka my Ring Delay thread)
      2. Learn how to create an all-pass filter using a ring buffer.
      3. Understand how fractional delays work, and the various types of interpolation.
      4. Learn how to manage feedback loops.

      Loads of resources out there for sure!

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Orv's ScriptNode+SNEX Journey

      Lesson 5 - SNEX code in a bit more detail.

      So I'm by no means an expert in C or C++ - in fact I only just recently started learning it. But here's what I've sussed out in regards to the HISE template.... and template is exactly the right word, because the first line is:

      template <int NV> struct audio_loader
      

      Somewhere under the hood, HISE must be setup to send in an integer into any SNEX node, that integer corresponding to a voice. NV = new voice perhaps, or number of voices ????

      The line above declares a template that takes this NV integer in, and creates a struct called audio_loader for each instance of NV. Indeed we can prove this by running the following code:

      template <int NV> struct audio_loader
      {
      	SNEX_NODE(audio_loader);
      	
      	ExternalData data;
      	double note = 0.0;
      	
      	// Initialise the processing specs here
      	void prepare(PrepareSpecs ps)
      	{
      
      	}
      	
      	// Reset the processing pipeline here
      	void reset()
      	{
      		
      	}
      	
      	// Process the signal here
      	template <typename ProcessDataType> void process(ProcessDataType& data)
      	{
      
      	}
      	
      	// Process the signal as frame here
      	template <int C> void processFrame(span<float, C>& data)
      	{
      
      	}
      	
      	// Process the MIDI events here
      	void handleHiseEvent(HiseEvent& e)
      	{
      		double note = e.getNoteNumber();
      		Console.print(note);
      
      	}
      	
      	// Use this function to setup the external data
      	void setExternalData(const ExternalData& d, int index)
      	{
      		data = d;
      	}
      	
      	// Set the parameters here
      	template <int P> void setParameter(double v)
      	{
      		
      	}
      };
      
      

      There are only three things happening here:

      1. We set the ExternalData as in a previous post.
      2. We establish a variable with the datatype of double called 'note' and we initialise it as 0.0. But this value will never hold because....
      3. In the handleHiseEvent() method, we use e.getNoteNumber() and we assign this to the note variable. We then print the note variable out inside of the handleHiseEvent() method.

      Now when we run this script, any time we play a midi note, the console will show us the note number that we pressed. This is even true if you play chords, or in a scenario where no note off events occur.

      That's a long winded way of saying that a SNEX node is run for each active voice; at least when it is within a ScriptNode Synthesiser dsp network.

      The next line in the script after the template is established is:

      SNEX_NODE(audio_loader);
      

      This is pretty straight forward. The text you pass here has to match the name of the script loaded inside your SNEX node - not the name of the SNEX node itself.

      2aa2dbe0-4ea2-40b8-8a45-49d96ada26ec-image.png

      Here you can see my SNEX node is just called: snex_node.

      But the script loaded into it is called audio_loader, and so the reference to SNEX_NODE inside the script has to also reference audio_loader.

      posted in ScriptNode
      OrvillainO
      Orvillain
    • RE: scriptAudioWaveForm and updating contents

      @d-healey said in scriptAudioWaveForm and updating contents:

      @Orvillain Did you try, AudioWaveform.set("processorId", value); ?

      Yeah I did, and it does update it based on a follow up AudioWaveform.get('processorId') call - but the UI component doesn't seem to update, and still shows data from the previous processorId. When I compile the script, then the UI updates one time... but not on subsequent calls to the set method.

      I figured I needed to call some kind of update() function after setting the processorId, but no such luck so far.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: CSS in production plugins?

      Hmmmm I started using it for the modulation matrix controller, but there were things I wanted to do that I couldn't, so I wrote my own script panel matrix controller using LAF instead.

      LAF is - I guess - a subset of the JUCE graphics API, so I'm more comfortable with LAF. CSS hasn't really fully clicked for me yet, if I'm honest. I've never needed it for anything else I've ever done, because none of it was web based and it was all Python, c++, JUCE, Lua, and C#.

      posted in General Questions
      OrvillainO
      Orvillain

    Latest posts made by Orvillain

    • RE: Wavetable creation

      @DanSound You should set the root note of your file to the same root note played when sampling the source. That will cure your transpose issue.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Is there a way to pickup host transport messages directly within a custom node??
      #pragma once
      #include <JuceHeader.h>
      
      namespace project
      {
      using namespace juce;
      using namespace hise;
      using namespace scriptnode;
      using namespace snex;
      
      /**
          Smallest possible BPM listener example.
          Demonstrates:
          - TempoListener registration
          - tempoChanged() callback
          - BPM flowing into the audio graph
      */
      struct MinimalBPMListener : public data::base,
                                  public hise::TempoListener
      {
          SNEX_NODE(MinimalBPMListener);
          struct MetadataClass { SN_NODE_ID("MinimalBPMListener"); };
      
          static constexpr bool isModNode()            { return true;  }
          static constexpr bool isPolyphonic()         { return false; }
          static constexpr bool hasTail()              { return false; }
          static constexpr bool isSuspendedOnSilence() { return false; }
          static constexpr int  getFixChannelAmount()  { return 1; }
      
          // --- Tempo sync ---
          hise::DllBoundaryTempoSyncer* tempoSyncer = nullptr;
          double bpm = 120.0;
      
          // Exposed modulation value
          double lastOut = 120.0;
      
          // --- TempoListener ---
          void tempoChanged(double newTempo) override
          {
              bpm = newTempo;
              lastOut = bpm; // make it observable
          }
      
          // --- Lifecycle ---
          void prepare(PrepareSpecs specs)
          {
              if (tempoSyncer == nullptr && specs.voiceIndex != nullptr)
              {
                  tempoSyncer = specs.voiceIndex->getTempoSyncer();
                  if (tempoSyncer != nullptr)
                      tempoSyncer->registerItem(this);
              }
      
              // Initialize output
              lastOut = bpm;
          }
      
          void reset() {}
      
          ~MinimalBPMListener() override
          {
              if (tempoSyncer != nullptr)
              {
                  tempoSyncer->deregisterItem(this);
                  tempoSyncer = nullptr;
              }
          }
      
          // --- Processing ---
          template <typename T>
          void process(T& data)
          {
              static constexpr int NumChannels = getFixChannelAmount();
              auto& fixData = data.template as<ProcessData<NumChannels>>();
              auto fd = fixData.toFrameData();
      
              while (fd.next())
                  fd.toSpan()[0] = (float)lastOut;
          }
      
          int handleModulation(double& value)
          {
              value = lastOut;
              return 1;
          }
      
          void setExternalData(const ExternalData&, int) {}
      };
      
      }
      
      

      This is a minimal example of how to get your custom C++ node to listen to the host BPM. Code above doesn't actually DO anything with the BPM information. But it proves the concept.

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Wavetable creation

      TBH, and certainly IMO.... Wavetable creation is not as optimized or fluid as it could be. The wavetable creator often crashes for no discernable reason, and the resynthesis modes do not sound as good as the resample mode does - when it works.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: How do I remove or mask out sections of a path?

      @dannytaurus Pretty similar to my fix above too. I just wanted a LAF solution rather than another panel hierarchy!

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: How do I remove or mask out sections of a path?

      Oh... wait... I get it.... tweak the draw area for the vertical fix, and draw coloured boxes over the edges to mask it all out.

                  laf.registerFunction("drawAnalyserPath", function(g, obj)
                  {
                      var a = obj.area;
                      var stroke = 2.0;
                      var pad = 2;
                      var a2 = [ a[0], a[1] + pad, a[2], a[3] - 2*pad ];
      
                      g.setColour(UIColours.modLFOLine);
                      g.drawPath(obj.path, a2, stroke);
      
                      var cover = 4;
                      g.setColour(UIColours.modPanelBackground);
                      g.fillRect([a[0] - cover, a[1] - 1, cover * 2, a[3] + 2]);
                      g.fillRect([a[0] + a[2] - cover, a[1] - 1, cover * 2, a[3] + 2]);
                  });
      
      posted in General Questions
      OrvillainO
      Orvillain
    • How do I remove or mask out sections of a path?
      namespace UILFOPlotter
      {
          
          const lfoPlotters = [
              Content.getComponent("PlotterLFO1"),
              Content.getComponent("PlotterLFO2"),
              Content.getComponent("PlotterLFO3")
          ];
      
          reg laf = undefined;
      
          inline function init()
          {
              laf = UILAF.ids.LFOPlotter;
      
              if (laf != undefined)
              {
                  laf.registerFunction("drawAnalyserBackground", function(g, obj)
                  {
                      g.fillAll(UIColours.modPanelBackground);
                  });
      
                  laf.registerFunction("drawAnalyserGrid", function(g, obj)
                  {
                      
                  });
      
                  laf.registerFunction("drawAnalyserPath", function(g, obj)
                  {
                      g.setColour(UIColours.modLFOLine);
                      
                      // draw the analyser path as a stroked line instead of a filled area
                      g.drawPath(obj.path, obj.area, 2.0);
                  });
              }
      
              for (plotter in lfoPlotters)
              {
                  plotter.setLocalLookAndFeel(laf);
                  plotter.set("itemColour3", 0);
                  plotter.set("bgColour", 0);
                  plotter.set("itemColour", 0);
                  plotter.set("itemColour2", 0);
                  plotter.set("textColour", 0);
              }
          }
      }
      

      960accb5-7fa3-47e6-9448-f4b2deac736d-image.png

      I have a floating tile set to plot the output of an LFO. I am setting up a look and feel and I'm registering the drawAnalyserPath function. As you can see it is working, but the drawn path has two issues:

      1 - It draws too far on the vertical axis; meaning my line gets clipped by the bounding box of the panel.
      2 - It draws the, presumably zero, data points at the far left and far right edges of the panel.

      How can I fix these two issues?

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Crash when loading files into Wavetable Creator (Resample Mode)

      @Christoph-Hart

      I'm still getting a crash when loading files into the wavetable creator and resample mode. It doesn't seem to happen when I use one of the other resynthesis modes.

      >	HISE Debug.exe!juce::MemoryBlock::MemoryBlock(const juce::MemoryBlock & other) Line 42	C++
       	HISE Debug.exe!hise::getMemoryBlockFromWavetableData(const juce::ValueTree & v, int channelIndex) Line 1324	C++
       	HISE Debug.exe!hise::WavetableSound::WavetableSound(const juce::ValueTree & wavetableData, hise::Processor * parent) Line 1357	C++
       	HISE Debug.exe!hise::SampleMapToWavetableConverter::rebuildPreviewBuffersInternal() Line 712	C++
       	HISE Debug.exe!hise::SampleMapToWavetableConverter::refreshCurrentWavetable(bool forceReanalysis) Line 1597	C++
       	HISE Debug.exe!hise::SampleMapToWavetableConverter::setCurrentIndex(int index, juce::NotificationType n) Line 1637	C++
       	HISE Debug.exe!hise::SampleMapToWavetableConverter::parseSampleMap(const juce::ValueTree & sampleMapTree) Line 854	C++
       	HISE Debug.exe!hise::WavetableConverterDialog::loadSampleMap::__l2::<lambda>() Line 787	C++
       	[External Code]	
       	HISE Debug.exe!hise::WavetableConverterDialog::run::__l2::<lambda>(std::function<void __cdecl(void)> & f) Line 942	C++
       	[External Code]	
       	HISE Debug.exe!hise::LockfreeQueue<std::function<void __cdecl(void)>>::callForEveryElementInQueue(const std::function<bool __cdecl(std::function<void __cdecl(void)> &)> & f) Line 1316	C++
       	HISE Debug.exe!hise::WavetableConverterDialog::run() Line 936	C++
       	HISE Debug.exe!hise::DialogWindowWithBackgroundThread::LoadingThread::run() Line 397	C++
       	HISE Debug.exe!juce::Thread::threadEntryPoint() Line 96	C++
       	HISE Debug.exe!juce::juce_threadEntryPoint(void * userData) Line 118	C++
       	HISE Debug.exe!juce::threadEntryProc(void * userData) Line 66	C++
       	HISE Debug.exe!thread_start<unsigned int (__cdecl*)(void *),1>(void * const parameter) Line 97	C++
       	[External Code]	
      
      

      That's the debugger callstack in VS2022. The main error I get is Exception thrown: read access violation.
      other was nullptr.

      It makes no difference as to whether I use a SampleMap in a sampler, or I drag and drop the sample directly into the creator.

      Is this anything you know about or could investigate??

      posted in Bug Reports
      OrvillainO
      Orvillain
    • RE: Modulation Matrix FX plugin crashes in DAW

      @resonant

      My project is setup for this:

      HISE_NUM_SCRIPTNODE_FX_MODS=32
      HISE_NUM_POLYPHONIC_SCRIPTNODE_FX_MODS=32
      NUM_HARDCODED_FX_MODS=32
      NUM_HARDCODED_POLY_FX_MODS=32
      ENABLE_ALL_PEAK_METERS=1
       JUCE_LOG_ASSERTIONS=1
      

      If you're going to be using hardcoded modulators, then you're definitely going to want to activate some of the mods. Saying that, I don't think having them set to zero would cause a crash. Would just cause modulation to not work.

      If you're using a hardcoded module, are you initialising the SlotFX properly when your plugin loads? I'm not 100% certain, but if you're not ensuring the slot actually has the effect and then you're trying to map modulation to it at any point, that could cause a null pointer and a crash.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Component search - how does it work?

      @Chazrox In the UI editor, the foldable panel on the left hand side that shows all of your added components. There's a search box at the top of it, but it is a bit ropey.

      posted in General Questions
      OrvillainO
      Orvillain
    • Component search - how does it work?

      Component search seems a bit iffy to me. If I search for something like "Engine1SamplerTabArea" then depending on what the names of my other components are ... I might end up with a load of stuff in the results that just isn't anything remotely to do with my original search term.

      How does it work?

      posted in General Questions
      OrvillainO
      Orvillain