Files
JustOneCacophony/docs/binaural.md
T

10 KiB
Raw Blame History

JustOneCacophony — 双耳渲染数学

English · 返回 README

本文说明 pcm16 + ID11/OAMD → stereo 路径中的计算、状态和时间对齐。双耳渲染直接接在对象重建之后,不经过 ADM BWF 或 AXML。

1. 总体路径与记号

pcm16:LFE + 15 路对象 PCM
  → 64-band QMF analysis
  → 77-band hybrid analysis
  → 逐对象方向、距离、双耳传递函数和 room send
  → 对象累加 + room network
  → hybrid synthesis
  → QMF synthesis
  → 961-sample 延迟补偿
  → stereo WAV

主要记号:

符号 含义
s=0\ldots15 输入源;s=0 为 LFE,s=1\ldots15 为对象
e\in\{L,R\} 左右输出耳
p=0\ldots63 QMF phase / 时域 hop 内采样
k=0\ldots63 QMF 子带
h=0\ldots76 hybrid 子带
j=0\ldots35 方向 basis 项
m 64-sample QMF 时槽
n 时域采样位置

每个 QMF hop 为 64 samples,每个双耳控制块为


N_b=512=8\times64,

每个 E-AC-3/JOC 音频帧为


N_f=1536=3N_b.

2. 输入与控制块

输入矩阵为


x_s[n],\qquad s=0\ldots15.

pcm16 的通道约定为:

ch0      special LFE
ch1..15  JOC 对象 1..15

渲染器按连续采样流推进。QMF、hybrid、room 和 synthesis 状态不会在 1536-sample 帧边界清零。

3. 64-band QMF analysis

令 a_{p,\ell} 为固定的 64×10 polyphase 系数,r_{s,\ell,p}[m] 为当前和前 9 个 hop 的 phase 历史。奇偶 lag 分别累加:


E_{s,p}[m]
=\sum_{\substack{\ell=0\\\ell\text{ even}}}^{9}
a_{p,\ell}r_{s,\ell,p}[m],

O_{s,p}[m]
=\sum_{\substack{\ell=0\\\ell\text{ odd}}}^{9}
a_{p,\ell}r_{s,\ell,p}[m].

对任一 64-vector $v[p]$,定义调制变换


\mathcal Q(v)_k
=
\operatorname{FFT}_{128}
\left(
\left[v[p]e^{-j\pi p/128}\right]_{p=0}^{63},
0_{64}
\right)_k

e^{-j3\pi(k+1/2)/128}.

analysis 输出为


X_{s,k}[m]
=
\mathcal Q(O_s)_k
+j(-1)^k\mathcal Q(E_s)_k.

所有历史、乘加和 FFT 结果使用 float64/complex128。

4. 77-band hybrid analysis

低 3 个 QMF 子带使用 13-slot FIR 拆分为 16 个 hybrid bands。把复数的实部和虚部分量记为 $i,o\in{0,1}$,固定核为 $K_{p,i,\ell,h,o}$:


H_{s,h,o}[m]
=
\sum_{p=0}^{2}
\sum_{i=0}^{1}
\sum_{\ell=0}^{12}
X_{s,p,i}[m-\ell]K_{p,i,\ell,h,o},
\qquad h=0\ldots15.

其余 61 个 hybrid bands 是 QMF 3..63 的 6-slot 延迟:


H_{s,16+q}[m]=X_{s,3+q}[m-6],
\qquad q=0\ldots60.

因此 hybrid vector 的顺序为:

0..15   低 3 个 QMF bands 的细分
16..76  延迟后的 QMF bands 3..63

5. OAMD 坐标与时间轴

5.1 Q15 坐标到 Cartesian

对象状态中的 q_1,q_2,q_3 先恢复到离散位置网格:


u_1=\min\left(1,\frac{\operatorname{round}(62q_1/32767)}{62}\right),

u_2=\min\left(1,\frac{\operatorname{round}(62q_2/32767)}{62}\right),

u_3=\operatorname{clip}\left(
\frac{\operatorname{round}(15q_3/32767)}{15},-1,1\right).

ADM Cartesian 坐标为


(X,Y,Z)=(2u_1-1,\ 1-2u_2,\ u_3).

5.2 更新时间

一条位置更新的编码时刻为


n_{\mathrm{coded}}
=n_{\mathrm{frame}}
+n_{\mathrm{outer}}
+n_{\mathrm{block}}.

首个有效状态作为 sample 0 的初始位置。后续更新加入对象 PCM 延迟 $D_o$,默认


D_o=1473.

若 ramp duration 为 $R>64$,连续运动为


n_{\mathrm{start}}=n_{\mathrm{coded}}+D_o+64,

R_{\mathrm{eff}}=R-64,

