DigiDrie
DigiDrie copied to clipboard
experiment: High pass filter
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?
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);
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...
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.
After an hour, it finished compiling. :+1:
Unfortunately the dsp usage is actually a bit higher than the old one.
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).
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 : !,_;
};
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?
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.
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.
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
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?
I reported our slow compile upstream. Just in case you can add useful info there.
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.
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.
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:
I like the idea of switch for toggling filters. It will be handy.
For DSP load on plugin, I have no idea.