DigiDrie icon indicating copy to clipboard operation
DigiDrie copied to clipboard

experiment: High pass filter

Open magnetophon opened this issue 4 years ago • 16 comments

I added another filter. It sounds great, but uses quite some CPU: it went from 36% to 39% on my machine.

Also the compile takes way longer with this.

What do you think, use it, or leave it out until we find a way to optimize the whole synth?

magnetophon avatar Aug 15 '20 21:08 magnetophon

Could you try this one? The synth's code is supplying same freq and Q to the filters. So, we can unify the computation of svf.lp and svf.hp to one.

import("stdfaust.lib");

// Output is: lp,hp.
svf(F,Q) = tick ~ (_,_) : !,!,_,_,_ : mix
with {
  tick(ic1eq, ic2eq, v0) =
    2*v1 - ic1eq,
    2*v2 - ic2eq,
    v0, v1, v2
  with {
    v1 = ic1eq + g *(v0-ic2eq) : /(1 + g*(g+k));
    v2 = ic2eq + g * v1;
  };
  g = tan(F * ma.PI / ma.SR);
  k = 1/Q;
  mix(s0, s1, s2) =
    s2,               // lp
    s0 - k * s1 - s2; // hp
};

freq = hslider("freq",100,20,1000,1e-5);
cut = hslider("cutoff",60,0,127,1e-5) : ba.pianokey2hz : max(20) : min(20000);
Q = hslider("Q",1,1e-5,1,1e-5);

process = os.sawtooth(freq) : svf(cut, Q);

ryukau avatar Aug 15 '20 22:08 ryukau

Your filter works fine in the demo you provided.

In this branch I used it instead of the old svf. It has been compiling for 50 minutes now... :( It's at end Constant propagation

Maybe I did something wrong. It is getting late here...

magnetophon avatar Aug 15 '20 23:08 magnetophon

Also: It looks like it's doing the exact same calculations, no? I think the two versions should be identical after compilation.

The odd thing is that yours takes longer to compile. I would expect the other way around.

magnetophon avatar Aug 15 '20 23:08 magnetophon

After an hour, it finished compiling. :+1:

Unfortunately the dsp usage is actually a bit higher than the old one.

magnetophon avatar Aug 15 '20 23:08 magnetophon

I looked into C++ code generated by faust command, and confirmed that my one didn't improved anything. Faust is smart that didn't use tan twice even when using svf.lp and svf.hp separately.

Other possibility for speed up is the approximated implementation (link).

ryukau avatar Aug 16 '20 00:08 ryukau

Also how about this one?

preFilter(svfLpLevel,svfHpLevel,ms20level,oberheimLevel,normFreq,Q) =
  _<:
  (
    _
  , (svfLpLevel , svflp:enableIfVolume)
  , (svfHpLevel , svfhp:enableIfVolume)
  , (ms20level , korg35LPF(freq,Q):enableIfVolume)
  , (oberheimLevel , oberheimLPFf(freq,Q):enableIfVolume)
    )
  :fallbackMixer(4,1,1)
with {
  freq = normFreq*127:ba.pianokey2hz
         :max(0)
         :min(ma.SR/2-10); // oberheim has artifacts with high freqs, they go away when compiling with -quad, but also when I limit the range.
  svfout = svfF(freq, Q);
  svflp = svfout : _,!;
  svfhp = svfout : !,_;
};

ryukau avatar Aug 16 '20 00:08 ryukau

approximated implementation

I almost forgot about that one. I'll go try now.

Also how about this one?

Isn't that the exact same calculations again?

magnetophon avatar Aug 16 '20 08:08 magnetophon

It's the same calculations. The generated code I looked in was small Faust code with only SVF on it. I'm suspecting that Faust failed to simplify SVF in more complex code.

I'll measure it on my environment.

ryukau avatar Aug 16 '20 09:08 ryukau

I'm suspecting that Faust failed to simplify SVF in more complex code.

Yeah, I suspect that too sometimes.

For example when I use freq(note) instead of note for the note modulation, that doesn't even compile, even though that value is already used elsewhere, so it should e a simple copy-paste for the compiler, iiuc.

I'm compiling a version with all your approximations now. I'm afraid it will not help much, because all 48 filters use the same g =, so it should be calculated only once.

Let's see.

magnetophon avatar Aug 16 '20 09:08 magnetophon

HPF branch took almost 1 hour (3500+ seconds) to build. There's not much difference on DSP load here. All are around 30-32%.

I tried following builds:

  • faust branch
  • HPF branch
  • Explicit simplification on this comment.
  • Approximation only for SVF.
  • Approximation for all filters.

Build command:

faust2jaqt -t 0 -time -midi DigiDrie.dsp

ryukau avatar Aug 16 '20 10:08 ryukau

Heh, I also just finished building a version using all approximations, also took an hour.

I also got similar DSP usage. Maybe slightly lower than before.

I do love the sound of the HPF, so I vote for keeping it. What do you think?

Maybe I secretly hope there will be an optimization break-trough. One option we didn't try yet, is to compile for a fixed SR. If that helps a lot, you could use C++ to switch between versions compiled with different SR, right?

Do we have any other options for optimization left?

magnetophon avatar Aug 16 '20 11:08 magnetophon

I reported our slow compile upstream. Just in case you can add useful info there.

magnetophon avatar Aug 16 '20 11:08 magnetophon

I just cloned this repo 5 times and built them on parallel. Faust compiler seems to using only a single thread.

I'm all for adding HPF. However, merging this branch will cause serious problem because of build time. So I vote for pending of merge.

I'm against for fixed SR. In my opinion, fixed SR option is only useful when targeting to embedded environment. On DAW, sampling rate can change anytime by user configuration. And I have no idea how host sends SR. My feeling is that there are some hosts which sends SR from non-DSP thread. If that's the case, it will segfault at sometime at somewhere. And it's very hard for me to debug/fix.

Also:

  • Compile time (single thread case) and size of plugin goes up to the multiple of supported SR.
  • It's possible someone use SR other than 44100, 48000, 88200, 96000, 192000.

Approximated version didn't get the speed up I hoped. Replacing variable to constant is far more subtle in my experience. Unless there's significant speed up, like at least DSP load goes down to half or so, I don't think it's worth the effort.

ryukau avatar Aug 16 '20 11:08 ryukau

Perhaps DSP load changes when compiled into plugin. At least parameter propagation is likely different to faust2* commands.

I'm currently working on combining Faust DSP code to C++ parts. Let's see how it turns out.

ryukau avatar Aug 16 '20 12:08 ryukau

So I vote for pending of merge.

Agreed.

I can also put it behind a compile time constant, so you can easily build different versions by changing just one value. Maybe I should make that variable switch between "all filters" an "no filters". Probably reduces compile time even more, for testing.

What do you think?

Too bad fixed SR is not possible. :/

Perhaps DSP load changes when compiled into plugin.

Do you think it will be better or worse, or you don't know?

I'm currently working on combining Faust DSP code to C++ parts.

:rocket:

magnetophon avatar Aug 16 '20 12:08 magnetophon

I like the idea of switch for toggling filters. It will be handy.

For DSP load on plugin, I have no idea.

ryukau avatar Aug 16 '20 12:08 ryukau