OK… partly for fun, partly as a nice math exercise… I was curious what it would take to get Balance2 to weight the signal 75% to the left.
Because pan values increase to the right, it’s a bit easier to think of weighting the signal some percentage to the right. 75% left = 25% right, so we’ll use 0.25.
What is “25% to the right”? It means the volume allotted to the right channel is 1/4 of the total volume of both channels. If a = left channel volume and b = right channel volume, this ratio r is
r = b / (a+b)
Then:
ra + rb = b
b - rb = ra
b(1-r) = ra
b = (r/(1-r)) * a
That ‘r’ thing will be inconvenient to carry around, so let q = r / (1-r). (Also notice that r == 1 will be a problem – easy to handle as a special case, but worth noting.)
From the earlier post, Balance2 uses cos(x) as a falling function for the left channel fadeout as x rises, and sin(x) as a rising function for the right channel. So a = cos x and b = sin x. ‘x’, for now, is in radians, ranging 0 to 0.5pi – this is 0, up to the crest of a sine wave.
b = q * a
sin x = q * cos x
It would be helpful to get cos x in terms of sin x. There’s a trigonometric identity sin2 x + cos2 x = 1, so cos2 x = 1 - sin2 x. First square:
(sin x)^2 = q^2 * (cos x)^2
Then:
(sin x)^2 = q^2 * (1 - (sin x)^2)
(sin x)^2 = q^2 - q^2 (sin x)^2
(sin x)^2 + q^2 (sin x)^2 = q^2
(sin x)^2 * (1 + q^2) = q^2
(sin x)^2 = q^2 / (1 + q^2)
Unsquare:
sin x = sqrt(q^2 / (1 + q^2)) = q / sqrt(1 + q^2)
So the angle x should be the arcsin of q / sqrt(1 + q.squared). Again, this is 0 to 0.5pi. We need to map this onto a bipolar panning range for Balance2. Target range 2 / source range 0.5pi = 4/pi so first do x / 0.25pi, then add subtract 1.
(
f = { |r|
var q;
r = r.clip(0, 1);
if(r == 1) {
1
} {
q = r / (1 - r);
asin(q / sqrt(1 + q.squared)) / 0.25pi - 1
}
};
)
So the pan value for Balance2, which should result in a 75-25% split, is about -0.590334 (which is rather far from -0.75).
Let’s test:
(
a = {
var unity = DC.kr(1);
var trig = Impulse.kr(0);
var stereo = Balance2.kr(unity, unity, f.(0.25)).poll(trig);
(stereo[1] / stereo.sum).poll(trig);
FreeSelf.kr(trig <= 0);
Silent.ar(1)
}.play;
)
UGen Array [0]: 0.948804
UGen Array [1]: 0.315866
UGen(BinaryOpUGen): 0.249761
So the quotient of the right channel volume over the total is, allowing for rounding error, certainly close enough to the desired ratio = 0.25.
That was a bit deeper dive than I expected – but a useful bit of math to have around.
hjh