diff --git a/libtascar/include/speakerarray.h b/libtascar/include/speakerarray.h index 2c772908..b6f87470 100644 --- a/libtascar/include/speakerarray.h +++ b/libtascar/include/speakerarray.h @@ -99,6 +99,7 @@ namespace TASCAR { spk_array_t(const spk_array_t&); public: + enum dffusedecoder_t { basic, maxre, inphase }; double get_rmax() const { return rmax; }; double get_rmin() const { return rmin; }; class didx_t { @@ -116,7 +117,7 @@ namespace TASCAR { private: double rmax; double rmin; - float xyzgain; + dffusedecoder_t diffusedecoder_enum = maxre; std::string onload; std::string onunload; std::vector didx; @@ -212,8 +213,6 @@ namespace TASCAR { // lowpass filters for subwoofer (24 dB/Oct): std::vector flt_lowp1; std::vector flt_lowp2; - // allpass filters for transition phase matching, broad band speakers: - //std::vector flt_allp; std::vector> subweight; std::vector convolution_ir; //< file name of impulse response for convolution diff --git a/libtascar/src/speakerarray.cc b/libtascar/src/speakerarray.cc index 81a439bd..b65f84ea 100644 --- a/libtascar/src/speakerarray.cc +++ b/libtascar/src/speakerarray.cc @@ -79,7 +79,7 @@ spk_array_cfg_t::~spk_array_cfg_t() spk_array_t::spk_array_t(tsccfg::node_t e, bool use_parent_xml, const std::string& elementname_, bool allow_empty) : spk_array_cfg_t(e, use_parent_xml), elayout(e_layout), rmax(0), rmin(0), - xyzgain(1.0), elementname(elementname_), mean_rotation(0) + elementname(elementname_), mean_rotation(0) { clear(); { @@ -119,12 +119,23 @@ spk_array_t::spk_array_t(tsccfg::node_t e, bool use_parent_xml, } for(auto& sn : tsccfg::node_get_children(e_layout, elementname)) emplace_back(sn); - elayout.GET_ATTRIBUTE(xyzgain, "", "XYZ-gain for FOA decoding"); elayout.GET_ATTRIBUTE(name, "", "Name of layout, for documentation only"); elayout.GET_ATTRIBUTE(onload, "", "system command to be executed when layout is loaded"); elayout.GET_ATTRIBUTE( onunload, "", "system command to be executed when layout is unloaded"); + std::string diffusedecoder = "maxre"; + elayout.GET_ATTRIBUTE(diffusedecoder, "basic|maxre|inphase", + "Diffuse-decoder method"); + if(diffusedecoder == "maxre") + diffusedecoder_enum = maxre; + else if(diffusedecoder == "basic") + diffusedecoder_enum = basic; + else if(diffusedecoder == "inphase") + diffusedecoder_enum = inphase; + else + throw TASCAR::ErrMsg("Invalid diffuse decoder type \"" + diffusedecoder + + "\". Valid values are basic, maxre or inphase."); // if(empty() && (!allow_empty)) throw TASCAR::ErrMsg("Invalid " + elementname_ + " array (no " + @@ -141,13 +152,35 @@ spk_array_t::spk_array_t(tsccfg::node_t e, bool use_parent_xml, rmin = r; } } + bool isflat = true; std::complex p_xy(0); for(uint32_t k = 0; k < size(); k++) { + if(fabsf(operator[](k).unitvector.z) > 1e-6f) + isflat = false; operator[](k).spkgain *= operator[](k).norm() / rmax; operator[](k).dr = rmax - operator[](k).norm(); p_xy += std::exp(-(double)k * TASCAR_2PI * i / (double)(size())) * (operator[](k).unitvector.x + i * operator[](k).unitvector.y); } + // calculate xyzgain according to Daniel (2001), table 3.10: + double xyzgain = 1.0; + switch(diffusedecoder_enum) { + case basic: + xyzgain = 1.0; + break; + case maxre: + if(isflat) + xyzgain = sqrt(0.5); + else + xyzgain = 0.577; + break; + case inphase: + if(isflat) + xyzgain = 0.5; + else + xyzgain = 1.0/3.0; + break; + } mean_rotation = std::arg(p_xy); didx.resize(size()); for(uint32_t k = 0; k < size(); ++k) { diff --git a/manual/manual.tex b/manual/manual.tex index ce059b03..9fcadf3c 100644 --- a/manual/manual.tex +++ b/manual/manual.tex @@ -1181,7 +1181,7 @@ \subsection{The {\tt } element}\label{sec:receiver}\index{receive first order Ambisonics signal of the $l$-th diffuse sound field; $L$ is the number of all diffuse sound fields, including diffuse reverberation inputs. -For all loudspeaker-based receiver types, $D$ is a first order Ambisonics decoder matrix, with optional loudspeaker density compensation and decorrelation filters. To get a $\max rE$-decoder, set the \indattr{xyzgain} attribute to 0.707 for regular horizontal loudspeaker layouts and to 0.577 for regular 3D loudspeaker layouts. For Ambisonics based receiver types, $D$ is a diagonal matrix. By default, the decoded output of the first order Ambisonics rendering is de-correlated using FIR all-pass filters to achieve diffuse sound fields and avoid coloration artifacts (see \indattr{decorr} and \indattr{decorr\_length} for details). +For all loudspeaker-based receiver types, $D$ is a first order Ambisonics decoder matrix, with optional loudspeaker density compensation and decorrelation filters. By default, a $\max rE$-decoder is used. The order gain $g_{xyz}$ is set according to Table 3.10 of \citet{Daniel2001}. A loudspeaker layout is assumed to reproduce in 3D when at least one loudspeaker has non-zero elevation. For Ambisonics based receiver types, $D$ is a diagonal matrix. By default, the decoded output of the first order Ambisonics rendering is de-correlated using FIR all-pass filters to achieve diffuse sound fields and avoid coloration artifacts (see \indattr{decorr} and \indattr{decorr\_length} for details). Figure \ref{fig:renderer} presents the typical connections in \tascar{} and may help to visualize the role of the receiver. diff --git a/test/36ch.spk b/test/36ch.spk index b121ceaf..7d361a0d 100644 --- a/test/36ch.spk +++ b/test/36ch.spk @@ -1,5 +1,5 @@ - + diff --git a/test/4ch.spk b/test/4ch.spk index 3842d303..9d5f484f 100644 --- a/test/4ch.spk +++ b/test/4ch.spk @@ -1,5 +1,5 @@ - + diff --git a/test/4ch_decorr.spk b/test/4ch_decorr.spk index 1f55f1ba..84b148f5 100644 --- a/test/4ch_decorr.spk +++ b/test/4ch_decorr.spk @@ -1,5 +1,5 @@ - + diff --git a/test/4ch_nodecorr.spk b/test/4ch_nodecorr.spk index 339aac07..8df748a1 100644 --- a/test/4ch_nodecorr.spk +++ b/test/4ch_nodecorr.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch.spk b/test/8ch.spk index 0a242194..2804e98a 100644 --- a/test/8ch.spk +++ b/test/8ch.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch_calib.spk b/test/8ch_calib.spk index ad918e54..6441427c 100644 --- a/test/8ch_calib.spk +++ b/test/8ch_calib.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch_diffuse.spk b/test/8ch_diffuse.spk index 0a43eace..e7026354 100644 --- a/test/8ch_diffuse.spk +++ b/test/8ch_diffuse.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch_diffuse_zero.spk b/test/8ch_diffuse_zero.spk index 1c666cdf..4c529e56 100644 --- a/test/8ch_diffuse_zero.spk +++ b/test/8ch_diffuse_zero.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch_nodecorr.spk b/test/8ch_nodecorr.spk index cd9eceb7..3af667ec 100644 --- a/test/8ch_nodecorr.spk +++ b/test/8ch_nodecorr.spk @@ -1,5 +1,5 @@ - + diff --git a/test/8ch_sub.spk b/test/8ch_sub.spk index 21a26e5f..e384caea 100644 --- a/test/8ch_sub.spk +++ b/test/8ch_sub.spk @@ -1,5 +1,5 @@ - + diff --git a/test/expected_snd_diffuse_maxre.wav b/test/expected_snd_diffuse_maxre.wav index 89bf6170..7367b8b6 100644 Binary files a/test/expected_snd_diffuse_maxre.wav and b/test/expected_snd_diffuse_maxre.wav differ diff --git a/test/irreg.spk b/test/irreg.spk index 88b8f075..7cb8c7c4 100644 --- a/test/irreg.spk +++ b/test/irreg.spk @@ -1,5 +1,5 @@ - + diff --git a/test/lidhan_3d.spk b/test/lidhan_3d.spk index 63b169e8..7c527b7a 100644 --- a/test/lidhan_3d.spk +++ b/test/lidhan_3d.spk @@ -1,5 +1,5 @@ - + diff --git a/test/lidhan_3d45.spk b/test/lidhan_3d45.spk index 75b18333..1b5925c4 100644 --- a/test/lidhan_3d45.spk +++ b/test/lidhan_3d45.spk @@ -1,5 +1,5 @@ - + diff --git a/test/lidhan_3d45_sub.spk b/test/lidhan_3d45_sub.spk index b788ad6b..5e794655 100644 --- a/test/lidhan_3d45_sub.spk +++ b/test/lidhan_3d45_sub.spk @@ -1,5 +1,5 @@ - + diff --git a/test/test_snd_diffuse_basic.tsc b/test/test_snd_diffuse_basic.tsc index 554a57fd..740f4c27 100644 --- a/test/test_snd_diffuse_basic.tsc +++ b/test/test_snd_diffuse_basic.tsc @@ -10,7 +10,7 @@ - + diff --git a/test/test_snd_diffuse_inphase.tsc b/test/test_snd_diffuse_inphase.tsc index 44835c42..2feed5ed 100644 --- a/test/test_snd_diffuse_inphase.tsc +++ b/test/test_snd_diffuse_inphase.tsc @@ -10,7 +10,7 @@ - + diff --git a/test/test_snd_diffuse_maxre.tsc b/test/test_snd_diffuse_maxre.tsc index 997ec58d..3b674fbb 100644 --- a/test/test_snd_diffuse_maxre.tsc +++ b/test/test_snd_diffuse_maxre.tsc @@ -10,7 +10,7 @@ - + diff --git a/test/vbap6.spk b/test/vbap6.spk index a59d2eea..e8146596 100644 --- a/test/vbap6.spk +++ b/test/vbap6.spk @@ -1,5 +1,5 @@ - +