Phase-Shifting at Specified Frequency?

I know that the Allpass uGens use delay time for its calculations - but I’m wondering what it would take to do phase shifting at specific frequencies? Is this something that would be better served with a different object? Is at as simple as just putting 1/freq in the delayTime argument of Allpass?

If I take your question literally, it’s possible to design an allpass filter whose Fourier transform is 1 at all frequencies except for a band where it’s a different unit complex number. But much like sinc filters, such filters are IIR, non-causal, and almost certainly do not admit a simple implementation, so they would have to be approximated, and computing such approximations is quite a difficult problem.

However, looking at a filter in terms of “phase shift” is not very intuitive or musical. An ordinary delay line is a “phase shift,” and so is multiplying a signal by -1. It’s more musical to think of an allpass as a frequency-dependent delay, i.e. group delay. The standard first-order allpass filter (which you can implement with FOS with FOS.ar(sig, k * -1, 1, k), no sc3-plugins required) can get you higher group delay for some frequencies than others. The second-order allpass filter (which I don’t have on hand but is described as “APF” in the EQ cookbook, so you can whip it up with SOS), if memory serves, has a bell-shaped group delay that’s close to 0 for most frequencies and peaks at some specified cutoff frequency.

I hope that answers something — it would help to know what kind of sound you’re trying to get here.

Sorry to ask a related question. Since SOS is being discussed:

  1. am I wrong in noticing that b and a are backwards between the cookbook and SOS?

  2. why do the cookbook formulas blow up below around 700hz (both HPF and LPF) with SOS? or am I messing something up?

//the the volume down. it isn't deadly, but it does blow up:
//LPF
({
	var sr = SampleRate.ir;
	var freq = MouseX.kr(20,10000).poll;
	var q = 5;

	var omega = 2pi*(freq/sr);

	var sine = omega.sin;
	var csine = omega.cos;

	var alpha = sine/(2*q);

	var b0 = (1-csine)/2;
	var b1 = 1-csine;
	var b2 = b0;
	var a0 = 1+alpha;
	var a1 = -2*csine;
	var a2 = 1-alpha;

	var sig = WhiteNoise.ar(1);

	sig = SOS.ar(sig, b0, b1, b2, a1.neg, a2.neg);
	sig.dup*0.1

}.play;
)

//HPF
({
	var sr = SampleRate.ir;
	var freq = MouseX.kr(20,10000).poll;
	var q = 5;

	var omega = 2pi*(freq/sr);

	var sine = omega.sin;
	var csine = omega.cos;

	var alpha = sine/(2*q);

	var b0 = (1+csine)/2;
	var b1 = (1+csine).neg;
	var b2 = (1+csine)/2;
	var a0 = 1+alpha;
	var a1 = -2*csine;
	var a2 = 1-alpha;

	var sig = WhiteNoise.ar(1);

	sig = SOS.ar(sig, b0, b1, b2, a1.neg, a2.neg);
	sig.dup*0.1

}.play;
)

The formula from the max gen help does not blow up:

({
	var sr = SampleRate.ir;
	var freq = MouseX.kr(20,10000);
	var q = 5;

	var omega = (freq*2pi/sr).poll;

	var sine = omega.sin;
	var csine = omega.cos;

	var alpha = sine/(2*q);

	var b0 = 1/(1+alpha);
	var a2 = ((1-csine)*0.5)*b0;
	var a0 =  a2;
	var a1 = (1-csine)*b0;
	var b1 = (-2*csine)*b0;
	var b2 = (1-alpha)*b0;

	var sig = WhiteNoise.ar(1);

	sig = SOS.ar(sig, a0, a1, a2, b1.neg,b2.neg);
	sig.dup*0.1

}.play;
)

Sam

Answering my own question. I did not divide by a0. But tulio, do notice that a and b are backwards from the cookbook.

({
	var sr = SampleRate.ir;
	var freq = MouseX.kr(20,10000).poll;
	var q = 5;

	var omega = 2pi*(freq/sr);

	var sine = omega.sin;
	var csine = omega.cos;

	var alpha = sine/(2*q);

	var b0 = (1-csine)/2;
	var b1 = 1-csine;
	var b2 = b0;
	var a0 = 1+alpha;
	var a1 = -2*csine;
	var a2 = 1-alpha;

	var sig = WhiteNoise.ar(1);

	sig = SOS.ar(sig, b0/a0, b1/a0, b2/a0, a1.neg/a0, a2.neg/a0);
	sig.dup*0.1

}.play;
)

Sam

Yeah, SOS is backwards from how DSP textbooks usually do it, and also b1 and b2 have a sign flip: SOS blowing up with K-weighting filter coefficients - #2 by nathan. It’s painful.

I recommend putting a K2A.ar on any input controls so that the filter coefficients are recomputed at audio rate. If they’re at control rate, SOS will linearly interpolate the coefficients, which I think may cause instability even if the two filters it’s interpolating between are stable (this is definitely an issue for high-order filters, but unsure about second order). If you want to do really rapid coefficient modulation like “allpass FM” then the SOS topology is inadequate. I do have a solution for this as part of a large project but it’s not ready to announce.

Well, there’s no type of sound in particular, I’m experimenting - but these descriptions help, although I might need to find a maths teacher. There’s not a “transfer functions for aged computer musicians” online course that can get me squared away in two hours, is there?

I understand that I wouldn’t be changing one single frequency’s phase, but rather an area of frequencies would be impacted. I am interested in experimenting with some types of cancellation - and maybe looking into a Frequency Shifter that could shift with a complex secondary signal instead of a sine wave.

Thanks to both of you.

Sam,

Sorry to ask a related question. Since SOS is being discussed:

  1. am I wrong in noticing that b and a are backwards between the cookbook and SOS?
    I discovered that a and b are not consistent in the literature, so
    always double-check. I started to refer to them as “forward” and
    “backwards” coefficients for myself.