Krell patch in pd - behaving buggy

I’ve been playing with my Lich and made this here Krell patch based on a youtube tutorial → https://www.rebeltech.org/patch-library/patch/krell_patch_unfinished

Now, the behaviour in heavy/hvcc is slightly off compared to Pd, but it works fine in both my DPF builds (lv2/vst2/jack) and the webasm on the patch-library compiler.

However when I load this patch in to my Lich it behaves more erratically, and seems to crash the dsp in 30-60 seconds or so. Can still select other patches so OWL is still running, but this happens every time and very consistently.
I thought it was a problem with the delay, but after removing that it still gives the error.

Any ideas/suggestions on why this happens?

The Lich is running firmware v21.2.2

I’ve just tried it out on a Witch and I get the same thing: it makes some sound when pressing the button, then after some time it just stops.

I’ll try to compile it offline with some different options for math optimisations and see if it changes anything.

1 Like

And, found out yet why it crashes? :slight_smile:

bump

Have you had time to try these different compiler options to see if they make a difference?

Still no idea why this happens, anyone else test this yet?

Sorry I went on holiday and completely forgot!

Testing it now again. If I don’t press the button, it doesn’t crash. Then after I press it, it sounds like some delay lines are saturating, and then suddenly it cuts out.

If I compile without math optimisations then it behaves a bit better, but ultimately still explodes.

At first I thought it could be because of DC offset creeping into the feedback lines, but I see you have both hp and lp filters there.

Maybe it is due to a difference in precision, we use 32 bit floats on the hardware while JS does everything in 64 bits. This can be important to the filters, depending on how they are implemented. Biquad filters tend to ‘explode’ if configured with very high or very low cutoff frequencies.

I would try changing the range of your [bp~] random generator. MIDI note 21 is only 27 Hz which puts the filter coefficients very, very close to zero - probably too close for 32 bit representation.

I made a copy which you can try here, it seems to work fine with a narrower bp range (note 44 to note 116, or 103 Hz to 6644 Hz). It’s sitting on my desk making some nice, spacey noises right now!

I also put a gain stage in the feedback loop but it didn’t have the effect I intended, probably because I’m attenuating the write and not read. It’s probably neither needed nor useful.

1 Like

Right, biquads with low cutoff frequency lead to denormals in FP math, especially in single precision floats. I recall reading that the SVF that we have (from Andy Simper’s paper) doesn’t have this sort of issue as its coefficients stay in a reasonable range in such situation.

Let me also quote the holy book a.k.a. ARM Cortex-M4 reference manual:

Floating Point Unit 

Full-compliance mode

In full-compliance mode, the FPU processes all 
operations according to the IEEE 754 standard in 
hardware.

Flush-to-zero mode

Setting the FZ bit, FPSCR[24], enables flush-to-zero 
mode. In this mode, the FPU treats all subnormal 
input operands of arithmetic CDP operations as 
zeros in the operation. Exceptions that result from 
a zero operand are signaled appropriately. VABS, 
VNEG, and VMOV are not considered arithmetic 
CDP operations and are not affected by flush-to-zero 
mode. A result that is tiny, as described in the IEEE 
754 standard, for the destination precision is smaller 
in magnitude than the minimum normal value before 
rounding and is replaced with a zero. The IDC flag, 
FPSCR[7], indicates when an input flush occurs. The 
UFC flag, FPSCR[3], indicates when a result flush occurs. 

Default NaN mode

Setting the DN bit, FPSCR[25], enables default NaN mode.
In this mode, the result of any arithmetic data processing 
operation that involves an input NaN, or that generates a
NaN result, returns the default NaN. Propagation of the 
fraction bits is maintained only by VABS, VNEG, and VMOV 
operations. All other CDP operations ignore any information 
in the fraction bits of an input NaN.

I suppose we would be using the first mode here?

1 Like

Assuming that the problem is that filter coefficients are truncated or quantized, then I don’t see how full-compliance mode here will help. We may still get unstable filters. Presumably the full compliance modes also come with a performance penalty?

SVFs don’t have the same issue with low cutoff frequency, but from memory I think they don’t like going too high, correct?

I’d expect that it’s not free. But it’s used by default and I didn’t mean that it would solve biquad’s computation problems;-) It may be worth checking if we can disable to get better performance it, i.e. Bela does this: IEEE 754 floating point on Bela · BelaPlatform/Bela Wiki · GitHub . But they have to interoperate with NEON and NEON is always FTZ, I imagine that not using it would give them exciting bugs in some cases.

IIRC, the Chamberlin SVF blows up at FS/6, but I don’t think that’s the case with trapezoid integrator SVF that we’re using. Here’s that post with that paper’s announcement: Trapezoidal and other integration methods applied to musical resonant filters

1 Like

Wow, thanks a lot for this analysis guys!

Would be good to have a side-note on these kind of things. I would not have thought of this myself for sure. So it’s quite platform dependent which numbers can be represented and this is not something a compiler can “straighten out” say. Is that something one could get warnings/errors on, or is it purely a run-time thing that you just have to find out the hard way?

Just tested your modified patch @mars and works great!
Will try to remember this in future patches.

It’s kind of hard to detect this kind of issues at compile time. Biquads don’t work well for low frequencies by design, this is something that’s worth to be mentioned in docs, but isn’t really an error per se. Possible numeric problems due to denormals only happen at runtime, so we can’t detect it when compiling a patch.

1 Like