\mathbf p[n]
=(1-\alpha)\mathbf p_0+\alpha\mathbf p_1,
\qquad
\alpha=\frac{n-n_{\mathrm{start}}}{R_{\mathrm{eff}}}.

当 R\le64 时,目标位置在 n_{\mathrm{coded}}+D_o 直接生效。

Rosella 参数在每个 512-sample block 起点求值,并用于该块的 8 个 hybrid slots。

6. 距离 profile 与方向

普通对象只使用 Near、Mid、Far 三个 profile。每个 profile 包含:

  • 三轴负/正边界 $b_{x-},b_{x+},b_{y-},b_{y+},b_{z-},b_{z+}$;
  • 距离尺度 D 和倒数尺度 $D^{-1}$;
  • 三轴内部尺度 $a_x,a_y,a_z$;
  • 最小归一化半径 $\rho_{\min}$。

Cartesian 坐标经过 Q15 metadata grid 后换成内部前、侧、上轴,乘以 profile 尺度:


\mathbf s=(a_zq_f,\ a_xq_l,\ a_yq_v).

若射线超出 profile 边界,则用单一比例 \lambda\le1 缩放:


\mathbf s' = \lambda\mathbf s.

随后


\rho=\|\mathbf s'\|_2,
\qquad
\rho_c=\max(\rho,\rho_{\min}),
\qquad
\alpha=\frac{\rho}{\rho_c},

\mathbf d=
\begin{cases}
\mathbf s'/\rho,&\rho>0,\\
(1,0,0),&\rho=0,
\end{cases}

物理半径为


R=D\rho.

7. 36 项方向 basis

方向 \mathbf d=(x,y,z) 被展开为 36 项实值多项式:


\mathbf b(\mathbf d)=
[1,x,y,z,x^2-\tfrac13,xy,xz,y^2-\tfrac13,yz,\ldots]^T.

完整顺序由 rosella_model.direction_basis() 固定。最高次数为 5;所有 field 系数必须按该顺序点积,不能交换 basis 项。

逐耳 basis 会根据耳偏移重新归一化。令耳偏移标量为 $e$:


\epsilon=\frac{eD^{-1}}{\rho_c},

\mathbf d_-=
\frac{(x,y-\epsilon,z)}{\|(x,y-\epsilon,z)\|_2},
\qquad
\mathbf d_+=
\frac{(x,y+\epsilon,z)}{\|(x,y+\epsilon,z)\|_2}.

8. 逐耳路径与 ITD

归一化路径长度为


\ell_-=\rho_c\sqrt{x^2+(y-\epsilon)^2+z^2},

\ell_+=\rho_c\sqrt{x^2+(y+\epsilon)^2+z^2}.

模型允许通过 36-vector 对路径加入非负方向修正:


\ell'_e
=
\ell_e
+
\max(\mathbf v_e^T\mathbf b_e,0)\,2cD^{-1}.

耳间延迟为


\tau
=|\ell'_+-\ell'_-|\,D\frac{f_s}{343.3}\alpha,
\qquad f_s=48000.

路径较长的一耳应用 hybrid-band 相位:


P_h=e^{j\omega_h\tau},

其中 \omega_h 由模型的 20 个 hybrid group 参数递推到 77 个 bands。

9. 方向 field 与直达增益

左右耳各有一个 77×36 complex field:


C_{e,h}(\mathbf d_e)
=
\sum_{j=0}^{35}F_{e,h,j}b_j(\mathbf d_e).

另一次耳路径计算给出左右权重:


w_L=\frac{\ell_+}{\sqrt{\ell_-^2+\ell_+^2}},
\qquad
w_R=\frac{\ell_-}{\sqrt{\ell_-^2+\ell_+^2}}.

有效距离为


R_e=\rho\,s_dD,

其中 s_d 为模型距离标量。Mid/Far 的公共衰减和 room send 为


g_c=\frac{1}{\sqrt{1+s_rR_e^2}},

g_{\mathrm{room}}=R_eg_c.

Near 使用


g_c=1,
\qquad
g_{\mathrm{room}}=0.

令 C_{e,h}^{(0)} 为 field 的第 0 个 basis 系数,中心保护项为 $1-\alpha$。普通直达传递函数可写成


G_{L,h}
=g_c\left[C_{L,h}w_L\alpha+C_{L,h}^{(0)}c_L(1-\alpha)\right],

G_{R,h}
=g_c\left[C_{R,h}w_R\alpha+C_{R,h}^{(0)}c_R(1-\alpha)\right].

c_L,c_R 由模型的耳权重配置选择;路径较长的一耳再乘 $P_h$。

10. LFE 传递函数

LFE 不进入普通对象方向计算。其传递函数为


