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