summaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2022-05-25 16:33:27 +0200
committerLars Knoll <lars.knoll@qt.io>2022-05-31 11:31:29 +0200
commitbfec5416903d664a9143d4c0fe7145702ffc3f38 (patch)
treec19e831126d5ab5661b2c84c9fa81799721ef0b4 /util
parent0199157dbcbe71ef6af195114b9330d7e0520cb6 (diff)
Fix the data to decode ambisonic to surround speaker arrays
Use the correct channel order and normalization of the ambisonic channels. Resonance Audio expects Ambix compatible ordering (ie. ACN channel order) and normalization (SN3D). Specify that we want that ordering in the script generating the speaker data and normalize the factors correctly to SN3D. Add hand coded handling for Mono, Stereo, 2Dot1, 3Dot0 and 3Dot1 speaker configurations as those do not cover the area behind the listener and thus don't really qualify as a surround configuration. Change-Id: I905ddaa81938df918a460a7dea0526444836cdff Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'util')
-rw-r--r--util/adt_generate_qt.m52
1 files changed, 22 insertions, 30 deletions
diff --git a/util/adt_generate_qt.m b/util/adt_generate_qt.m
index 45b3dcd03..8bb9497d3 100644
--- a/util/adt_generate_qt.m
+++ b/util/adt_generate_qt.m
@@ -98,34 +98,6 @@ function adt_generate_qt()
fprintf(outfile, "\n\n");
fprintf(outfile, "QT_BEGIN_NAMESPACE\n\n");
- % cover top/bottom and back for mono and stereo
- imag_speakers = [0,0,radius; 0,0,-radius; 0,radius,0; 0,-radius,0; -radius,0,0];
-
- % Mono, one speaker up front
- S = ambi_spkr_array(...
- ... % array name
- 'mono', ...
- ... % coordinate codes, unit codes
- ... % Azimuth, Elevation, Radius; Degrees, Degrees, Meters
- 'AER', 'DDM', ...
- ... % speaker name, [azimuth, elevation, radius]
- 'C', [ 0, 0, radius] ...
- );
- createDecoders(S, imag_speakers, outfile);
-
- % Stereo, assume -30 and 30 degree speakers
- S = ambi_spkr_array(...
- 'stereo', ...
- 'AER', 'DDM', ...
- 'L', [ 30, 0, radius], ...
- 'R', [ -30, 0, radius] ...
- );
- createDecoders(S, imag_speakers, outfile);
-
- S.lfeRow = 3;
- S.name = "2dot1";
- createDecoders(S, imag_speakers, outfile);
-
% cover top/bottom for surround
imag_speakers = [0,0,radius; 0,0,-radius];
@@ -197,6 +169,24 @@ function writeLFERow(outfile, m, suffix)
fprintf(outfile, "// LFE\n");
end
+function [n, m] = getnm(l)
+% Computes spherical harmonic degree and order from Ambisonic Channel Number.
+ n = floor(sqrt(l));
+ m = l-n.^2-n;
+end
+
+function channels = normalizeSN3D(channels)
+ for i = 1:columns(channels)
+ [n, m] = getnm(i-1);
+ if (m == 0)
+ factor = 1;
+ else
+ factor = sqrt(2 * factorial(n - abs(m)) / (factorial(n + abs(m))));
+ endif
+ channels(i) *= factor;
+ endfor
+end
+
function writeMatrix(outfile, level, S, M, suffix)
m = trimMatrix(M);
hasLFE = isfield(S, "lfeRow");
@@ -208,7 +198,8 @@ function writeMatrix(outfile, level, S, M, suffix)
fprintf(outfile, "// Decoder matrix for %s, ambisonic level %d\n", S.name, level);
fprintf(outfile, "static constexpr float decoderMatrix_%s_%d_%s[%d*%d] = {\n", S.name, level, suffix, r, c);
for i = 1:rows(S.id)
- fprintf(outfile, "%ff, ", m(i, :));
+ channels = normalizeSN3D(m(i, :))
+ fprintf(outfile, "%ff, ", channels);
fprintf(outfile, "// %s\n", S.id(i, 1){1});
if (hasLFE && S.lfeRow == i + 1)
writeLFERow(outfile, m, suffix);
@@ -218,7 +209,8 @@ function writeMatrix(outfile, level, S, M, suffix)
end
function createOneDecoder(S, imag_speakers, outfile, level)
- [D,S,M,C] = ambi_run_allrad(S, level, imag_speakers, [S.name '_' int2str(level)], false, "amb", 1, 3);
+ ambi_order = ambi_channel_definitions_convention(level, 'ambix2011')
+ [D,S,M,C] = ambi_run_allrad(S, ambi_order, imag_speakers, [S.name '_' int2str(level)], false, "amb", 1, 3);
writeMatrix(outfile, level, S, M.lf, "lf");
m = ambi_apply_gamma(M.hf, D.hf_gains, C);
writeMatrix(outfile, level, S, m, "hf");