HISE Logo Forum
    • Categories
    • Register
    • Login
    1. HISE
    2. Orvillain
    3. Posts
    • Profile
    • Following 1
    • Followers 0
    • Topics 70
    • Posts 562
    • Groups 0

    Posts

    Recent Best Controversial
    • RE: Force mono node?

      @Christoph-Hart said in Force mono node?:

      Not sure I understand, where do you do the switch? And why do you want to switch if you know that a node is only processing a single channel?

      If you're node is known to be mono, then just process the first channel in the implementation, or if you want to force a generic node to only process the first channel, you can use the wrap::fix template to force mono processing.

      // instead of this member declaration
      MyClass obj;
      
      // use
      wrap::fix<1, MyClass> obj;
      

      Your code is probably throwing an assertion at auto* right = block.getChannelPointer(1); if you have created the audio block from a single channel process data object.

      I was thinking in situations where I want to do a tubescreamer emulation, for example. I don't want true stereo processing.

      But maybe I'm overthinking it, and I just do a stereo node... collapse the channels... process the result... write the result back to output left and output right, with some gain compensation?

      posted in C++ Development
      OrvillainO
      Orvillain
    • Force mono node?

      Sometimes you know that you definitely want a node to only process in mono.

      So if I do:

      static constexpr int getFixChannelAmount() { return 1; };
      

      And then later on:

      template <typename T> void process(T& data)
      		template <typename T> void process(T& data)
      		{
      			auto& fd = data.template as<ProcessData<getFixChannelAmount()>>();
      			auto block = fd.toAudioBlock();
      			auto* left = block.getChannelPointer(0);
                  auto* right = block.getChannelPointer(1);
      			numSamples = data.getNumSamples();
      			
      			// change "effect" object to StereoAudioEffect
      			// and switch to this if stereo
      			//effect.process(left, right, numSamples);
      
      			// change "effect" object to MonoAudioEffect
      			// and switch to this if mono
      			//effect.process(left, numSamples);
      			
      		}
      

      I would have two separate effect processor classes; MonoAudioEffect and StereoAudioEffect. Essentially wrappers around some child DSP objects.

      Is this a legal approach to effectively switching between mono versus stereo processing? Should I be copying the left channel to the right channel to make things consistent with the rest of scriptnode?

      posted in C++ Development
      OrvillainO
      Orvillain
    • More audio export options

      2069a4a6-07cb-43d0-9f9b-11fd64f1101f-image.png

      I know this is super boring low hanging fruit, but could we get a few extra options here? I'd really like 30 seconds, 1minute, 2 minutes, and a manual option if possible, where you can hit an on-screen stop button when you're ready.

      posted in Feature Requests
      OrvillainO
      Orvillain
    • RE: OSC Filter caps at 1.9khz

      Looks like your base value is not fully open on the filter itself. iirc, the matrix modulator takes the base value as the maximum possible value.

      Open the filter up to 20k, and then your modulation range will sweep the full range.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Christoph-Hart Good to know, cheers!!

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Christoph-Hart said in Matrix Modulation Feedback:

      @Orvillain now you have another reason. Also all dialogs / other inbuilt components will not scale correctly like this.

      Ah cool beans. Yeah that was trivial to implement in my existing code, and actually makes the whole thing a lot simpler. Sorry, I thought the whole thing was originally a bug to do with the matrix mod controller and how it processed css - hence tagging onto this thread!

      The only slight loss is, my approach was working inside HISE directly, without having to compile the plugin in order to double check zoom/rescale performance.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Christoph-Hart said in Matrix Modulation Feedback:

      @Orvillain wait, how do you rescale your UI? Settings.setZoomFactor() should scale all fonts correctly.

      No I'm not doing that. I have a custom scaling namespace that does a bunch of math, but ultimately what it does is update the properties of any UI widge - so x, y, w, h, fontSize, etc etc.

      This kind of thing:

          inline function rescaleAll()
          {
              // Order of operations:
              // Resize interface
              // Re-apply panel bounds
              // Re-apply control bounds
              // Re-apply control style props (font, radii, etc.)
              // Reposition zoom handle
      
              // Resize the window
              Content.makeFrontInterface(SharedData.getScaledWidth(), SharedData.getScaledHeight());
      
              // Panels first (so parents are sized before children)
              for (i = 0; i < _layout.length; i++)
                  _applyScaledBounds(_layout[i]);
      
              // Controls: bounds then props
              for (i = 0; i < _controls.length; i++)
              {
                  _applyScaledBounds(_controls[i]);
                  _applyScaledProps(_controls[i]);
              }
      
              LogicalZoom.onRescaled();
          }
      

      Effectively, I'm scaling everything manually. Not using the automatic zoom factor way to do it. I don't have a reason other than coder ego!!

      And this all works fine, but setting the font-size property in the modulation controller didn't seem to update in any of the ways I tried.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Orvillain I solved my issue by making my font size a percentage of the dragger, but it was a bit weird. Everything I tried simply would not update the font size. Even doing a setStylePropertyblahblahblah call on the LAF object didn't work.

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: CSS custom variables not taken by the ModulationMatrix

      Might also be true for FloatingTile in general. At least, I can't get it to work!

      posted in Bug Reports
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      Or maybe I'm better off making custom panels with callbacks, and doing all of the scaling stuff I want to do inside regular LAF, rather than css ??

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Christoph-Hart

      I'm trying to do this:

      inline function setupModulationControlPanelLAF(numDraggers)
          {
              Console.print("rescaling triggers the setupModulationControlPanelLAF, and UI_SCALE is: " + SharedData.UI_SCALE);
              local wPct = 100.0 / numDraggers;
              local fontPx = Math.round(12 * SharedData.UI_SCALE);
              Console.print("fontpx is: " + fontPx);
              local laf = Content.createLocalLookAndFeel();
              laf.setInlineStyleSheet("
                  
              #controller
              {
                  display:flex;
                  flex-wrap:nowrap;
                  align-items:center;
                  width:100%;
                  padding:0;
                  gap: 2px;
                  border-radius:0;
                  background:#333;
                  overflow:hidden;
              }
              
              .control-button
              {
                  display:none;
              }
      
              .dragger
              {
                  display:block;
                  flex:0 0 " + wPct + "%;
                  width:" + wPct + "%;
                  height:100%;
                  min-width:0;
                  box-sizing:border-box;
                  white-space:nowrap;
                  overflow:hidden;
                  text-overflow:ellipsis;
                  text-align:center;
                  background-color:rgba(76, 76, 76, 1);
                  opacity: 0.8;
                  font-size:" + fontPx + "px;
              }
      
              .dragger::before
              {
                  content: '';	
                  background-color: white;
                  background-image: var(--dragPath);
                  width: 24px;
                  margin: 2px;
              }
      
              .dragger:checked
              {
                  background-color:rgba(255, 0, 0, 1);
                  opacity: 1.0;
              }
      
              ");
      
              local tile = Content.getComponent("ft_modcontroller");
              tile.setLocalLookAndFeel(laf);
          }
      

      This function is called at init, but is also called when I rescale my UI (which is all code that definitely works) ... but my font doesn't resize.

      The flex and width of the draggers does seem to update. So I think I'm doing the right technique???

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Matrix Modulation Feedback

      @Christoph-Hart

      Does the ModulationMatrixController use the FloatingTile fontSize property???

      posted in General Questions
      OrvillainO
      Orvillain
    • RE: Ring Buffer design

      @griffinboy said in 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.

      A typical approach to decorrelating reverbs is to mildly modulate delay times in the FDN. But you can also do it on the input diffuser or the early reflections APF network too. So anything that affects delay time is ultimately going to make some kind of difference.

      It'd be interesting to compare them all. Maybe that's a new thread in a few weeks or so!

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Ring Buffer design

      @griffinboy said in 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.

      Indeed! Indeed! I haven't got to any of this yet. Just using basic c++ loops without any SIMD or vectorization.

      I'm looking at this purely for chorus or modulation effects, delays, reverbs, and sample playback.

      The reason I've implemented all of these is because I want to experiment with 80's, 90's, 2000's, and modern delay and reverb approaches, and I want to embrace the "shittiness" of certain approaches, as long as they add to or enhance the character.

      Pretty archetypal example for me. I've got a £100 Boss RV-5 pedal here, and a £700 Meris MercuryX pedal. Both outstanding reverbs. The RV-5 is clearly less clever under the hood. You can hear the delays in the FDN every now and then, and it doesn't sound super high fidelity. But bloody hell is it cool!!! Way better than later Boss reverbs IMHO.

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Ring Buffer design

      So yeah, what I've implemented in my ring delay are the following:

      Read Nearest: uses 1 sample. It is the worst quality in terms of aliasing and modulation smoothness. But the lowest CPU usage.
      Read Linear: Uses 2 samples. It has audible HF loss, the aliasing is poor, but the modulation is a level above nearest. CPU usage is still low.
      Read Cubic: Uses 4 samples. Somewhat noticeable HF roll-off, aliasing performance is fair, and the modulation is surprisingly smooth. Medium CPU usage.
      Read Lagrange3: Uses 4 samples. Better HF retention than cubic, but still rolls off. Aliasing rejection is okay, but does let some junk through. Smooth modulation. Medium CPU usage.
      Read Sinc: Has 16 taps, which means it takes 16 input samples around the read point and does 16 FMA's to produce one output sample. The passband is very flat, no HF loss. Aliasing performance is excellent. Modulation is excellent. CPU is relatively high - but here on my machine never spiked above 1%.
      Read Sinc Blended: Also takes 16 input samples, but because we have a blend it performs 32 FMA's to produce one output sample. The passband is very flat, no HF loss. Aliasing performance is excellent. Modulation is excellent. CPU is relatively high - but here on my machine never spiked above 2%.

      It will be interesting when I get this stuff onto an embedded platform like the DaisySeed (ARM Cortex based) and then I can see how it all works out CPU-wise.

      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Ring Buffer design

      @griffinboy said in Ring Buffer design:

      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.

      Hey thanks dude for this. I went off on a ChatGPT research mission, and I think I'm starting to understand it. I've got it implemented anyway, it seems to work.

      Here's how I'm understanding it, again with a bit of help!!!

      ....

      Sinc uses a band-limited approach to reconstruct the original continuous signal. But computing a fresh sinc for every fractional position would be super expensive. So we precompute lots of sinc kernels and whack 'em in a table.

      The table has a bunch of rows - phases.
      Each row contains taps - the weights that nearby samples get multiplied by. The more taps you have gives you a better frequency response, but more CPU usage.

      Each row is then a windowed sinc where 'k' is the taps integer offset from the centre sample, 'f' is the fractional position. You take a window function like Hann or Blackman-Harris, and that gentle fades the ends so that the limited sinc doesn't pre-ring.

      After building the row, normalize it so it sums to 1. This keeps DC level stable.

      Store all rows flat in a coeffs array, with some helpers to read the correct row - rowNearest and rowBlended.

      Nearest gives you the closest phase row for the given fraction.
      Blended gives the two neighbouring rows plus a blend factor, so you can crossfade across the two.

      Then inside my RingDelay, my new 'getReadPos' function gives an integer index and a fractional part. This can be used with any of my interpolation methods (nearest, linear, cubic, lagrange3, and now sinc)

      readSinc uses nearest. readSincBlended uses blended.

      For each tap, lookup the neighbouring samples around i1, and multiply by the weights. Sum them up, and that gives the interpolated value.

      So Cubic or Lagrange - uses 4 samples, and looks smooth. But is not truly band limited. It rolls off highs in the pass band, so things sound slightly dull. Stop band rejection is not great, so it can alias or cause whistle tones.

      Windowed Sinc - approximates the ideal reconstruction. Much flatter passband so it keeps brightness. Much stronger stopband attenuation, so there is less aliasing. It is also linear phase, so transients don't get skewed. When you sweep the delay time, it stays clean and consistent. But it costs more CPU.

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

      @griffinboy Oh nice!! Some night time reading material right there!

      posted in C++ Development
      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: I wrote a reverb

      @hisefilo said in I wrote a reverb:

      @Orvillain it’s beautiful. Really impressive. Better that 99% of commercial reverbs out there IMO

      I'm honoured, thank you!

      I've done a few things since the video:

      • Improved the diffusion
      • Added some extra modulation shapes
      • Added early reflection modulation depth
      posted in C++ Development
      OrvillainO
      Orvillain
    • RE: Ring Buffer design

      @Christoph-Hart said in Ring Buffer design:

      TLDR: Start with the implementation that is the easiest to understand / write / debug, then profile or put isolated pieces into Godbolt to see what can be improved.

      This was my thought too - it isn't any good writing code if I come back to it a week later and can barely understand it. So I try to approach things in the easiest to understand way first, even if it is a bit knuckleheaded. You can always optimize the hell out of a for loop or array access, later on down the line.

      posted in C++ Development
      OrvillainO
      Orvillain