LPF with a cutoff that goes straight down

I’ve been wondering if it is possible to cutoff a band of frequencies with a straight and vertical line. I mean that if you’d set the cutoff frequency to 200, then even the frequency 201 would be completely cut off. Im asking because i’d like to for example only hear the low pitched aliasing artifacts of a LFSaw oscillator and completely filter out all higher frequencies that are not mirrored back. I’ve tried something like this to make the cutoff steeper. {LPF.ar(LPF.ar(LPF.ar(LPF.ar(LFSaw.ar(MouseY.kr(2600,2900)),1045),1045),1045),1045)!2;}.play;
Should i just continue nest LPF’s until the cutoff is completely vertical or are there better ways to do this?

This is more of a job for FFT / PV_BrickWall. LPFs will never give you a vertical cutoff - you’d need an infinite number for an infinite slope.

@Aueh, the SignalBox quark includes a rectangular windowed sinc design method. The returned Signal can be further windowed to smooth out the lowpass roll off. (One of my favorites is the Kaiser Window.)

To filter a sound, load this filter kernel into a Buffer, and supply to Convolution2.

Also of interest, SignalBox’s *gaussianBank will return a collection of matched linear phase kernels that can be used to filter a signal into selected frequency bands. Supplying a single frequency will return a matched low/highpass pair. An Array with more will give a collection of bandbass filters along with low and highpass to complete the decomposition. (Fun!)

As @nathan states, the cost is a much higher CPU hit… but sometimes you need to pay the price for a super selective filter.

2 Likes

You can try miSCellaneous_lib’s PV_BinRange. It’s a wrapper based on PV_BrickWall, where you pass low and high bin, calculation from frequencies is straight, see helpfile example (have in mind the inherent flaws mentioned by Nathan). Also, there’s the BandSplitter quark.

To illustrate:

(
a = {
	// using a 512-point fft buffer, bins are spaced...
	var n = 512;
	var hzPerBin = SampleRate.ir / n;
	// the nearest bin to 440 Hz is...
	var freq = 440;
	var bin440 = round(freq / hzPerBin);
	var nearestFreq = bin440 * hzPerBin;
	// modulate frequency within a P5 around that
	// upper frequencies should be cut out completely
	// lower frequencies basically pass through
	// just near the brickwall, massive harmonic distortion
	var sig = SinOsc.ar(
		nearestFreq * LFTri.kr(0.2).exprange(-7.midiratio, 7.midiratio)
	);
	var fft = FFT(LocalBuf(n, 1), sig);
	fft = PV_BrickWall(fft, (bin440 / n) * 2 - 1);
	(IFFT(fft) * 0.2).dup
}.play;
)

“BrickWall” is something of a misleading name. It suggests that you get full-strength content very, very, very close to the cutoff, and suddenly 0 amplitude past that point. The actual sound is nothing like that. (I’ve deliberately used a small FFT frame to exaggerate the effect. With a larger frame, the effect would be compressed into a narrower frequency range, but the artifacts will never go away.)

For the original question, given an LFSaw frequency and a sample rate, it should be possible to calculate the aliased frequencies and their amplitudes, and synthesize them additively.

hjh

So many suggestions and ideas; again i’ve learned alot as a beginner. Thanks all!

I cant seem to perfectly match them. This is as close as i can get.

{[LFSaw.ar(-200,1), Saw.ar(200,2)]}.plot(0.5);

But when i subtract them there is still alot of sound.

So just a question, so i can try to build the artifacts myself. An aliasing ugen will mirror back anything over 22khz(judging from the freqscope window)? And they will be mapped back like this: 22001—>21999, 22002 —> 21998 etc. I dont know how the amplitudes are mapped. To be honest i dont know anything about how aliasing is done in supercollider. Is there any place where i can read up on this?

Cool i was also looking for something like that!

… mirror back anything over half the sampling rate. At 44.1 kHz, this is 22050.

You can use .fold(0, s.sampleRate * 0.5) to get from a calculated too-high frequency to its aliased equivalent.

hjh