HISE Logo Forum
    • Categories
    • Register
    • Login
    1. HISE
    2. griffinboy
    3. Posts
    • Profile
    • Following 8
    • Followers 8
    • Topics 115
    • Posts 947
    • Groups 1

    Posts

    Recent Best Controversial
    • RE: Is it possible to get a wider Q shape?

      @Dan-Korneff
      @WillowWolf

      Indeed.
      Creating a custom filter is your best bet.

      Digital SVFs are a particular topology which have limits to the shapes you can make with them. There are a few different methods to choose from to create digital filters with more flexible frequency responses.

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @Orvillain

      I've never used sync / fir interpolators in a reverb.
      I'm not sure how high the benefit would be.
      For delays and synthesis it's great though when you need low aliasing and low ripple.

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @Orvillain

      That's exactly it.
      And the cool thing about using a fir interpolator like this with multiple taps, is that you can SIMD it
      Process 4 taps in one SIMD instruction cut CPU significantly.

      Hise has XSIMD included.
      You don't need to include it you can just use it in a c++ node

      Oh but it has latency potentially to use this technique. So it's not good for certain uses where it's too fiddly to compensate latency in different places.
      But it's good for delay effects and for reading samples from a buffer at a new speed.

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: I wrote a reverb

      @Orvillain

      Just a moment...

      favicon

      (gearspace.com)

      I've also found this thread to be helpful!
      and for tuning reverbs there are some papers from a few years back about using neural networks to tune FDNs to be spectrally flat (no resonances)

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @Christoph-Hart

      Thanks for all this, it's super interesting.

      I'm afraid I've turned this thread into an optimisation discussion, my fault whoops

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @Christoph-Hart

      Thanks for the rebuke! Looks like I need to do my homework

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @ustk

      absolutely efficiency. The built in ones aren't bad by any means, but they are generic rather than made specific for your needs only. And thus they miss out on a few optimizations.

      But apart from that they are also not amazing.
      I don't use cubic interpolators on my delay lines, I use FIR filters (using SIMD) using impulses which are equivalent to windowed sync interpolation. But for this example I left in the cubic. Else it would be multiple headers worth of scripts as we start to worry about upsampling downsampling, convolution.
      Which is perhaps overkill by the way, I partly do it because I can. Not because anyone cares.

      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Ring Buffer design

      @Orvillain

      Keep posting!
      It's great to see c++ stuff here, I'm having fun looking at your work.

      Here is my take on your concept!
      This may give more to chew on if you want to explore common buffer optimizations.
      Your example is really nice and clear: this will be less so. I'm not trying to overshadow any of your stuff at all, I just wondered if you'd be curious. I'll leave it here for the curious.

      /*
          Power-of-2 sized ring buffer delay with cubic interpolation.
          Uses fixed-point math for fractional addressing: the high 16 bits store the integer index,
          the low 16 bits store the fractional position between samples. This makes wrapping branchless, so each read is very cheap on the CPU.
      
          HOW TO USE:
            1. Call setSize(minCapacitySamples) once to allocate the buffer.
               - The actual buffer allocated will be to the next power-of-two.
               - This function sets the maximum possible delay length.
            2. Each new input sample, call push(x) to write it into the delay line.
            3. To read a delayed sample, call readCubic(delaySamples).
               - delaySamples can be any float value (integer or fractional) up to the buffer size.
               For example: delaySamples = 4410.5f gives a 100 ms delay at 44.1 kHz 
      */
      
      
      #pragma once
      #include <vector>
      #include <algorithm>
      #include <cstdint>
      #include <cmath>
      
      struct RingDelay
      {
          // fixed point settings: 16 fractional bits
          static constexpr int FP_BITS = 16;
          static constexpr uint32_t FP_ONE = 1u << FP_BITS;
          static constexpr uint32_t FP_FRAC_MASK = FP_ONE - 1u;
          static constexpr float FP_INV = 1.0f / float(FP_ONE); // precomputed reciprocal
      
          std::vector<float> buf;
          int w = 0;
          int mask = 0;
      
          static inline int nextPow2(int x) noexcept
          {
              if (x <= 1) return 1;
              --x;
              x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16;
              return x + 1;
          }
      
          inline void setSize(int minCapacitySamples)
          {
              if (minCapacitySamples <= 0) minCapacitySamples = 1;
              const int n = nextPow2(minCapacitySamples);
              buf.assign((size_t)n, 0.0f);
              mask = n - 1;
              w = 0;
          }
      
          inline void push(float x) noexcept
          {
              buf[(size_t)w] = x;
              w = (w + 1) & mask;
          }
      
          // cubic interpolation between 4 samples
          static inline float cubicInterp(float s0, float s1, float s2, float s3, float f) noexcept
          {
              float c0 = s1;
              float c1 = 0.5f * (s2 - s0);
              float c2 = 0.5f * (2.0f*s0 - 5.0f*s1 + 4.0f*s2 - s3);
              float c3 = 0.5f * (3.0f*(s1 - s2) + s3 - s0);
              float t  = std::fmaf(c3, f, c2);
              t        = std::fmaf(t,  f, c1);
              return std::fmaf(t,  f, c0);
          }
      
          // fractional read using fixed-point address (Q16.16)
          inline float readCubic(float delaySamples) const noexcept
          {
              if (delaySamples < 0.0f) delaySamples = 0.0f;
      
              // convert delay into fixed point
              const uint32_t delayQ = (uint32_t)(delaySamples * float(FP_ONE) + 0.5f);
      
              // make fixed-point write pointer
              const uint32_t wQ = (uint32_t)w << FP_BITS;
      
              // wrap both integer and fractional parts with one AND
              const uint32_t sizeMaskQ = (uint32_t(mask) << FP_BITS) | FP_FRAC_MASK;
              const uint32_t rpQ = (wQ - delayQ) & sizeMaskQ;
      
              // integer and fractional parts 
              const int   i1 = int(rpQ >> FP_BITS);
              const float f  = float(rpQ & FP_FRAC_MASK) * FP_INV;
      
              // neighbours
              const int i0 = (i1 - 1) & mask;
              const int i2 = (i1 + 1) & mask;
              const int i3 = (i1 + 2) & mask;
      
              return cubicInterp(buf[(size_t)i0], buf[(size_t)i1], buf[(size_t)i2], buf[(size_t)i3], f);
          }
      
          inline int size() const noexcept { return mask + 1; }
      
          inline void clear() noexcept
          {
              std::fill(buf.begin(), buf.end(), 0.0f);
              w = 0;
          }
      };
      
      
      
      1. Fixed-point addressing 
         - Delay time is split into fixed point math. 
      We store the integer + fractional part as a 32-bit value. 
      (Fixed-point is better because it stores the whole and fractional 
      parts together in one integer, so the CPU can grab them with 
      simple bit-ops instead of doing slower math. With a float, the 
      whole part and fractional part are hidden inside its binary 
      format, so you need extra math (like floor and division) to separate them)
         - Wrapping is now done with a single bitmask, no floor or % calls.
      
      2. Removed redundant mask
         - i1 index already wraps by sizeMaskQ. No extra mask is needed.
      
      3. Fused multiply-add (FMA) cubic interpolation
         - We use the Horner form here (fewer multiplications and rounding steps) It's
       faster on CPUs that support FMA.
      
      4. Inlined hot methods
         - We mark small functions as inline. This removes function call overhead.
      
      5. Efficient power-of-two size calculation
         - nextPow2 uses bit-twiddling. No loops
      
      
      posted in C++ Development
      griffinboyG
      griffinboy
    • RE: Compressor

      @ustk

      Yeah of course if it's c++ dsp, you can just use a global cable to send the graph to the UI
      Keep a second, mono class of the compressor dsp without envelopes, and when a paramter changes, compute the response (staggered updates) using that instance and send it as a json to the UI side of Hise.

      But you can even do this in Hise if you want. I doubt the compressor algorithm is complex. Just write it as Hise script and process your line through it.
      Without envelopes, a compressor is a waveshaper. It'll just be a simple algo

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Compressor

      @hyperphonias

      Sending a linear -1 to 1 sample DC sweep through the effect is the real way to get out the curve. But you can just create a paintroutinue to approximate it if you're after the rough visual.

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Electrodyne Drum Sampler (Looking for Co-Developer)

      @d-healey
      @tahinar

      I second this.
      For your first project, you'll want to split this up into 'mini projects' and get each part working in isolation. Then bring the ideas together. If you try and build the final product straight away in a single project, when all the different systems go wrong, you'll have a heck of a bad time trying to untangle all the pieces!

      Create the sampler engine as one project,
      The Distortions in another project, the EQs in another, and then prototype the GUI in yet another. Especially since they will all progress at different paces, and each part involves a lot of coding and testing on its own.
      This is a big project!

      posted in General Questions
      griffinboyG
      griffinboy
    • Sample Map + Display Buffer? (c++ nodes and sample maps)

      I've got this c++ sampler and I'm not sure how I'm supposed to interact with it using Hise?
      Can display buffers be used in any way with it?

      I've noticed that when loaded into a hardcoded network, there is no option for external display buffer at all.

      For loading sample maps using code we do it like this right?

      use the {XYZ::SampleMap} wildcard, 
      followed by the samplemap ID (without the .xml extension). 
      So if your samplemap is called Piano.xml, then the string 
      you pass into loadFile() is "{XYZ::SampleMap}Piano
      
      posted in General Questions
      griffinboyG
      griffinboy
    • RE: load data into wavetable synthesiser without killing all voices

      @Allen

      My custom wavetable node does this, but it's c++

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Feature request: extract XYZ data metadata

      @Christoph-Hart

      Update

      You can forget it! Client decided that they didn't need this feature. Thanks for your help thus far. I no longer need to solve this!

      posted in Feature Requests
      griffinboyG
      griffinboy
    • RE: Feature request: extract XYZ data metadata

      @Christoph-Hart

      edit This issue is solved. Read my message below this post.


      okay the issue is that when we load a sample map into the c++ sampler, we need the Loop metadata to set the Loop Parameters of the c++ node.

      0bea0a38-8bf5-4a94-aef5-218b2d39e383-image.png

      Sure, I can just load in a sample map and internally use the loop values, the result will sound correct. However, the actual parameters will be in the wrong locations.

      posted in Feature Requests
      griffinboyG
      griffinboy
    • RE: FX plugin Dev needed

      @Chazrox

      😆 Indeed.
      Let all the Hise experts assemble!

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Wordpress plugin to block temp mail signups

      @dannytaurus

      The idea isn't to discount any of your main products. It's to create a 'lite' version of one of your products, and make that super cheap.

      Then after people have bought that, you send emails to upsell the full version. Then after they've bought that, you send emails to sell from the parallel product lines.

      I agree with you that huge discounts are a bad idea on regular products. Unless it's very very infrequent. The point of normal discounts is to get money from people who would never buy your product at full price. Whereas the point of the strategy I'm referring to is to convert cold traffic and get people into your pipeline, lead magnet kind of idea. You can run paid ads on this lead and choose how much traffic to generate.

      I'm no expert though, this is all just stuff that I've heard.

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Widen The Mid and High

      @Oriah-Beats

      i've done it in c++

      In scriptnode you can probably do it by using the frequency split template, and on the high band, create a haas effect (delay the right channel by a small amount), or increase the volume of the side channel on that band. There are other tricks to create width using analog modelling or filters, but the haas and side channel technique are the basic digital methods.

      For the more advanced tricks you'll want to use c++ (for example if you simulate an analog circuit, like the ones found inside of mixing desks, you can use different component values for the left and right channel circuits, resulting in super natural sounding width from the component differences in each channel)

      probably the most advanced scriptnode widening chain you could create would be an early reflections type thing, where you have a send to a chain which applies filtering, haas, invert the right channel (flip waveform upside down) and then swaps the left and right channels.

      posted in General Questions
      griffinboyG
      griffinboy
    • RE: Feature request: extract XYZ data metadata

      @griffinboy
      @Christoph-Hart
      @DanH

      Sorry to bother you! Important! : )

      posted in Feature Requests
      griffinboyG
      griffinboy