# Ambisonics
Spatial audio based on spherical harmonics.
# 1 Order
Higher order gives better spatial fidelity.
Order N needs (N+1)2 channels.
# 1.1 Order 0
- W (monophonic)
# 1.2 Order 1
Order 0 plus
- Y (positive left, negative right)
- Z (positive up, negative down)
- X (positive front, negative back)
# 1.3 Order N
Order N-1 plus
- 2N+1 degree N polynomials in x, y, z.
# 2 Encoding
Let x,y,z be components of unit direction vector towards source sound. Then each channel weight is formed of a polynomial in x,y,z. The weight is multiplied by the monophonic sound waveform.
There are various channel ordering and normalization conventions, this one uses AmbiX.
# 2.1 Encoder In C
Formulas copy/pasted from:
May have transcription errors…
void encode(float *w, int order, float x, float y, float z)
{
float x2, y2, z2, x4, y4, z4, x6, y6, z6;
if (order >= 0)
{
w[0] = 1;
}
if (order >= 1)
{
w[1] = y;
w[2] = z;
w[3] = x;
}
if (order >= 2)
{
x2 = x * x;
y2 = y * y;
z2 = z * z;
w[4] = sqrtf(3) * x * y;
w[5] = sqrtf(3) * y * z;
w[6] = 0.5 * (3 * z2 - 1);
w[7] = sqrtf(3) * x * z;
w[8] = 0.5 * sqrtf(3) * (x2 - y2);
}
if (order >= 3)
{
w[ 9] = sqrtf(5./8.) * y * (3 * x2 - y2);
w[10] = sqrtf(15) * x * y * z;
w[11] = sqrtf(3./8.) * y * (5 * z2 - 1);
w[12] = 0.5 * z * (5 * z2 - 3);
w[13] = sqrtf(3./8.) * x * (5 * z2 - 1);
w[14] = sqrtf(15./4.) * z * (x2 - y2);
w[15] = sqrtf(5./8.) * x * (x2 - 3 * y2);
}
if (order >= 4)
{
x4 = x2 * x2;
y4 = y2 * y2;
z4 = z2 * z2;
w[16] = sqrtf(35./4.)*x*y*(x2-y2);
w[17] = sqrtf(35./8.)*y*z*(3*x2-y2);
w[18] = sqrtf(5./4.)*x*y*(7*z2-1);
w[19] = sqrtf(5./8.)*y*z*(7*z2-3);
w[20] = 1./8.*(35*z4-30*z2+3);
w[21] = sqrtf(5./8.)*x*z*(7*z2-3);
w[22] = sqrtf(5./16.)*(x2-y2)*(7*z2-1);
w[23] = sqrtf(35./8.)*x*z*(x2-3*y2);
w[24] = sqrtf(35./64.)*(x4-6*x2*y2+y4);
}
if (order >= 5)
{
w[25] = sqrtf(63./128.)*y*(5*x4-10*x2*y2+y4);
w[26] = sqrtf(315./4.)*x*y*z*(x2-y2);
w[27] = sqrtf(35./128.)*y*(y4-2*x2*y2-3*x4-8*y2*z2+24*x2*z2);
w[28] = sqrtf(105./4.)*x*y*z*(2*z2-x2-y2);
w[29] = sqrtf(15./64.)*y*(x4+2*x2*y2+y4-12*x2*z2-12*y2*z2+8*z4);
w[30] = 1./8.*z*(63*z4-70*z2+15);
w[31] = sqrtf(15./64.)*x*(x4+2*x2*y2+y4-12*x2*z2-12*y2*z2+8*z4);
w[32] = sqrtf(105./16.)*z*(2*x2*z2-2*y2*z2-x4+y4);
w[33] = sqrtf(35./128.)*x*(2*x2*y2+8*x2*z2-24*y2*z2-x4+3*y4);
w[34] = sqrtf(315./64.)*z*(x4-6*x2*y2+y4);
w[35] = sqrtf(63./128.)*x*(x4-10*x2*y2+5*y4);
}
if (order >= 6)
{
x6 = x2 * x4;
y6 = y2 * y4;
z6 = z2 * z4;
w[36] = 1./8*sqrtf(231./2)*x*y*(3*x4-10*x2*y2+3*y4);
w[37] = 3./8*sqrtf(77./2)*y*z*(5*x4-10*x2*y2+y4);
w[38] = 3./4*sqrtf(7)*x*y*(-x4+y4 +10*x2*y2-10*y2*z2);
w[39] = 1./8*sqrtf(105./2)*y*z*(-9*x4+3*y4-6*x2*y2+24*x2*z2-8*y2*z2);
w[40] = 1./8*sqrtf(105./2)*x*y*(x4+y4+16*z4+2*x2*y2-16*x2*z2-16*y2*z2);
w[41] = 1./8*sqrtf(21)*y*z*(5*x4+5*y4+8*z4+10*x2*y2-20*x2*z2-20*y2*z2);
w[42] = 1./16*(231*z6-315*z4+105*z2-5);
w[43] = 1./8*sqrtf(21)*x*z*(5*x4+5*y4+8*z4+10*x2*y2-20*x2*z2-20*y2*z2);
w[44] = 1./16*sqrtf(105./2)*(x6-y6+x4*y2-x2*y4-16*x4*z2+16*x2*z4+16*y4*z2-16*y2*z4);
w[45] = 1./8*sqrtf(105./2)*x*z*(-3*x4+6*x2*y2+8*x2*z2-24*y2*z2+9*y4);
w[46] = 3./16*sqrtf(7)*(-x6+5*x4*y2+10*x4*z2+5*x2*y4+10*y4*z2-y6-60*x2*y2*z2);
w[47] = 3./8*sqrtf(77./2)*x*z*(5*y4-10*x2*y2+x4);
w[48] = 1./16*sqrtf(231./2)*(x6-15*x4*y2+15*x2*y4-y6);
}
if (order >= 7)
{
assert(! "high order ambisonics implemented");
abort();
}
}
# 3 Decoding
Multi-channel Ambisonic signals can be decoded to whichever speaker layout you have at hand.
Making a decoder is non-trivial:
https://bitbucket.org/ambidecodertoolbox/adt
Using ADT I made a simple binaural decoder.