🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1805 lines
62 KiB

  1. /*
  2. * HRTF utility for producing and demonstrating the process of creating an
  3. * OpenAL Soft compatible HRIR data set.
  4. *
  5. * Copyright (C) 2011-2019 Christopher Fitzgerald
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. *
  23. * --------------------------------------------------------------------------
  24. *
  25. * A big thanks goes out to all those whose work done in the field of
  26. * binaural sound synthesis using measured HRTFs makes this utility and the
  27. * OpenAL Soft implementation possible.
  28. *
  29. * The algorithm for diffuse-field equalization was adapted from the work
  30. * done by Rio Emmanuel and Larcher Veronique of IRCAM and Bill Gardner of
  31. * MIT Media Laboratory. It operates as follows:
  32. *
  33. * 1. Take the FFT of each HRIR and only keep the magnitude responses.
  34. * 2. Calculate the diffuse-field power-average of all HRIRs weighted by
  35. * their contribution to the total surface area covered by their
  36. * measurement. This has since been modified to use coverage volume for
  37. * multi-field HRIR data sets.
  38. * 3. Take the diffuse-field average and limit its magnitude range.
  39. * 4. Equalize the responses by using the inverse of the diffuse-field
  40. * average.
  41. * 5. Reconstruct the minimum-phase responses.
  42. * 5. Zero the DC component.
  43. * 6. IFFT the result and truncate to the desired-length minimum-phase FIR.
  44. *
  45. * The spherical head algorithm for calculating propagation delay was adapted
  46. * from the paper:
  47. *
  48. * Modeling Interaural Time Difference Assuming a Spherical Head
  49. * Joel David Miller
  50. * Music 150, Musical Acoustics, Stanford University
  51. * December 2, 2001
  52. *
  53. * The formulae for calculating the Kaiser window metrics are from the
  54. * the textbook:
  55. *
  56. * Discrete-Time Signal Processing
  57. * Alan V. Oppenheim and Ronald W. Schafer
  58. * Prentice-Hall Signal Processing Series
  59. * 1999
  60. */
  61. #include "config.h"
  62. #define _UNICODE
  63. #include <cstdio>
  64. #include <cstdlib>
  65. #include <cstdarg>
  66. #include <cstddef>
  67. #include <cstring>
  68. #include <climits>
  69. #include <cstdint>
  70. #include <cctype>
  71. #include <cmath>
  72. #ifdef HAVE_STRINGS_H
  73. #include <strings.h>
  74. #endif
  75. #ifdef HAVE_GETOPT
  76. #include <unistd.h>
  77. #else
  78. #include "getopt.h"
  79. #endif
  80. #include <atomic>
  81. #include <limits>
  82. #include <vector>
  83. #include <chrono>
  84. #include <thread>
  85. #include <complex>
  86. #include <numeric>
  87. #include <algorithm>
  88. #include <functional>
  89. #include "mysofa.h"
  90. #include "makemhr.h"
  91. #include "loaddef.h"
  92. #include "loadsofa.h"
  93. #include "win_main_utf8.h"
  94. namespace {
  95. using namespace std::placeholders;
  96. } // namespace
  97. #ifndef M_PI
  98. #define M_PI (3.14159265358979323846)
  99. #endif
  100. // Head model used for calculating the impulse delays.
  101. enum HeadModelT {
  102. HM_NONE,
  103. HM_DATASET, // Measure the onset from the dataset.
  104. HM_SPHERE // Calculate the onset using a spherical head model.
  105. };
  106. // The epsilon used to maintain signal stability.
  107. #define EPSILON (1e-9)
  108. // The limits to the FFT window size override on the command line.
  109. #define MIN_FFTSIZE (65536)
  110. #define MAX_FFTSIZE (131072)
  111. // The limits to the equalization range limit on the command line.
  112. #define MIN_LIMIT (2.0)
  113. #define MAX_LIMIT (120.0)
  114. // The limits to the truncation window size on the command line.
  115. #define MIN_TRUNCSIZE (16)
  116. #define MAX_TRUNCSIZE (512)
  117. // The limits to the custom head radius on the command line.
  118. #define MIN_CUSTOM_RADIUS (0.05)
  119. #define MAX_CUSTOM_RADIUS (0.15)
  120. // The truncation window size must be a multiple of the below value to allow
  121. // for vectorized convolution.
  122. #define MOD_TRUNCSIZE (8)
  123. // The defaults for the command line options.
  124. #define DEFAULT_FFTSIZE (65536)
  125. #define DEFAULT_EQUALIZE (1)
  126. #define DEFAULT_SURFACE (1)
  127. #define DEFAULT_LIMIT (24.0)
  128. #define DEFAULT_TRUNCSIZE (32)
  129. #define DEFAULT_HEAD_MODEL (HM_DATASET)
  130. #define DEFAULT_CUSTOM_RADIUS (0.0)
  131. // The maximum propagation delay value supported by OpenAL Soft.
  132. #define MAX_HRTD (63.0)
  133. // The OpenAL Soft HRTF format marker. It stands for minimum-phase head
  134. // response protocol 02.
  135. #define MHR_FORMAT ("MinPHR02")
  136. /* Channel index enums. Mono uses LeftChannel only. */
  137. enum ChannelIndex : uint {
  138. LeftChannel = 0u,
  139. RightChannel = 1u
  140. };
  141. /* Performs a string substitution. Any case-insensitive occurrences of the
  142. * pattern string are replaced with the replacement string. The result is
  143. * truncated if necessary.
  144. */
  145. static int StrSubst(const char *in, const char *pat, const char *rep, const size_t maxLen, char *out)
  146. {
  147. size_t inLen, patLen, repLen;
  148. size_t si, di;
  149. int truncated;
  150. inLen = strlen(in);
  151. patLen = strlen(pat);
  152. repLen = strlen(rep);
  153. si = 0;
  154. di = 0;
  155. truncated = 0;
  156. while(si < inLen && di < maxLen)
  157. {
  158. if(patLen <= inLen-si)
  159. {
  160. if(strncasecmp(&in[si], pat, patLen) == 0)
  161. {
  162. if(repLen > maxLen-di)
  163. {
  164. repLen = maxLen - di;
  165. truncated = 1;
  166. }
  167. strncpy(&out[di], rep, repLen);
  168. si += patLen;
  169. di += repLen;
  170. }
  171. }
  172. out[di] = in[si];
  173. si++;
  174. di++;
  175. }
  176. if(si < inLen)
  177. truncated = 1;
  178. out[di] = '\0';
  179. return !truncated;
  180. }
  181. /*********************
  182. *** Math routines ***
  183. *********************/
  184. // Simple clamp routine.
  185. static double Clamp(const double val, const double lower, const double upper)
  186. {
  187. return std::min(std::max(val, lower), upper);
  188. }
  189. static inline uint dither_rng(uint *seed)
  190. {
  191. *seed = *seed * 96314165 + 907633515;
  192. return *seed;
  193. }
  194. // Performs a triangular probability density function dither. The input samples
  195. // should be normalized (-1 to +1).
  196. static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale,
  197. const int count, const int step, uint *seed)
  198. {
  199. static constexpr double PRNG_SCALE = 1.0 / std::numeric_limits<uint>::max();
  200. for(int i{0};i < count;i++)
  201. {
  202. uint prn0{dither_rng(seed)};
  203. uint prn1{dither_rng(seed)};
  204. out[i*step] = std::round(in[i]*scale + (prn0*PRNG_SCALE - prn1*PRNG_SCALE));
  205. }
  206. }
  207. /* Fast Fourier transform routines. The number of points must be a power of
  208. * two.
  209. */
  210. // Performs bit-reversal ordering.
  211. static void FftArrange(const uint n, complex_d *inout)
  212. {
  213. // Handle in-place arrangement.
  214. uint rk{0u};
  215. for(uint k{0u};k < n;k++)
  216. {
  217. if(rk > k)
  218. std::swap(inout[rk], inout[k]);
  219. uint m{n};
  220. while(rk&(m >>= 1))
  221. rk &= ~m;
  222. rk |= m;
  223. }
  224. }
  225. // Performs the summation.
  226. static void FftSummation(const int n, const double s, complex_d *cplx)
  227. {
  228. double pi;
  229. int m, m2;
  230. int i, k, mk;
  231. pi = s * M_PI;
  232. for(m = 1, m2 = 2;m < n; m <<= 1, m2 <<= 1)
  233. {
  234. // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m))
  235. double sm = sin(0.5 * pi / m);
  236. auto v = complex_d{-2.0*sm*sm, -sin(pi / m)};
  237. auto w = complex_d{1.0, 0.0};
  238. for(i = 0;i < m;i++)
  239. {
  240. for(k = i;k < n;k += m2)
  241. {
  242. mk = k + m;
  243. auto t = w * cplx[mk];
  244. cplx[mk] = cplx[k] - t;
  245. cplx[k] = cplx[k] + t;
  246. }
  247. w += v*w;
  248. }
  249. }
  250. }
  251. // Performs a forward FFT.
  252. void FftForward(const uint n, complex_d *inout)
  253. {
  254. FftArrange(n, inout);
  255. FftSummation(n, 1.0, inout);
  256. }
  257. // Performs an inverse FFT.
  258. void FftInverse(const uint n, complex_d *inout)
  259. {
  260. FftArrange(n, inout);
  261. FftSummation(n, -1.0, inout);
  262. double f{1.0 / n};
  263. for(uint i{0};i < n;i++)
  264. inout[i] *= f;
  265. }
  266. /* Calculate the complex helical sequence (or discrete-time analytical signal)
  267. * of the given input using the Hilbert transform. Given the natural logarithm
  268. * of a signal's magnitude response, the imaginary components can be used as
  269. * the angles for minimum-phase reconstruction.
  270. */
  271. static void Hilbert(const uint n, complex_d *inout)
  272. {
  273. uint i;
  274. // Handle in-place operation.
  275. for(i = 0;i < n;i++)
  276. inout[i].imag(0.0);
  277. FftInverse(n, inout);
  278. for(i = 1;i < (n+1)/2;i++)
  279. inout[i] *= 2.0;
  280. /* Increment i if n is even. */
  281. i += (n&1)^1;
  282. for(;i < n;i++)
  283. inout[i] = complex_d{0.0, 0.0};
  284. FftForward(n, inout);
  285. }
  286. /* Calculate the magnitude response of the given input. This is used in
  287. * place of phase decomposition, since the phase residuals are discarded for
  288. * minimum phase reconstruction. The mirrored half of the response is also
  289. * discarded.
  290. */
  291. void MagnitudeResponse(const uint n, const complex_d *in, double *out)
  292. {
  293. const uint m = 1 + (n / 2);
  294. uint i;
  295. for(i = 0;i < m;i++)
  296. out[i] = std::max(std::abs(in[i]), EPSILON);
  297. }
  298. /* Apply a range limit (in dB) to the given magnitude response. This is used
  299. * to adjust the effects of the diffuse-field average on the equalization
  300. * process.
  301. */
  302. static void LimitMagnitudeResponse(const uint n, const uint m, const double limit, const double *in, double *out)
  303. {
  304. double halfLim;
  305. uint i, lower, upper;
  306. double ave;
  307. halfLim = limit / 2.0;
  308. // Convert the response to dB.
  309. for(i = 0;i < m;i++)
  310. out[i] = 20.0 * std::log10(in[i]);
  311. // Use six octaves to calculate the average magnitude of the signal.
  312. lower = (static_cast<uint>(std::ceil(n / std::pow(2.0, 8.0)))) - 1;
  313. upper = (static_cast<uint>(std::floor(n / std::pow(2.0, 2.0)))) - 1;
  314. ave = 0.0;
  315. for(i = lower;i <= upper;i++)
  316. ave += out[i];
  317. ave /= upper - lower + 1;
  318. // Keep the response within range of the average magnitude.
  319. for(i = 0;i < m;i++)
  320. out[i] = Clamp(out[i], ave - halfLim, ave + halfLim);
  321. // Convert the response back to linear magnitude.
  322. for(i = 0;i < m;i++)
  323. out[i] = std::pow(10.0, out[i] / 20.0);
  324. }
  325. /* Reconstructs the minimum-phase component for the given magnitude response
  326. * of a signal. This is equivalent to phase recomposition, sans the missing
  327. * residuals (which were discarded). The mirrored half of the response is
  328. * reconstructed.
  329. */
  330. static void MinimumPhase(const uint n, const double *in, complex_d *out)
  331. {
  332. const uint m = 1 + (n / 2);
  333. std::vector<double> mags(n);
  334. uint i;
  335. for(i = 0;i < m;i++)
  336. {
  337. mags[i] = std::max(EPSILON, in[i]);
  338. out[i] = complex_d{std::log(mags[i]), 0.0};
  339. }
  340. for(;i < n;i++)
  341. {
  342. mags[i] = mags[n - i];
  343. out[i] = out[n - i];
  344. }
  345. Hilbert(n, out);
  346. // Remove any DC offset the filter has.
  347. mags[0] = EPSILON;
  348. for(i = 0;i < n;i++)
  349. {
  350. auto a = std::exp(complex_d{0.0, out[i].imag()});
  351. out[i] = complex_d{mags[i], 0.0} * a;
  352. }
  353. }
  354. /***************************
  355. *** Resampler functions ***
  356. ***************************/
  357. /* This is the normalized cardinal sine (sinc) function.
  358. *
  359. * sinc(x) = { 1, x = 0
  360. * { sin(pi x) / (pi x), otherwise.
  361. */
  362. static double Sinc(const double x)
  363. {
  364. if(std::abs(x) < EPSILON)
  365. return 1.0;
  366. return std::sin(M_PI * x) / (M_PI * x);
  367. }
  368. /* The zero-order modified Bessel function of the first kind, used for the
  369. * Kaiser window.
  370. *
  371. * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
  372. * = sum_{k=0}^inf ((x / 2)^k / k!)^2
  373. */
  374. static double BesselI_0(const double x)
  375. {
  376. double term, sum, x2, y, last_sum;
  377. int k;
  378. // Start at k=1 since k=0 is trivial.
  379. term = 1.0;
  380. sum = 1.0;
  381. x2 = x/2.0;
  382. k = 1;
  383. // Let the integration converge until the term of the sum is no longer
  384. // significant.
  385. do {
  386. y = x2 / k;
  387. k++;
  388. last_sum = sum;
  389. term *= y * y;
  390. sum += term;
  391. } while(sum != last_sum);
  392. return sum;
  393. }
  394. /* Calculate a Kaiser window from the given beta value and a normalized k
  395. * [-1, 1].
  396. *
  397. * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
  398. * { 0, elsewhere.
  399. *
  400. * Where k can be calculated as:
  401. *
  402. * k = i / l, where -l <= i <= l.
  403. *
  404. * or:
  405. *
  406. * k = 2 i / M - 1, where 0 <= i <= M.
  407. */
  408. static double Kaiser(const double b, const double k)
  409. {
  410. if(!(k >= -1.0 && k <= 1.0))
  411. return 0.0;
  412. return BesselI_0(b * std::sqrt(1.0 - k*k)) / BesselI_0(b);
  413. }
  414. // Calculates the greatest common divisor of a and b.
  415. static uint Gcd(uint x, uint y)
  416. {
  417. while(y > 0)
  418. {
  419. uint z{y};
  420. y = x % y;
  421. x = z;
  422. }
  423. return x;
  424. }
  425. /* Calculates the size (order) of the Kaiser window. Rejection is in dB and
  426. * the transition width is normalized frequency (0.5 is nyquist).
  427. *
  428. * M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21
  429. * { ceil(5.79 / 2 pi f_t), r <= 21.
  430. *
  431. */
  432. static uint CalcKaiserOrder(const double rejection, const double transition)
  433. {
  434. double w_t = 2.0 * M_PI * transition;
  435. if(rejection > 21.0)
  436. return static_cast<uint>(std::ceil((rejection - 7.95) / (2.285 * w_t)));
  437. return static_cast<uint>(std::ceil(5.79 / w_t));
  438. }
  439. // Calculates the beta value of the Kaiser window. Rejection is in dB.
  440. static double CalcKaiserBeta(const double rejection)
  441. {
  442. if(rejection > 50.0)
  443. return 0.1102 * (rejection - 8.7);
  444. if(rejection >= 21.0)
  445. return (0.5842 * std::pow(rejection - 21.0, 0.4)) +
  446. (0.07886 * (rejection - 21.0));
  447. return 0.0;
  448. }
  449. /* Calculates a point on the Kaiser-windowed sinc filter for the given half-
  450. * width, beta, gain, and cutoff. The point is specified in non-normalized
  451. * samples, from 0 to M, where M = (2 l + 1).
  452. *
  453. * w(k) 2 p f_t sinc(2 f_t x)
  454. *
  455. * x -- centered sample index (i - l)
  456. * k -- normalized and centered window index (x / l)
  457. * w(k) -- window function (Kaiser)
  458. * p -- gain compensation factor when sampling
  459. * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist)
  460. */
  461. static double SincFilter(const int l, const double b, const double gain, const double cutoff, const int i)
  462. {
  463. return Kaiser(b, static_cast<double>(i - l) / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * (i - l));
  464. }
  465. /* This is a polyphase sinc-filtered resampler.
  466. *
  467. * Upsample Downsample
  468. *
  469. * p/q = 3/2 p/q = 3/5
  470. *
  471. * M-+-+-+-> M-+-+-+->
  472. * -------------------+ ---------------------+
  473. * p s * f f f f|f| | p s * f f f f f |
  474. * | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| |
  475. * v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 |
  476. * s * f|f|f f f | s * f f|f|f f |
  477. * 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 |
  478. * --------+=+--------+ 0 * |0|0 0 0 0 |
  479. * d . d .|d|. d . d ----------+=+--------+
  480. * d . . . .|d|. . . .
  481. * q->
  482. * q-+-+-+->
  483. *
  484. * P_f(i,j) = q i mod p + pj
  485. * P_s(i,j) = floor(q i / p) - j
  486. * d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} {
  487. * { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M
  488. * { 0, P_f(i,j) >= M. }
  489. */
  490. // Calculate the resampling metrics and build the Kaiser-windowed sinc filter
  491. // that's used to cut frequencies above the destination nyquist.
  492. void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate)
  493. {
  494. double cutoff, width, beta;
  495. uint gcd, l;
  496. int i;
  497. gcd = Gcd(srcRate, dstRate);
  498. rs->mP = dstRate / gcd;
  499. rs->mQ = srcRate / gcd;
  500. /* The cutoff is adjusted by half the transition width, so the transition
  501. * ends before the nyquist (0.5). Both are scaled by the downsampling
  502. * factor.
  503. */
  504. if(rs->mP > rs->mQ)
  505. {
  506. cutoff = 0.475 / rs->mP;
  507. width = 0.05 / rs->mP;
  508. }
  509. else
  510. {
  511. cutoff = 0.475 / rs->mQ;
  512. width = 0.05 / rs->mQ;
  513. }
  514. // A rejection of -180 dB is used for the stop band. Round up when
  515. // calculating the left offset to avoid increasing the transition width.
  516. l = (CalcKaiserOrder(180.0, width)+1) / 2;
  517. beta = CalcKaiserBeta(180.0);
  518. rs->mM = l*2 + 1;
  519. rs->mL = l;
  520. rs->mF.resize(rs->mM);
  521. for(i = 0;i < (static_cast<int>(rs->mM));i++)
  522. rs->mF[i] = SincFilter(static_cast<int>(l), beta, rs->mP, cutoff, i);
  523. }
  524. // Perform the upsample-filter-downsample resampling operation using a
  525. // polyphase filter implementation.
  526. void ResamplerRun(ResamplerT *rs, const uint inN, const double *in, const uint outN, double *out)
  527. {
  528. const uint p = rs->mP, q = rs->mQ, m = rs->mM, l = rs->mL;
  529. std::vector<double> workspace;
  530. const double *f = rs->mF.data();
  531. uint j_f, j_s;
  532. double *work;
  533. uint i;
  534. if(outN == 0)
  535. return;
  536. // Handle in-place operation.
  537. if(in == out)
  538. {
  539. workspace.resize(outN);
  540. work = workspace.data();
  541. }
  542. else
  543. work = out;
  544. // Resample the input.
  545. for(i = 0;i < outN;i++)
  546. {
  547. double r = 0.0;
  548. // Input starts at l to compensate for the filter delay. This will
  549. // drop any build-up from the first half of the filter.
  550. j_f = (l + (q * i)) % p;
  551. j_s = (l + (q * i)) / p;
  552. while(j_f < m)
  553. {
  554. // Only take input when 0 <= j_s < inN. This single unsigned
  555. // comparison catches both cases.
  556. if(j_s < inN)
  557. r += f[j_f] * in[j_s];
  558. j_f += p;
  559. j_s--;
  560. }
  561. work[i] = r;
  562. }
  563. // Clean up after in-place operation.
  564. if(work != out)
  565. {
  566. for(i = 0;i < outN;i++)
  567. out[i] = work[i];
  568. }
  569. }
  570. /***************************
  571. *** File storage output ***
  572. ***************************/
  573. // Write an ASCII string to a file.
  574. static int WriteAscii(const char *out, FILE *fp, const char *filename)
  575. {
  576. size_t len;
  577. len = strlen(out);
  578. if(fwrite(out, 1, len, fp) != len)
  579. {
  580. fclose(fp);
  581. fprintf(stderr, "\nError: Bad write to file '%s'.\n", filename);
  582. return 0;
  583. }
  584. return 1;
  585. }
  586. // Write a binary value of the given byte order and byte size to a file,
  587. // loading it from a 32-bit unsigned integer.
  588. static int WriteBin4(const uint bytes, const uint32_t in, FILE *fp, const char *filename)
  589. {
  590. uint8_t out[4];
  591. uint i;
  592. for(i = 0;i < bytes;i++)
  593. out[i] = (in>>(i*8)) & 0x000000FF;
  594. if(fwrite(out, 1, bytes, fp) != bytes)
  595. {
  596. fprintf(stderr, "\nError: Bad write to file '%s'.\n", filename);
  597. return 0;
  598. }
  599. return 1;
  600. }
  601. // Store the OpenAL Soft HRTF data set.
  602. static int StoreMhr(const HrirDataT *hData, const char *filename)
  603. {
  604. uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
  605. uint n = hData->mIrPoints;
  606. FILE *fp;
  607. uint fi, ei, ai, i;
  608. uint dither_seed = 22222;
  609. if((fp=fopen(filename, "wb")) == nullptr)
  610. {
  611. fprintf(stderr, "\nError: Could not open MHR file '%s'.\n", filename);
  612. return 0;
  613. }
  614. if(!WriteAscii(MHR_FORMAT, fp, filename))
  615. return 0;
  616. if(!WriteBin4(4, hData->mIrRate, fp, filename))
  617. return 0;
  618. if(!WriteBin4(1, static_cast<uint32_t>(hData->mSampleType), fp, filename))
  619. return 0;
  620. if(!WriteBin4(1, static_cast<uint32_t>(hData->mChannelType), fp, filename))
  621. return 0;
  622. if(!WriteBin4(1, hData->mIrPoints, fp, filename))
  623. return 0;
  624. if(!WriteBin4(1, hData->mFdCount, fp, filename))
  625. return 0;
  626. for(fi = 0;fi < hData->mFdCount;fi++)
  627. {
  628. auto fdist = static_cast<uint32_t>(std::round(1000.0 * hData->mFds[fi].mDistance));
  629. if(!WriteBin4(2, fdist, fp, filename))
  630. return 0;
  631. if(!WriteBin4(1, hData->mFds[fi].mEvCount, fp, filename))
  632. return 0;
  633. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  634. {
  635. if(!WriteBin4(1, hData->mFds[fi].mEvs[ei].mAzCount, fp, filename))
  636. return 0;
  637. }
  638. }
  639. for(fi = 0;fi < hData->mFdCount;fi++)
  640. {
  641. const double scale = (hData->mSampleType == ST_S16) ? 32767.0 :
  642. ((hData->mSampleType == ST_S24) ? 8388607.0 : 0.0);
  643. const int bps = (hData->mSampleType == ST_S16) ? 2 :
  644. ((hData->mSampleType == ST_S24) ? 3 : 0);
  645. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  646. {
  647. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  648. {
  649. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  650. double out[2 * MAX_TRUNCSIZE];
  651. TpdfDither(out, azd->mIrs[0], scale, n, channels, &dither_seed);
  652. if(hData->mChannelType == CT_STEREO)
  653. TpdfDither(out+1, azd->mIrs[1], scale, n, channels, &dither_seed);
  654. for(i = 0;i < (channels * n);i++)
  655. {
  656. int v = static_cast<int>(Clamp(out[i], -scale-1.0, scale));
  657. if(!WriteBin4(bps, static_cast<uint32_t>(v), fp, filename))
  658. return 0;
  659. }
  660. }
  661. }
  662. }
  663. for(fi = 0;fi < hData->mFdCount;fi++)
  664. {
  665. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  666. {
  667. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  668. {
  669. const HrirAzT &azd = hData->mFds[fi].mEvs[ei].mAzs[ai];
  670. int v = static_cast<int>(std::min(std::round(hData->mIrRate * azd.mDelays[0]), MAX_HRTD));
  671. if(!WriteBin4(1, static_cast<uint32_t>(v), fp, filename))
  672. return 0;
  673. if(hData->mChannelType == CT_STEREO)
  674. {
  675. v = static_cast<int>(std::min(std::round(hData->mIrRate * azd.mDelays[1]), MAX_HRTD));
  676. if(!WriteBin4(1, static_cast<uint32_t>(v), fp, filename))
  677. return 0;
  678. }
  679. }
  680. }
  681. }
  682. fclose(fp);
  683. return 1;
  684. }
  685. /***********************
  686. *** HRTF processing ***
  687. ***********************/
  688. /* Balances the maximum HRIR magnitudes of multi-field data sets by
  689. * independently normalizing each field in relation to the overall maximum.
  690. * This is done to ignore distance attenuation.
  691. */
  692. static void BalanceFieldMagnitudes(const HrirDataT *hData, const uint channels, const uint m)
  693. {
  694. double maxMags[MAX_FD_COUNT];
  695. uint fi, ei, ai, ti, i;
  696. double maxMag{0.0};
  697. for(fi = 0;fi < hData->mFdCount;fi++)
  698. {
  699. maxMags[fi] = 0.0;
  700. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  701. {
  702. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  703. {
  704. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  705. for(ti = 0;ti < channels;ti++)
  706. {
  707. for(i = 0;i < m;i++)
  708. maxMags[fi] = std::max(azd->mIrs[ti][i], maxMags[fi]);
  709. }
  710. }
  711. }
  712. maxMag = std::max(maxMags[fi], maxMag);
  713. }
  714. for(fi = 0;fi < hData->mFdCount;fi++)
  715. {
  716. const double magFactor{maxMag / maxMags[fi]};
  717. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  718. {
  719. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  720. {
  721. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  722. for(ti = 0;ti < channels;ti++)
  723. {
  724. for(i = 0;i < m;i++)
  725. azd->mIrs[ti][i] *= magFactor;
  726. }
  727. }
  728. }
  729. }
  730. }
  731. /* Calculate the contribution of each HRIR to the diffuse-field average based
  732. * on its coverage volume. All volumes are centered at the spherical HRIR
  733. * coordinates and measured by extruded solid angle.
  734. */
  735. static void CalculateDfWeights(const HrirDataT *hData, double *weights)
  736. {
  737. double sum, innerRa, outerRa, evs, ev, upperEv, lowerEv;
  738. double solidAngle, solidVolume;
  739. uint fi, ei;
  740. sum = 0.0;
  741. // The head radius acts as the limit for the inner radius.
  742. innerRa = hData->mRadius;
  743. for(fi = 0;fi < hData->mFdCount;fi++)
  744. {
  745. // Each volume ends half way between progressive field measurements.
  746. if((fi + 1) < hData->mFdCount)
  747. outerRa = 0.5f * (hData->mFds[fi].mDistance + hData->mFds[fi + 1].mDistance);
  748. // The final volume has its limit extended to some practical value.
  749. // This is done to emphasize the far-field responses in the average.
  750. else
  751. outerRa = 10.0f;
  752. evs = M_PI / 2.0 / (hData->mFds[fi].mEvCount - 1);
  753. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  754. {
  755. // For each elevation, calculate the upper and lower limits of
  756. // the patch band.
  757. ev = hData->mFds[fi].mEvs[ei].mElevation;
  758. lowerEv = std::max(-M_PI / 2.0, ev - evs);
  759. upperEv = std::min(M_PI / 2.0, ev + evs);
  760. // Calculate the surface area of the patch band.
  761. solidAngle = 2.0 * M_PI * (std::sin(upperEv) - std::sin(lowerEv));
  762. // Then the volume of the extruded patch band.
  763. solidVolume = solidAngle * (std::pow(outerRa, 3.0) - std::pow(innerRa, 3.0)) / 3.0;
  764. // Each weight is the volume of one extruded patch.
  765. weights[(fi * MAX_EV_COUNT) + ei] = solidVolume / hData->mFds[fi].mEvs[ei].mAzCount;
  766. // Sum the total coverage volume of the HRIRs for all fields.
  767. sum += solidAngle;
  768. }
  769. innerRa = outerRa;
  770. }
  771. for(fi = 0;fi < hData->mFdCount;fi++)
  772. {
  773. // Normalize the weights given the total surface coverage for all
  774. // fields.
  775. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  776. weights[(fi * MAX_EV_COUNT) + ei] /= sum;
  777. }
  778. }
  779. /* Calculate the diffuse-field average from the given magnitude responses of
  780. * the HRIR set. Weighting can be applied to compensate for the varying
  781. * coverage of each HRIR. The final average can then be limited by the
  782. * specified magnitude range (in positive dB; 0.0 to skip).
  783. */
  784. static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const uint channels, const uint m, const int weighted, const double limit, double *dfa)
  785. {
  786. std::vector<double> weights(hData->mFdCount * MAX_EV_COUNT);
  787. uint count, ti, fi, ei, i, ai;
  788. if(weighted)
  789. {
  790. // Use coverage weighting to calculate the average.
  791. CalculateDfWeights(hData, weights.data());
  792. }
  793. else
  794. {
  795. double weight;
  796. // If coverage weighting is not used, the weights still need to be
  797. // averaged by the number of existing HRIRs.
  798. count = hData->mIrCount;
  799. for(fi = 0;fi < hData->mFdCount;fi++)
  800. {
  801. for(ei = 0;ei < hData->mFds[fi].mEvStart;ei++)
  802. count -= hData->mFds[fi].mEvs[ei].mAzCount;
  803. }
  804. weight = 1.0 / count;
  805. for(fi = 0;fi < hData->mFdCount;fi++)
  806. {
  807. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  808. weights[(fi * MAX_EV_COUNT) + ei] = weight;
  809. }
  810. }
  811. for(ti = 0;ti < channels;ti++)
  812. {
  813. for(i = 0;i < m;i++)
  814. dfa[(ti * m) + i] = 0.0;
  815. for(fi = 0;fi < hData->mFdCount;fi++)
  816. {
  817. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  818. {
  819. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  820. {
  821. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  822. // Get the weight for this HRIR's contribution.
  823. double weight = weights[(fi * MAX_EV_COUNT) + ei];
  824. // Add this HRIR's weighted power average to the total.
  825. for(i = 0;i < m;i++)
  826. dfa[(ti * m) + i] += weight * azd->mIrs[ti][i] * azd->mIrs[ti][i];
  827. }
  828. }
  829. }
  830. // Finish the average calculation and keep it from being too small.
  831. for(i = 0;i < m;i++)
  832. dfa[(ti * m) + i] = std::max(sqrt(dfa[(ti * m) + i]), EPSILON);
  833. // Apply a limit to the magnitude range of the diffuse-field average
  834. // if desired.
  835. if(limit > 0.0)
  836. LimitMagnitudeResponse(hData->mFftSize, m, limit, &dfa[ti * m], &dfa[ti * m]);
  837. }
  838. }
  839. // Perform diffuse-field equalization on the magnitude responses of the HRIR
  840. // set using the given average response.
  841. static void DiffuseFieldEqualize(const uint channels, const uint m, const double *dfa, const HrirDataT *hData)
  842. {
  843. uint ti, fi, ei, ai, i;
  844. for(fi = 0;fi < hData->mFdCount;fi++)
  845. {
  846. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  847. {
  848. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  849. {
  850. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  851. for(ti = 0;ti < channels;ti++)
  852. {
  853. for(i = 0;i < m;i++)
  854. azd->mIrs[ti][i] /= dfa[(ti * m) + i];
  855. }
  856. }
  857. }
  858. }
  859. }
  860. /* Perform minimum-phase reconstruction using the magnitude responses of the
  861. * HRIR set. Work is delegated to this struct, which runs asynchronously on one
  862. * or more threads (sharing the same reconstructor object).
  863. */
  864. struct HrirReconstructor {
  865. std::vector<double*> mIrs;
  866. std::atomic<size_t> mCurrent;
  867. std::atomic<size_t> mDone;
  868. size_t mFftSize;
  869. size_t mIrPoints;
  870. void Worker()
  871. {
  872. auto h = std::vector<complex_d>(mFftSize);
  873. while(1)
  874. {
  875. /* Load the current index to process. */
  876. size_t idx{mCurrent.load()};
  877. do {
  878. /* If the index is at the end, we're done. */
  879. if(idx >= mIrs.size())
  880. return;
  881. /* Otherwise, increment the current index atomically so other
  882. * threads know to go to the next one. If this call fails, the
  883. * current index was just changed by another thread and the new
  884. * value is loaded into idx, which we'll recheck.
  885. */
  886. } while(!mCurrent.compare_exchange_weak(idx, idx+1, std::memory_order_relaxed));
  887. /* Now do the reconstruction, and apply the inverse FFT to get the
  888. * time-domain response.
  889. */
  890. MinimumPhase(mFftSize, mIrs[idx], h.data());
  891. FftInverse(mFftSize, h.data());
  892. for(size_t i{0u};i < mIrPoints;++i)
  893. mIrs[idx][i] = h[i].real();
  894. /* Increment the number of IRs done. */
  895. mDone.fetch_add(1);
  896. }
  897. }
  898. };
  899. static void ReconstructHrirs(const HrirDataT *hData)
  900. {
  901. const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
  902. /* Count the number of IRs to process (excluding elevations that will be
  903. * synthesized later).
  904. */
  905. size_t total{hData->mIrCount};
  906. for(uint fi{0u};fi < hData->mFdCount;fi++)
  907. {
  908. for(uint ei{0u};ei < hData->mFds[fi].mEvStart;ei++)
  909. total -= hData->mFds[fi].mEvs[ei].mAzCount;
  910. }
  911. total *= channels;
  912. /* Set up the reconstructor with the needed size info and pointers to the
  913. * IRs to process.
  914. */
  915. HrirReconstructor reconstructor;
  916. reconstructor.mIrs.reserve(total);
  917. reconstructor.mCurrent.store(0, std::memory_order_relaxed);
  918. reconstructor.mDone.store(0, std::memory_order_relaxed);
  919. reconstructor.mFftSize = hData->mFftSize;
  920. reconstructor.mIrPoints = hData->mIrPoints;
  921. for(uint fi{0u};fi < hData->mFdCount;fi++)
  922. {
  923. const HrirFdT &field = hData->mFds[fi];
  924. for(uint ei{field.mEvStart};ei < field.mEvCount;ei++)
  925. {
  926. const HrirEvT &elev = field.mEvs[ei];
  927. for(uint ai{0u};ai < elev.mAzCount;ai++)
  928. {
  929. const HrirAzT &azd = elev.mAzs[ai];
  930. for(uint ti{0u};ti < channels;ti++)
  931. reconstructor.mIrs.push_back(azd.mIrs[ti]);
  932. }
  933. }
  934. }
  935. /* Launch two threads to work on reconstruction. */
  936. std::thread thrd1{std::mem_fn(&HrirReconstructor::Worker), &reconstructor};
  937. std::thread thrd2{std::mem_fn(&HrirReconstructor::Worker), &reconstructor};
  938. /* Keep track of the number of IRs done, periodically reporting it. */
  939. size_t count;
  940. while((count=reconstructor.mDone.load()) != total)
  941. {
  942. size_t pcdone{count * 100 / total};
  943. printf("\r%3zu%% done (%zu of %zu)", pcdone, count, total);
  944. fflush(stdout);
  945. std::this_thread::sleep_for(std::chrono::milliseconds{50});
  946. }
  947. size_t pcdone{count * 100 / total};
  948. printf("\r%3zu%% done (%zu of %zu)\n", pcdone, count, total);
  949. if(thrd2.joinable()) thrd2.join();
  950. if(thrd1.joinable()) thrd1.join();
  951. }
  952. // Resamples the HRIRs for use at the given sampling rate.
  953. static void ResampleHrirs(const uint rate, HrirDataT *hData)
  954. {
  955. uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
  956. uint n = hData->mIrPoints;
  957. uint ti, fi, ei, ai;
  958. ResamplerT rs;
  959. ResamplerSetup(&rs, hData->mIrRate, rate);
  960. for(fi = 0;fi < hData->mFdCount;fi++)
  961. {
  962. for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++)
  963. {
  964. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  965. {
  966. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  967. for(ti = 0;ti < channels;ti++)
  968. ResamplerRun(&rs, n, azd->mIrs[ti], n, azd->mIrs[ti]);
  969. }
  970. }
  971. }
  972. hData->mIrRate = rate;
  973. }
  974. /* Given field and elevation indices and an azimuth, calculate the indices of
  975. * the two HRIRs that bound the coordinate along with a factor for
  976. * calculating the continuous HRIR using interpolation.
  977. */
  978. static void CalcAzIndices(const HrirFdT &field, const uint ei, const double az, uint *a0, uint *a1, double *af)
  979. {
  980. double f{(2.0*M_PI + az) * field.mEvs[ei].mAzCount / (2.0*M_PI)};
  981. uint i{static_cast<uint>(f) % field.mEvs[ei].mAzCount};
  982. f -= std::floor(f);
  983. *a0 = i;
  984. *a1 = (i + 1) % field.mEvs[ei].mAzCount;
  985. *af = f;
  986. }
  987. /* Synthesize any missing onset timings at the bottom elevations of each field.
  988. * This just mirrors some top elevations for the bottom, and blends the
  989. * remaining elevations (not an accurate model).
  990. */
  991. static void SynthesizeOnsets(HrirDataT *hData)
  992. {
  993. const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
  994. auto proc_field = [channels](HrirFdT &field) -> void
  995. {
  996. /* Get the starting elevation from the measurements, and use it as the
  997. * upper elevation limit for what needs to be calculated.
  998. */
  999. const uint upperElevReal{field.mEvStart};
  1000. if(upperElevReal <= 0) return;
  1001. /* Get the lowest half of the missing elevations' delays by mirroring
  1002. * the top elevation delays. The responses are on a spherical grid
  1003. * centered between the ears, so these should align.
  1004. */
  1005. uint ei{};
  1006. if(channels > 1)
  1007. {
  1008. /* Take the polar opposite position of the desired measurement and
  1009. * swap the ears.
  1010. */
  1011. field.mEvs[0].mAzs[0].mDelays[0] = field.mEvs[field.mEvCount-1].mAzs[0].mDelays[1];
  1012. field.mEvs[0].mAzs[0].mDelays[1] = field.mEvs[field.mEvCount-1].mAzs[0].mDelays[0];
  1013. for(ei = 1u;ei < (upperElevReal+1)/2;++ei)
  1014. {
  1015. const uint topElev{field.mEvCount-ei-1};
  1016. for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
  1017. {
  1018. uint a0, a1;
  1019. double af;
  1020. /* Rotate this current azimuth by a half-circle, and lookup
  1021. * the mirrored elevation to find the indices for the polar
  1022. * opposite position (may need blending).
  1023. */
  1024. const double az{field.mEvs[ei].mAzs[ai].mAzimuth + M_PI};
  1025. CalcAzIndices(field, topElev, az, &a0, &a1, &af);
  1026. /* Blend the delays, and again, swap the ears. */
  1027. field.mEvs[ei].mAzs[ai].mDelays[0] = Lerp(
  1028. field.mEvs[topElev].mAzs[a0].mDelays[1],
  1029. field.mEvs[topElev].mAzs[a1].mDelays[1], af);
  1030. field.mEvs[ei].mAzs[ai].mDelays[1] = Lerp(
  1031. field.mEvs[topElev].mAzs[a0].mDelays[0],
  1032. field.mEvs[topElev].mAzs[a1].mDelays[0], af);
  1033. }
  1034. }
  1035. }
  1036. else
  1037. {
  1038. field.mEvs[0].mAzs[0].mDelays[0] = field.mEvs[field.mEvCount-1].mAzs[0].mDelays[0];
  1039. for(ei = 1u;ei < (upperElevReal+1)/2;++ei)
  1040. {
  1041. const uint topElev{field.mEvCount-ei-1};
  1042. for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
  1043. {
  1044. uint a0, a1;
  1045. double af;
  1046. /* For mono data sets, mirror the azimuth front<->back
  1047. * since the other ear is a mirror of what we have (e.g.
  1048. * the left ear's back-left is simulated with the right
  1049. * ear's front-right, which uses the left ear's front-left
  1050. * measurement).
  1051. */
  1052. double az{field.mEvs[ei].mAzs[ai].mAzimuth};
  1053. if(az <= M_PI) az = M_PI - az;
  1054. else az = (M_PI*2.0)-az + M_PI;
  1055. CalcAzIndices(field, topElev, az, &a0, &a1, &af);
  1056. field.mEvs[ei].mAzs[ai].mDelays[0] = Lerp(
  1057. field.mEvs[topElev].mAzs[a0].mDelays[0],
  1058. field.mEvs[topElev].mAzs[a1].mDelays[0], af);
  1059. }
  1060. }
  1061. }
  1062. /* Record the lowest elevation filled in with the mirrored top. */
  1063. const uint lowerElevFake{ei-1u};
  1064. /* Fill in the remaining delays using bilinear interpolation. This
  1065. * helps smooth the transition back to the real delays.
  1066. */
  1067. for(;ei < upperElevReal;++ei)
  1068. {
  1069. const double ef{(field.mEvs[upperElevReal].mElevation - field.mEvs[ei].mElevation) /
  1070. (field.mEvs[upperElevReal].mElevation - field.mEvs[lowerElevFake].mElevation)};
  1071. for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
  1072. {
  1073. uint a0, a1, a2, a3;
  1074. double af0, af1;
  1075. double az{field.mEvs[ei].mAzs[ai].mAzimuth};
  1076. CalcAzIndices(field, upperElevReal, az, &a0, &a1, &af0);
  1077. CalcAzIndices(field, lowerElevFake, az, &a2, &a3, &af1);
  1078. double blend[4]{
  1079. (1.0-ef) * (1.0-af0),
  1080. (1.0-ef) * ( af0),
  1081. ( ef) * (1.0-af1),
  1082. ( ef) * ( af1)
  1083. };
  1084. for(uint ti{0u};ti < channels;ti++)
  1085. {
  1086. field.mEvs[ei].mAzs[ai].mDelays[ti] =
  1087. field.mEvs[upperElevReal].mAzs[a0].mDelays[ti]*blend[0] +
  1088. field.mEvs[upperElevReal].mAzs[a1].mDelays[ti]*blend[1] +
  1089. field.mEvs[lowerElevFake].mAzs[a2].mDelays[ti]*blend[2] +
  1090. field.mEvs[lowerElevFake].mAzs[a3].mDelays[ti]*blend[3];
  1091. }
  1092. }
  1093. }
  1094. };
  1095. std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc_field);
  1096. }
  1097. /* Attempt to synthesize any missing HRIRs at the bottom elevations of each
  1098. * field. Right now this just blends the lowest elevation HRIRs together and
  1099. * applies some attenuation and high frequency damping. It is a simple, if
  1100. * inaccurate model.
  1101. */
  1102. static void SynthesizeHrirs(HrirDataT *hData)
  1103. {
  1104. const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
  1105. const uint irSize{hData->mIrPoints};
  1106. const double beta{3.5e-6 * hData->mIrRate};
  1107. auto proc_field = [channels,irSize,beta](HrirFdT &field) -> void
  1108. {
  1109. const uint oi{field.mEvStart};
  1110. if(oi <= 0) return;
  1111. for(uint ti{0u};ti < channels;ti++)
  1112. {
  1113. for(uint i{0u};i < irSize;i++)
  1114. field.mEvs[0].mAzs[0].mIrs[ti][i] = 0.0;
  1115. /* Blend the lowest defined elevation's responses for an average
  1116. * -90 degree elevation response.
  1117. */
  1118. double blend_count{0.0};
  1119. for(uint ai{0u};ai < field.mEvs[oi].mAzCount;ai++)
  1120. {
  1121. /* Only include the left responses for the left ear, and the
  1122. * right responses for the right ear. This removes the cross-
  1123. * talk that shouldn't exist for the -90 degree elevation
  1124. * response (and would be mistimed anyway). NOTE: Azimuth goes
  1125. * from 0...2pi rather than -pi...+pi (0 in front, clockwise).
  1126. */
  1127. if(std::abs(field.mEvs[oi].mAzs[ai].mAzimuth) < EPSILON ||
  1128. (ti == LeftChannel && field.mEvs[oi].mAzs[ai].mAzimuth > M_PI-EPSILON) ||
  1129. (ti == RightChannel && field.mEvs[oi].mAzs[ai].mAzimuth < M_PI+EPSILON))
  1130. {
  1131. for(uint i{0u};i < irSize;i++)
  1132. field.mEvs[0].mAzs[0].mIrs[ti][i] += field.mEvs[oi].mAzs[ai].mIrs[ti][i];
  1133. blend_count += 1.0;
  1134. }
  1135. }
  1136. if(blend_count > 0.0)
  1137. {
  1138. for(uint i{0u};i < irSize;i++)
  1139. field.mEvs[0].mAzs[0].mIrs[ti][i] /= blend_count;
  1140. }
  1141. for(uint ei{1u};ei < field.mEvStart;ei++)
  1142. {
  1143. const double of{static_cast<double>(ei) / field.mEvStart};
  1144. const double b{(1.0 - of) * beta};
  1145. for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
  1146. {
  1147. uint a0, a1;
  1148. double af;
  1149. CalcAzIndices(field, oi, field.mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af);
  1150. double lp[4]{};
  1151. for(uint i{0u};i < irSize;i++)
  1152. {
  1153. /* Blend the two defined HRIRs closest to this azimuth,
  1154. * then blend that with the synthesized -90 elevation.
  1155. */
  1156. const double s1{Lerp(field.mEvs[oi].mAzs[a0].mIrs[ti][i],
  1157. field.mEvs[oi].mAzs[a1].mIrs[ti][i], af)};
  1158. const double s0{Lerp(field.mEvs[0].mAzs[0].mIrs[ti][i], s1, of)};
  1159. /* Apply a low-pass to simulate body occlusion. */
  1160. lp[0] = Lerp(s0, lp[0], b);
  1161. lp[1] = Lerp(lp[0], lp[1], b);
  1162. lp[2] = Lerp(lp[1], lp[2], b);
  1163. lp[3] = Lerp(lp[2], lp[3], b);
  1164. field.mEvs[ei].mAzs[ai].mIrs[ti][i] = lp[3];
  1165. }
  1166. }
  1167. }
  1168. const double b{beta};
  1169. double lp[4]{};
  1170. for(uint i{0u};i < irSize;i++)
  1171. {
  1172. const double s0{field.mEvs[0].mAzs[0].mIrs[ti][i]};
  1173. lp[0] = Lerp(s0, lp[0], b);
  1174. lp[1] = Lerp(lp[0], lp[1], b);
  1175. lp[2] = Lerp(lp[1], lp[2], b);
  1176. lp[3] = Lerp(lp[2], lp[3], b);
  1177. field.mEvs[0].mAzs[0].mIrs[ti][i] = lp[3];
  1178. }
  1179. }
  1180. field.mEvStart = 0;
  1181. };
  1182. std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc_field);
  1183. }
  1184. // The following routines assume a full set of HRIRs for all elevations.
  1185. // Normalize the HRIR set and slightly attenuate the result.
  1186. static void NormalizeHrirs(HrirDataT *hData)
  1187. {
  1188. const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
  1189. const uint irSize{hData->mIrPoints};
  1190. /* Find the maximum amplitude and RMS out of all the IRs. */
  1191. struct LevelPair { double amp, rms; };
  1192. auto proc0_field = [channels,irSize](const LevelPair levels, const HrirFdT &field) -> LevelPair
  1193. {
  1194. auto proc_elev = [channels,irSize](const LevelPair levels, const HrirEvT &elev) -> LevelPair
  1195. {
  1196. auto proc_azi = [channels,irSize](const LevelPair levels, const HrirAzT &azi) -> LevelPair
  1197. {
  1198. auto proc_channel = [irSize](const LevelPair levels, const double *ir) -> LevelPair
  1199. {
  1200. /* Calculate the peak amplitude and RMS of this IR. */
  1201. auto current = std::accumulate(ir, ir+irSize, LevelPair{0.0, 0.0},
  1202. [](const LevelPair current, const double impulse) -> LevelPair
  1203. {
  1204. return LevelPair{std::max(std::abs(impulse), current.amp),
  1205. current.rms + impulse*impulse};
  1206. });
  1207. current.rms = std::sqrt(current.rms / irSize);
  1208. /* Accumulate levels by taking the maximum amplitude and RMS. */
  1209. return LevelPair{std::max(current.amp, levels.amp),
  1210. std::max(current.rms, levels.rms)};
  1211. };
  1212. return std::accumulate(azi.mIrs, azi.mIrs+channels, levels, proc_channel);
  1213. };
  1214. return std::accumulate(elev.mAzs, elev.mAzs+elev.mAzCount, levels, proc_azi);
  1215. };
  1216. return std::accumulate(field.mEvs, field.mEvs+field.mEvCount, levels, proc_elev);
  1217. };
  1218. const auto maxlev = std::accumulate(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount,
  1219. LevelPair{0.0, 0.0}, proc0_field);
  1220. /* Normalize using the maximum RMS of the HRIRs. The RMS measure for the
  1221. * non-filtered signal is of an impulse with equal length (to the filter):
  1222. *
  1223. * rms_impulse = sqrt(sum([ 1^2, 0^2, 0^2, ... ]) / n)
  1224. * = sqrt(1 / n)
  1225. *
  1226. * This helps keep a more consistent volume between the non-filtered signal
  1227. * and various data sets.
  1228. */
  1229. double factor{std::sqrt(1.0 / irSize) / maxlev.rms};
  1230. /* Also ensure the samples themselves won't clip. */
  1231. factor = std::min(factor, 0.99/maxlev.amp);
  1232. /* Now scale all IRs by the given factor. */
  1233. auto proc1_field = [channels,irSize,factor](HrirFdT &field) -> void
  1234. {
  1235. auto proc_elev = [channels,irSize,factor](HrirEvT &elev) -> void
  1236. {
  1237. auto proc_azi = [channels,irSize,factor](HrirAzT &azi) -> void
  1238. {
  1239. auto proc_channel = [irSize,factor](double *ir) -> void
  1240. {
  1241. std::transform(ir, ir+irSize, ir,
  1242. std::bind(std::multiplies<double>{}, _1, factor));
  1243. };
  1244. std::for_each(azi.mIrs, azi.mIrs+channels, proc_channel);
  1245. };
  1246. std::for_each(elev.mAzs, elev.mAzs+elev.mAzCount, proc_azi);
  1247. };
  1248. std::for_each(field.mEvs, field.mEvs+field.mEvCount, proc_elev);
  1249. };
  1250. std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc1_field);
  1251. }
  1252. // Calculate the left-ear time delay using a spherical head model.
  1253. static double CalcLTD(const double ev, const double az, const double rad, const double dist)
  1254. {
  1255. double azp, dlp, l, al;
  1256. azp = std::asin(std::cos(ev) * std::sin(az));
  1257. dlp = std::sqrt((dist*dist) + (rad*rad) + (2.0*dist*rad*sin(azp)));
  1258. l = std::sqrt((dist*dist) - (rad*rad));
  1259. al = (0.5 * M_PI) + azp;
  1260. if(dlp > l)
  1261. dlp = l + (rad * (al - std::acos(rad / dist)));
  1262. return dlp / 343.3;
  1263. }
  1264. // Calculate the effective head-related time delays for each minimum-phase
  1265. // HRIR. This is done per-field since distance delay is ignored.
  1266. static void CalculateHrtds(const HeadModelT model, const double radius, HrirDataT *hData)
  1267. {
  1268. uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
  1269. double customRatio{radius / hData->mRadius};
  1270. uint ti, fi, ei, ai;
  1271. if(model == HM_SPHERE)
  1272. {
  1273. for(fi = 0;fi < hData->mFdCount;fi++)
  1274. {
  1275. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  1276. {
  1277. HrirEvT *evd = &hData->mFds[fi].mEvs[ei];
  1278. for(ai = 0;ai < evd->mAzCount;ai++)
  1279. {
  1280. HrirAzT *azd = &evd->mAzs[ai];
  1281. for(ti = 0;ti < channels;ti++)
  1282. azd->mDelays[ti] = CalcLTD(evd->mElevation, azd->mAzimuth, radius, hData->mFds[fi].mDistance);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. else if(customRatio != 1.0)
  1288. {
  1289. for(fi = 0;fi < hData->mFdCount;fi++)
  1290. {
  1291. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  1292. {
  1293. HrirEvT *evd = &hData->mFds[fi].mEvs[ei];
  1294. for(ai = 0;ai < evd->mAzCount;ai++)
  1295. {
  1296. HrirAzT *azd = &evd->mAzs[ai];
  1297. for(ti = 0;ti < channels;ti++)
  1298. azd->mDelays[ti] *= customRatio;
  1299. }
  1300. }
  1301. }
  1302. }
  1303. for(fi = 0;fi < hData->mFdCount;fi++)
  1304. {
  1305. double minHrtd{std::numeric_limits<double>::infinity()};
  1306. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  1307. {
  1308. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  1309. {
  1310. HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
  1311. for(ti = 0;ti < channels;ti++)
  1312. minHrtd = std::min(azd->mDelays[ti], minHrtd);
  1313. }
  1314. }
  1315. for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
  1316. {
  1317. for(ti = 0;ti < channels;ti++)
  1318. {
  1319. for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
  1320. hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] -= minHrtd;
  1321. }
  1322. }
  1323. }
  1324. }
  1325. // Allocate and configure dynamic HRIR structures.
  1326. int PrepareHrirData(const uint fdCount, const double (&distances)[MAX_FD_COUNT],
  1327. const uint (&evCounts)[MAX_FD_COUNT], const uint azCounts[MAX_FD_COUNT * MAX_EV_COUNT],
  1328. HrirDataT *hData)
  1329. {
  1330. uint evTotal = 0, azTotal = 0, fi, ei, ai;
  1331. for(fi = 0;fi < fdCount;fi++)
  1332. {
  1333. evTotal += evCounts[fi];
  1334. for(ei = 0;ei < evCounts[fi];ei++)
  1335. azTotal += azCounts[(fi * MAX_EV_COUNT) + ei];
  1336. }
  1337. if(!fdCount || !evTotal || !azTotal)
  1338. return 0;
  1339. hData->mEvsBase.resize(evTotal);
  1340. hData->mAzsBase.resize(azTotal);
  1341. hData->mFds.resize(fdCount);
  1342. hData->mIrCount = azTotal;
  1343. hData->mFdCount = fdCount;
  1344. evTotal = 0;
  1345. azTotal = 0;
  1346. for(fi = 0;fi < fdCount;fi++)
  1347. {
  1348. hData->mFds[fi].mDistance = distances[fi];
  1349. hData->mFds[fi].mEvCount = evCounts[fi];
  1350. hData->mFds[fi].mEvStart = 0;
  1351. hData->mFds[fi].mEvs = &hData->mEvsBase[evTotal];
  1352. evTotal += evCounts[fi];
  1353. for(ei = 0;ei < evCounts[fi];ei++)
  1354. {
  1355. uint azCount = azCounts[(fi * MAX_EV_COUNT) + ei];
  1356. hData->mFds[fi].mIrCount += azCount;
  1357. hData->mFds[fi].mEvs[ei].mElevation = -M_PI / 2.0 + M_PI * ei / (evCounts[fi] - 1);
  1358. hData->mFds[fi].mEvs[ei].mIrCount += azCount;
  1359. hData->mFds[fi].mEvs[ei].mAzCount = azCount;
  1360. hData->mFds[fi].mEvs[ei].mAzs = &hData->mAzsBase[azTotal];
  1361. for(ai = 0;ai < azCount;ai++)
  1362. {
  1363. hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth = 2.0 * M_PI * ai / azCount;
  1364. hData->mFds[fi].mEvs[ei].mAzs[ai].mIndex = azTotal + ai;
  1365. hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[0] = 0.0;
  1366. hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[1] = 0.0;
  1367. hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[0] = nullptr;
  1368. hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[1] = nullptr;
  1369. }
  1370. azTotal += azCount;
  1371. }
  1372. }
  1373. return 1;
  1374. }
  1375. /* Parse the data set definition and process the source data, storing the
  1376. * resulting data set as desired. If the input name is NULL it will read
  1377. * from standard input.
  1378. */
  1379. static int ProcessDefinition(const char *inName, const uint outRate, const ChannelModeT chanMode, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const char *outName)
  1380. {
  1381. char rateStr[8+1], expName[MAX_PATH_LEN];
  1382. char startbytes[4]{};
  1383. size_t startbytecount{0u};
  1384. HrirDataT hData;
  1385. FILE *fp;
  1386. int ret;
  1387. if(!inName)
  1388. {
  1389. inName = "stdin";
  1390. fp = stdin;
  1391. }
  1392. else
  1393. {
  1394. fp = fopen(inName, "r");
  1395. if(fp == nullptr)
  1396. {
  1397. fprintf(stderr, "Error: Could not open input file '%s'\n", inName);
  1398. return 0;
  1399. }
  1400. startbytecount = fread(startbytes, 1, sizeof(startbytes), fp);
  1401. if(startbytecount != sizeof(startbytes))
  1402. {
  1403. fclose(fp);
  1404. fprintf(stderr, "Error: Could not read input file '%s'\n", inName);
  1405. return 0;
  1406. }
  1407. if(startbytes[0] == '\x89' && startbytes[1] == 'H' && startbytes[2] == 'D' &&
  1408. startbytes[3] == 'F')
  1409. {
  1410. fclose(fp);
  1411. fp = nullptr;
  1412. fprintf(stdout, "Reading HRTF data from %s...\n", inName);
  1413. if(!LoadSofaFile(inName, fftSize, truncSize, chanMode, &hData))
  1414. return 0;
  1415. }
  1416. }
  1417. if(fp != nullptr)
  1418. {
  1419. fprintf(stdout, "Reading HRIR definition from %s...\n", inName);
  1420. const bool success{LoadDefInput(fp, startbytes, startbytecount, inName, fftSize, truncSize,
  1421. chanMode, &hData)};
  1422. if(fp != stdin)
  1423. fclose(fp);
  1424. if(!success)
  1425. return 0;
  1426. }
  1427. if(equalize)
  1428. {
  1429. uint c = (hData.mChannelType == CT_STEREO) ? 2 : 1;
  1430. uint m = 1 + hData.mFftSize / 2;
  1431. std::vector<double> dfa(c * m);
  1432. if(hData.mFdCount > 1)
  1433. {
  1434. fprintf(stdout, "Balancing field magnitudes...\n");
  1435. BalanceFieldMagnitudes(&hData, c, m);
  1436. }
  1437. fprintf(stdout, "Calculating diffuse-field average...\n");
  1438. CalculateDiffuseFieldAverage(&hData, c, m, surface, limit, dfa.data());
  1439. fprintf(stdout, "Performing diffuse-field equalization...\n");
  1440. DiffuseFieldEqualize(c, m, dfa.data(), &hData);
  1441. }
  1442. fprintf(stdout, "Performing minimum phase reconstruction...\n");
  1443. ReconstructHrirs(&hData);
  1444. if(outRate != 0 && outRate != hData.mIrRate)
  1445. {
  1446. fprintf(stdout, "Resampling HRIRs...\n");
  1447. ResampleHrirs(outRate, &hData);
  1448. }
  1449. fprintf(stdout, "Truncating minimum-phase HRIRs...\n");
  1450. hData.mIrPoints = truncSize;
  1451. fprintf(stdout, "Synthesizing missing elevations...\n");
  1452. if(model == HM_DATASET)
  1453. SynthesizeOnsets(&hData);
  1454. SynthesizeHrirs(&hData);
  1455. fprintf(stdout, "Normalizing final HRIRs...\n");
  1456. NormalizeHrirs(&hData);
  1457. fprintf(stdout, "Calculating impulse delays...\n");
  1458. CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData);
  1459. snprintf(rateStr, 8, "%u", hData.mIrRate);
  1460. StrSubst(outName, "%r", rateStr, MAX_PATH_LEN, expName);
  1461. fprintf(stdout, "Creating MHR data set %s...\n", expName);
  1462. ret = StoreMhr(&hData, expName);
  1463. return ret;
  1464. }
  1465. static void PrintHelp(const char *argv0, FILE *ofile)
  1466. {
  1467. fprintf(ofile, "Usage: %s [<option>...]\n\n", argv0);
  1468. fprintf(ofile, "Options:\n");
  1469. fprintf(ofile, " -r <rate> Change the data set sample rate to the specified value and\n");
  1470. fprintf(ofile, " resample the HRIRs accordingly.\n");
  1471. fprintf(ofile, " -m Change the data set to mono, mirroring the left ear for the\n");
  1472. fprintf(ofile, " right ear.\n");
  1473. fprintf(ofile, " -f <points> Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE);
  1474. fprintf(ofile, " -e {on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off"));
  1475. fprintf(ofile, " -s {on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off"));
  1476. fprintf(ofile, " -l {<dB>|none} Specify a limit to the magnitude range of the diffuse-field\n");
  1477. fprintf(ofile, " average (default: %.2f).\n", DEFAULT_LIMIT);
  1478. fprintf(ofile, " -w <points> Specify the size of the truncation window that's applied\n");
  1479. fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE);
  1480. fprintf(ofile, " -d {dataset| Specify the model used for calculating the head-delay timing\n");
  1481. fprintf(ofile, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere"));
  1482. fprintf(ofile, " -c <radius> Use a customized head radius measured to-ear in meters.\n");
  1483. fprintf(ofile, " -i <filename> Specify an HRIR definition file to use (defaults to stdin).\n");
  1484. fprintf(ofile, " -o <filename> Specify an output file. Use of '%%r' will be substituted with\n");
  1485. fprintf(ofile, " the data set sample rate.\n");
  1486. }
  1487. // Standard command line dispatch.
  1488. int main(int argc, char *argv[])
  1489. {
  1490. const char *inName = nullptr, *outName = nullptr;
  1491. uint outRate, fftSize;
  1492. int equalize, surface;
  1493. char *end = nullptr;
  1494. ChannelModeT chanMode;
  1495. HeadModelT model;
  1496. uint truncSize;
  1497. double radius;
  1498. double limit;
  1499. int opt;
  1500. GET_UNICODE_ARGS(&argc, &argv);
  1501. if(argc < 2)
  1502. {
  1503. fprintf(stdout, "HRTF Processing and Composition Utility\n\n");
  1504. PrintHelp(argv[0], stdout);
  1505. exit(EXIT_SUCCESS);
  1506. }
  1507. outName = "./oalsoft_hrtf_%r.mhr";
  1508. outRate = 0;
  1509. chanMode = CM_AllowStereo;
  1510. fftSize = DEFAULT_FFTSIZE;
  1511. equalize = DEFAULT_EQUALIZE;
  1512. surface = DEFAULT_SURFACE;
  1513. limit = DEFAULT_LIMIT;
  1514. truncSize = DEFAULT_TRUNCSIZE;
  1515. model = DEFAULT_HEAD_MODEL;
  1516. radius = DEFAULT_CUSTOM_RADIUS;
  1517. while((opt=getopt(argc, argv, "r:mf:e:s:l:w:d:c:e:i:o:h")) != -1)
  1518. {
  1519. switch(opt)
  1520. {
  1521. case 'r':
  1522. outRate = strtoul(optarg, &end, 10);
  1523. if(end[0] != '\0' || outRate < MIN_RATE || outRate > MAX_RATE)
  1524. {
  1525. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %u to %u.\n", optarg, opt, MIN_RATE, MAX_RATE);
  1526. exit(EXIT_FAILURE);
  1527. }
  1528. break;
  1529. case 'm':
  1530. chanMode = CM_ForceMono;
  1531. break;
  1532. case 'f':
  1533. fftSize = strtoul(optarg, &end, 10);
  1534. if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MIN_FFTSIZE || fftSize > MAX_FFTSIZE)
  1535. {
  1536. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected a power-of-two between %u to %u.\n", optarg, opt, MIN_FFTSIZE, MAX_FFTSIZE);
  1537. exit(EXIT_FAILURE);
  1538. }
  1539. break;
  1540. case 'e':
  1541. if(strcmp(optarg, "on") == 0)
  1542. equalize = 1;
  1543. else if(strcmp(optarg, "off") == 0)
  1544. equalize = 0;
  1545. else
  1546. {
  1547. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected on or off.\n", optarg, opt);
  1548. exit(EXIT_FAILURE);
  1549. }
  1550. break;
  1551. case 's':
  1552. if(strcmp(optarg, "on") == 0)
  1553. surface = 1;
  1554. else if(strcmp(optarg, "off") == 0)
  1555. surface = 0;
  1556. else
  1557. {
  1558. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected on or off.\n", optarg, opt);
  1559. exit(EXIT_FAILURE);
  1560. }
  1561. break;
  1562. case 'l':
  1563. if(strcmp(optarg, "none") == 0)
  1564. limit = 0.0;
  1565. else
  1566. {
  1567. limit = strtod(optarg, &end);
  1568. if(end[0] != '\0' || limit < MIN_LIMIT || limit > MAX_LIMIT)
  1569. {
  1570. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.0f to %.0f.\n", optarg, opt, MIN_LIMIT, MAX_LIMIT);
  1571. exit(EXIT_FAILURE);
  1572. }
  1573. }
  1574. break;
  1575. case 'w':
  1576. truncSize = strtoul(optarg, &end, 10);
  1577. if(end[0] != '\0' || truncSize < MIN_TRUNCSIZE || truncSize > MAX_TRUNCSIZE || (truncSize%MOD_TRUNCSIZE))
  1578. {
  1579. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected multiple of %u between %u to %u.\n", optarg, opt, MOD_TRUNCSIZE, MIN_TRUNCSIZE, MAX_TRUNCSIZE);
  1580. exit(EXIT_FAILURE);
  1581. }
  1582. break;
  1583. case 'd':
  1584. if(strcmp(optarg, "dataset") == 0)
  1585. model = HM_DATASET;
  1586. else if(strcmp(optarg, "sphere") == 0)
  1587. model = HM_SPHERE;
  1588. else
  1589. {
  1590. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected dataset or sphere.\n", optarg, opt);
  1591. exit(EXIT_FAILURE);
  1592. }
  1593. break;
  1594. case 'c':
  1595. radius = strtod(optarg, &end);
  1596. if(end[0] != '\0' || radius < MIN_CUSTOM_RADIUS || radius > MAX_CUSTOM_RADIUS)
  1597. {
  1598. fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.2f to %.2f.\n", optarg, opt, MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS);
  1599. exit(EXIT_FAILURE);
  1600. }
  1601. break;
  1602. case 'i':
  1603. inName = optarg;
  1604. break;
  1605. case 'o':
  1606. outName = optarg;
  1607. break;
  1608. case 'h':
  1609. PrintHelp(argv[0], stdout);
  1610. exit(EXIT_SUCCESS);
  1611. default: /* '?' */
  1612. PrintHelp(argv[0], stderr);
  1613. exit(EXIT_FAILURE);
  1614. }
  1615. }
  1616. int ret = ProcessDefinition(inName, outRate, chanMode, fftSize, equalize, surface, limit,
  1617. truncSize, model, radius, outName);
  1618. if(!ret) return -1;
  1619. fprintf(stdout, "Operation completed.\n");
  1620. return EXIT_SUCCESS;
  1621. }