G_{L,h}^{\mathrm{LFE}}=G_{R,h}^{\mathrm{LFE}}=
\begin{cases}
g_h,&0\le h<16,\\
0,&16\le h<77.
\end{cases}

前 16 个固定系数为

 2.60290003,  1.80741799,  0.659342408, -0.0275855921,
-0.105803289, -0.0699509233, 0.0749056414, -0.00919809937,
 0.00349014648,-0.0158600751,-0.000723021978,0.00188189559,
-0.000421735429,0.0000329252762,0.0000317397971,0.000000580376991

LFE 的 room send 恒为 0。

11. 对象累加与 room input

每个 hybrid slot 的直达输出为


Y^{\mathrm{direct}}_{e,h}
=
\sum_{s=0}^{15}H_{s,h}G_{s,e,h}.

room 输入为


U_h
=
\sum_{s=1}^{15}H_{s,h}g_{\mathrm{room},s}.

LFE 不进入该和式。

12. Room network

room 只处理前 64 个 hybrid bands。输入先乘


g_0=0.70710677.

对每级 all-pass,设延迟样本为 $d[n]$、系数为 $a$:


r[n]=x[n]-ad[n],

y[n]=ar[n]+d[n].

all-pass 输出复制到 4 个 FDN branches。设延迟输出为 $\mathbf d_h[m]$、4×4 混合矩阵为 $M$:


\mathbf b_h[m]
=U_h[m]\mathbf 1+M\mathbf d_h[m].

每个 branch 使用复反馈系数 $f_{h,i}$:


m_{h,i}[m]=f_{h,i}b_{h,i}[m].

主 tap、可选额外 tap 和左右输出矩阵合成为


Y^{\mathrm{room}}_{e,h}[m]
=
\sum_{i=0}^{3}O_{e,h,i}z_{h,i}[m].

最终 hybrid 输出为


Y_{e,h}=Y^{\mathrm{direct}}_{e,h}+Y^{\mathrm{room}}_{e,h}.

Python 后端把该递归网络展开为有限 complex FIR 并使用 overlap-add;C++ 后端直接保持递归状态。两者均跨帧连续。

13. Hybrid synthesis

hybrid synthesis 是 154 项稀疏即时映射。令映射项为 $(h,i,k,o,w)$,其中 i,o 表示实部或虚部,则


Q_{e,k,o}[m]
\mathrel{+}=
Y_{e,h,i}[m]w.

输出是每耳 64 个 complex QMF bands。

14. QMF synthesis

每耳 QMF vector 先展开为 128 项实向量


\mathbf q_e=[\Re Q_{e,0},\Im Q_{e,0},\ldots,\Re Q_{e,63},\Im Q_{e,63}]^T.

对每个 phase p 和 rank $r=0\ldots3$:


f_{e,p,r}[m]
=\mathbf b_{p,r}^T\mathbf q_e[m].

使用 10-slot taps 合成时域样本:


y_e[64m+p]
=
\sum_{\ell=0}^{9}
\sum_{r=0}^{3}
t_{p,\ell,r}f_{e,p,r}[m-\ell].

15. 延迟、尾声和输出

完整 filterbank 的固定延迟为


L=961\ \text{samples}.

只在连续流起点丢弃一次前 L 个输出 samples。输入结束后继续送零,以释放 QMF、hybrid 和 room 状态。尾声裁切只作用于文件末端:


\max(|y_L[n]|,|y_R[n]|) > 10^{-8}

的最后一个 sample 被保留,同时输出长度不得短于源 PCM 长度。

所有内部状态、参数计算和对象累加使用 float64/complex128。最终 writer 才转换为 float32 或 PCM24。

16. Python 与 C++ 后端

两套后端共享:

  • 同一份 QMF/hybrid 固定表;
  • 同一份模型解析结果;
  • 同一套 512-sample 参数更新时间轴;
  • 同一组逐对象 complex gains 和 room sends;
  • 同一 961-sample 延迟补偿与尾声策略。

C++ 后端以 512-sample block 为处理单位,内部持有 QMF、hybrid、room 和 synthesis 状态。Python 只负责模型解析、OAMD 时间轴和每块参数更新。

17. 模型文件

默认路径为

HRTF/binaural.personalized_headphone

也可通过

--personalized-headphone PATH

指定其它文件。

.personalized_headphone 中的 int32/Q15 参数在解析后提升为 float64。任意 SOFA FIR 不能只通过数组重排变成该参数模型;若要转换,需要拟合方向 fields、ITD、距离 profile、耳几何和 room 参数。

18. 适用范围

当前路径处理 15 个普通点对象和 1 路 special LFE。对象 extent、spread、diffuse、divergence、channel lock,以及未实现的 OAMD element 变体不在本公式范围内。