0
$\begingroup$

I am working with a STFT spectral processing toolkit I wrote in C, now focusing on a module for spectral filtering. In its first implementation, the module simply multiplied an user drawn spectral envelope (made of magnitudes only, i.e all phases set to zero) by the incoming spectral frames.

Unfortunately I recently realized (being the whole framework intended for music usage) that with certain shapes I get an annoying signal distortion. After investigating (I had not a formal training in digital filters, so be gentle please...) I understood the cause of the problem.

The issue can be seen in two different ways but they are likely two sides of a same money. Simply I create peak distortion. Since in DFT peaks usually share many bins (more so if using a low frame resolution), multiplying the spectrum by a curve can alter/distort the peak shape if too abrupt, causing all possible artifacts.

Another way of seeing the problem is that even by multiplying the spectrum by a real filter curve (i.e with zeroed imaginaries) I generate an unwanted circular convolution.

Focusing on the first way of seeing the problem as I described above, I invented a trick: I identify every peak and copy it entirely to destination by scaling it of a same amount dictated by the filter curve value at its tip. This trick does wonders, but fails miserably in presence of overlapping peaks, i.e two or many peaks merging in a single apparent peak (this happens often when using frame sizes < 2048 or so, as one often has to do to reduce latency, and/or in presence of very low frequency harmonic signals. I posted another question here at this proposal about detecting overlapping peaks btw).

So I had to try another approach aimed at avoiding circular convolution - please read on, this will be my actual question.

I used an overlap-save approach: both the input and the filter spectra are doubled in size and zero padded on the right, to allow room for ringing, i.e to create a proper linear convolution which won't go wrap at the opposite end. As a premise, I discovered experimentally that I had to shift the filter kernel by half frame for proper results and to warrant an impulse response centered at the impulse itself (I never found this fact mentioned anywhere btw... strange). The method would work as expected without causing peak distortions but now I am facing an unexpected comb filter effect. After further investigation, I discovered the culprit: many filter spectral shapes produce kernels which don't fade to zero at their ends but which are either solid (non fading) sinusoidal blocks or have a kind of dc offset (look like truncated, as if they needed a larger framesize) Such "truncated" kernels will naturally produce a comb filtering effect.

What else I am ignoring here ? Is actually spectral filtering a so complex task to accomplish ? Any suggestion or elaboration is welcome. Thanks.

Addition: I have the intuition that I should perhaps apply a window (like a rised cosine) to the kernel to get rid of this annoyance, to have it fading gently to zero at its ends..

$\endgroup$
  • 2
    $\begingroup$ hi! This seems to be rather comprehensive work. Would you mind inserting empty lines to your question to mark logical paragraphs? It would most definitely make this more welcoming to read :) Content-wise, this sounds very interesting! $\endgroup$ – Marcus Müller Jan 13 at 16:27
  • $\begingroup$ I am sorry but all my newlines were rejected dunno why... let me try to edit it if I can... $\endgroup$ – elena Jan 14 at 11:14
  • $\begingroup$ This looks a lot easier to read now! Thanks! $\endgroup$ – Marcus Müller Jan 14 at 12:12
0
$\begingroup$

Have you seen the Spectral Filter supplied in the M4L Pluggo for Live packs in Ableton? It may be worth testing signals with both your implementation and that one to see whether these distortions you talk about are normal. You'll probably make more progress this way as only you really know what you're implementation is.

You will also be able to open the Max patch and infer some info on how they made it:

enter image description here

$\endgroup$
  • $\begingroup$ I have not Ableton to test but I can say that Reaper spectral filter and other VST spectral filters I tried ALL HAVE THE SAME PROBLEM! They likely do the job as I did i.e the "naive" way, by simply multiplying spectral frames by the frequency response spectrum,.leading to the same distortion. $\endgroup$ – elena Jan 15 at 13:35
  • $\begingroup$ Now at least I know how to implement it "the correct way" without generating artifacts, with the only limitation that the smaller the frame size used, the less faithful the intended frequency response will be (which however sounds reasonable). But now I would like also to explore that other idea I have, i.e working on single peaks and scaling their whole body basing on response curve values at their tips. If I can perfection this method not to be misled by overlapping peaks, I can gain a lot in terms of simplicity of implementation (vs. a complete overlap-save scheme) and CPU efficiency. $\endgroup$ – elena Jan 15 at 13:36
0
$\begingroup$

You can try more smoothly windowing the impulse response of your filter so that it fits in half your current FFT length instead of getting sharply truncated. Or you can lengthen your FFT so the it is longer than the sum of the data window length plus however long it takes your filter's impulse response to fade low enough not to be heard. Or a combination of the two (Hann,et.al., windowed much longer filter kernel/impulse response using a longer FFT).

Try an FFT 4x or 8x longer (with extended overlap-add/save), and optimize from there if that seems to improve things.

$\endgroup$
  • $\begingroup$ Thanks..as also I suspected by mere intuition, windowing the kernel does the trick 😀 A plain rised cos window does the job. Yeah I overlooked the fact that an impulse response may need even an infinite time to fade. Of course in the theorical case one would need an infinitely large IR to do its precise and intended filtering job, with the result that working with larger frame sizes you get a more precise filter. Well ok case closed 😊 $\endgroup$ – elena Jan 15 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.