nfcfilter.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. #include "config.h"
  2. #include "nfcfilter.h"
  3. #include "alu.h"
  4. /* Near-field control filters are the basis for handling the near-field effect.
  5. * The near-field effect is a bass-boost present in the directional components
  6. * of a recorded signal, created as a result of the wavefront curvature (itself
  7. * a function of sound distance). Proper reproduction dictates this be
  8. * compensated for using a bass-cut given the playback speaker distance, to
  9. * avoid excessive bass in the playback.
  10. *
  11. * For real-time rendered audio, emulating the near-field effect based on the
  12. * sound source's distance, and subsequently compensating for it at output
  13. * based on the speaker distances, can create a more realistic perception of
  14. * sound distance beyond a simple 1/r attenuation.
  15. *
  16. * These filters do just that. Each one applies a low-shelf filter, created as
  17. * the combination of a bass-boost for a given sound source distance (near-
  18. * field emulation) along with a bass-cut for a given control/speaker distance
  19. * (near-field compensation).
  20. *
  21. * Note that it is necessary to apply a cut along with the boost, since the
  22. * boost alone is unstable in higher-order ambisonics as it causes an infinite
  23. * DC gain (even first-order ambisonics requires there to be no DC offset for
  24. * the boost to work). Consequently, ambisonics requires a control parameter to
  25. * be used to avoid an unstable boost-only filter. NFC-HOA defines this control
  26. * as a reference delay, calculated with:
  27. *
  28. * reference_delay = control_distance / speed_of_sound
  29. *
  30. * This means w0 (for input) or w1 (for output) should be set to:
  31. *
  32. * wN = 1 / (reference_delay * sample_rate)
  33. *
  34. * when dealing with NFC-HOA content. For FOA input content, which does not
  35. * specify a reference_delay variable, w0 should be set to 0 to apply only
  36. * near-field compensation for output. It's important that w1 be a finite,
  37. * positive, non-0 value or else the bass-boost will become unstable again.
  38. * Also, w0 should not be too large compared to w1, to avoid excessively loud
  39. * low frequencies.
  40. */
  41. static const float B[4][3] = {
  42. { 0.0f },
  43. { 1.0f },
  44. { 3.0f, 3.0f },
  45. { 3.6778f, 6.4595f, 2.3222f },
  46. /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/
  47. };
  48. void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1)
  49. {
  50. float b_00, g_0;
  51. float r;
  52. memset(nfc, 0, sizeof(*nfc));
  53. nfc->g = 1.0f;
  54. nfc->coeffs[0] = 1.0f;
  55. /* Calculate bass-boost coefficients. */
  56. r = 0.5f * w0;
  57. b_00 = B[1][0] * r;
  58. g_0 = 1.0f + b_00;
  59. nfc->coeffs[0] *= g_0;
  60. nfc->coeffs[1] = (2.0f * b_00) / g_0;
  61. /* Calculate bass-cut coefficients. */
  62. r = 0.5f * w1;
  63. b_00 = B[1][0] * r;
  64. g_0 = 1.0f + b_00;
  65. nfc->g /= g_0;
  66. nfc->coeffs[0] /= g_0;
  67. nfc->coeffs[1+1] = (2.0f * b_00) / g_0;
  68. }
  69. void NfcFilterAdjust1(NfcFilter *nfc, const float w0)
  70. {
  71. float b_00, g_0;
  72. float r;
  73. r = 0.5f * w0;
  74. b_00 = B[1][0] * r;
  75. g_0 = 1.0f + b_00;
  76. nfc->coeffs[0] = nfc->g * g_0;
  77. nfc->coeffs[1] = (2.0f * b_00) / g_0;
  78. }
  79. void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
  80. {
  81. const float b0 = nfc->coeffs[0];
  82. const float a0 = nfc->coeffs[1];
  83. const float a1 = nfc->coeffs[2];
  84. float z1 = nfc->history[0];
  85. int i;
  86. for(i = 0;i < count;i++)
  87. {
  88. float out = src[i] * b0;
  89. float y;
  90. y = out - (a1*z1);
  91. out = y + (a0*z1);
  92. z1 += y;
  93. dst[i] = out;
  94. }
  95. nfc->history[0] = z1;
  96. }
  97. void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1)
  98. {
  99. float b_10, b_11, g_1;
  100. float r;
  101. memset(nfc, 0, sizeof(*nfc));
  102. nfc->g = 1.0f;
  103. nfc->coeffs[0] = 1.0f;
  104. /* Calculate bass-boost coefficients. */
  105. r = 0.5f * w0;
  106. b_10 = B[2][0] * r;
  107. b_11 = B[2][1] * r * r;
  108. g_1 = 1.0f + b_10 + b_11;
  109. nfc->coeffs[0] *= g_1;
  110. nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  111. nfc->coeffs[2] = (4.0f * b_11) / g_1;
  112. /* Calculate bass-cut coefficients. */
  113. r = 0.5f * w1;
  114. b_10 = B[2][0] * r;
  115. b_11 = B[2][1] * r * r;
  116. g_1 = 1.0f + b_10 + b_11;
  117. nfc->g /= g_1;
  118. nfc->coeffs[0] /= g_1;
  119. nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  120. nfc->coeffs[2+2] = (4.0f * b_11) / g_1;
  121. }
  122. void NfcFilterAdjust2(NfcFilter *nfc, const float w0)
  123. {
  124. float b_10, b_11, g_1;
  125. float r;
  126. r = 0.5f * w0;
  127. b_10 = B[2][0] * r;
  128. b_11 = B[2][1] * r * r;
  129. g_1 = 1.0f + b_10 + b_11;
  130. nfc->coeffs[0] = nfc->g * g_1;
  131. nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  132. nfc->coeffs[2] = (4.0f * b_11) / g_1;
  133. }
  134. void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
  135. {
  136. const float b0 = nfc->coeffs[0];
  137. const float a00 = nfc->coeffs[1];
  138. const float a01 = nfc->coeffs[2];
  139. const float a10 = nfc->coeffs[3];
  140. const float a11 = nfc->coeffs[4];
  141. float z1 = nfc->history[0];
  142. float z2 = nfc->history[1];
  143. int i;
  144. for(i = 0;i < count;i++)
  145. {
  146. float out = src[i] * b0;
  147. float y;
  148. y = out - (a10*z1) - (a11*z2);
  149. out = y + (a00*z1) + (a01*z2);
  150. z2 += z1;
  151. z1 += y;
  152. dst[i] = out;
  153. }
  154. nfc->history[0] = z1;
  155. nfc->history[1] = z2;
  156. }
  157. void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1)
  158. {
  159. float b_10, b_11, g_1;
  160. float b_00, g_0;
  161. float r;
  162. memset(nfc, 0, sizeof(*nfc));
  163. nfc->g = 1.0f;
  164. nfc->coeffs[0] = 1.0f;
  165. /* Calculate bass-boost coefficients. */
  166. r = 0.5f * w0;
  167. b_10 = B[3][0] * r;
  168. b_11 = B[3][1] * r * r;
  169. g_1 = 1.0f + b_10 + b_11;
  170. nfc->coeffs[0] *= g_1;
  171. nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  172. nfc->coeffs[2] = (4.0f * b_11) / g_1;
  173. b_00 = B[3][2] * r;
  174. g_0 = 1.0f + b_00;
  175. nfc->coeffs[0] *= g_0;
  176. nfc->coeffs[2+1] = (2.0f * b_00) / g_0;
  177. /* Calculate bass-cut coefficients. */
  178. r = 0.5f * w1;
  179. b_10 = B[3][0] * r;
  180. b_11 = B[3][1] * r * r;
  181. g_1 = 1.0f + b_10 + b_11;
  182. nfc->g /= g_1;
  183. nfc->coeffs[0] /= g_1;
  184. nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  185. nfc->coeffs[3+2] = (4.0f * b_11) / g_1;
  186. b_00 = B[3][2] * r;
  187. g_0 = 1.0f + b_00;
  188. nfc->g /= g_0;
  189. nfc->coeffs[0] /= g_0;
  190. nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0;
  191. }
  192. void NfcFilterAdjust3(NfcFilter *nfc, const float w0)
  193. {
  194. float b_10, b_11, g_1;
  195. float b_00, g_0;
  196. float r;
  197. r = 0.5f * w0;
  198. b_10 = B[3][0] * r;
  199. b_11 = B[3][1] * r * r;
  200. g_1 = 1.0f + b_10 + b_11;
  201. nfc->coeffs[0] = nfc->g * g_1;
  202. nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  203. nfc->coeffs[2] = (4.0f * b_11) / g_1;
  204. b_00 = B[3][2] * r;
  205. g_0 = 1.0f + b_00;
  206. nfc->coeffs[0] *= g_0;
  207. nfc->coeffs[2+1] = (2.0f * b_00) / g_0;
  208. }
  209. void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
  210. {
  211. const float b0 = nfc->coeffs[0];
  212. const float a00 = nfc->coeffs[1];
  213. const float a01 = nfc->coeffs[2];
  214. const float a02 = nfc->coeffs[3];
  215. const float a10 = nfc->coeffs[4];
  216. const float a11 = nfc->coeffs[5];
  217. const float a12 = nfc->coeffs[6];
  218. float z1 = nfc->history[0];
  219. float z2 = nfc->history[1];
  220. float z3 = nfc->history[2];
  221. int i;
  222. for(i = 0;i < count;i++)
  223. {
  224. float out = src[i] * b0;
  225. float y;
  226. y = out - (a10*z1) - (a11*z2);
  227. out = y + (a00*z1) + (a01*z2);
  228. z2 += z1;
  229. z1 += y;
  230. y = out - (a12*z3);
  231. out = y + (a02*z3);
  232. z3 += y;
  233. dst[i] = out;
  234. }
  235. nfc->history[0] = z1;
  236. nfc->history[1] = z2;
  237. nfc->history[2] = z3;
  238. }
  239. #if 0 /* Original methods the above are derived from. */
  240. static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate)
  241. {
  242. static const float B[4][5] = {
  243. { },
  244. { 1.0f },
  245. { 3.0f, 3.0f },
  246. { 3.6778f, 6.4595f, 2.3222f },
  247. { 4.2076f, 11.4877f, 5.7924f, 9.1401f }
  248. };
  249. float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate);
  250. float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate);
  251. ALsizei i;
  252. float r;
  253. nfc->g = 1.0f;
  254. nfc->coeffs[0] = 1.0f;
  255. /* NOTE: Slight adjustment from the literature to raise the center
  256. * frequency a bit (0.5 -> 1.0).
  257. */
  258. r = 1.0f * w0;
  259. for(i = 0; i < (order-1);i += 2)
  260. {
  261. float b_10 = B[order][i ] * r;
  262. float b_11 = B[order][i+1] * r * r;
  263. float g_1 = 1.0f + b_10 + b_11;
  264. nfc->b[i] = b_10;
  265. nfc->b[i + 1] = b_11;
  266. nfc->coeffs[0] *= g_1;
  267. nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  268. nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
  269. }
  270. if(i < order)
  271. {
  272. float b_00 = B[order][i] * r;
  273. float g_0 = 1.0f + b_00;
  274. nfc->b[i] = b_00;
  275. nfc->coeffs[0] *= g_0;
  276. nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
  277. }
  278. r = 1.0f * w1;
  279. for(i = 0;i < (order-1);i += 2)
  280. {
  281. float b_10 = B[order][i ] * r;
  282. float b_11 = B[order][i+1] * r * r;
  283. float g_1 = 1.0f + b_10 + b_11;
  284. nfc->g /= g_1;
  285. nfc->coeffs[0] /= g_1;
  286. nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  287. nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1;
  288. }
  289. if(i < order)
  290. {
  291. float b_00 = B[order][i] * r;
  292. float g_0 = 1.0f + b_00;
  293. nfc->g /= g_0;
  294. nfc->coeffs[0] /= g_0;
  295. nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0;
  296. }
  297. for(i = 0; i < MAX_AMBI_ORDER; i++)
  298. nfc->history[i] = 0.0f;
  299. }
  300. static void NfcFilterAdjust(NfcFilter *nfc, const float distance)
  301. {
  302. int i;
  303. nfc->coeffs[0] = nfc->g;
  304. for(i = 0;i < (nfc->order-1);i += 2)
  305. {
  306. float b_10 = nfc->b[i] / distance;
  307. float b_11 = nfc->b[i+1] / (distance * distance);
  308. float g_1 = 1.0f + b_10 + b_11;
  309. nfc->coeffs[0] *= g_1;
  310. nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
  311. nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
  312. }
  313. if(i < nfc->order)
  314. {
  315. float b_00 = nfc->b[i] / distance;
  316. float g_0 = 1.0f + b_00;
  317. nfc->coeffs[0] *= g_0;
  318. nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
  319. }
  320. }
  321. static float NfcFilterUpdate(const float in, NfcFilter *nfc)
  322. {
  323. int i;
  324. float out = in * nfc->coeffs[0];
  325. for(i = 0;i < (nfc->order-1);i += 2)
  326. {
  327. float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) -
  328. (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f;
  329. out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]);
  330. nfc->history[i+1] += nfc->history[i];
  331. nfc->history[i] += y;
  332. }
  333. if(i < nfc->order)
  334. {
  335. float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f;
  336. out = y + (nfc->coeffs[i+1] * nfc->history[i]);
  337. nfc->history[i] += y;
  338. }
  339. return out;
  340. }
  341. #endif