🛠️🐜 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.

139 lines
4.2 KiB

  1. /*
  2. * SOFA info utility for inspecting SOFA file metrics and determining HRTF
  3. * utility compatible layouts.
  4. *
  5. * Copyright (C) 2018-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. #include <stdio.h>
  24. #include <memory>
  25. #include <vector>
  26. #include "sofa-support.h"
  27. #include "mysofa.h"
  28. #include "win_main_utf8.h"
  29. using uint = unsigned int;
  30. static void PrintSofaAttributes(const char *prefix, struct MYSOFA_ATTRIBUTE *attribute)
  31. {
  32. while(attribute)
  33. {
  34. fprintf(stdout, "%s.%s: %s\n", prefix, attribute->name, attribute->value);
  35. attribute = attribute->next;
  36. }
  37. }
  38. static void PrintSofaArray(const char *prefix, struct MYSOFA_ARRAY *array)
  39. {
  40. PrintSofaAttributes(prefix, array->attributes);
  41. for(uint i{0u};i < array->elements;i++)
  42. fprintf(stdout, "%s[%u]: %.6f\n", prefix, i, array->values[i]);
  43. }
  44. /* Attempts to produce a compatible layout. Most data sets tend to be
  45. * uniform and have the same major axis as used by OpenAL Soft's HRTF model.
  46. * This will remove outliers and produce a maximally dense layout when
  47. * possible. Those sets that contain purely random measurements or use
  48. * different major axes will fail.
  49. */
  50. static void PrintCompatibleLayout(const uint m, const float *xyzs)
  51. {
  52. fputc('\n', stdout);
  53. auto fds = GetCompatibleLayout(m, xyzs);
  54. if(fds.empty())
  55. {
  56. fprintf(stdout, "No compatible field layouts in SOFA file.\n");
  57. return;
  58. }
  59. uint used_elems{0};
  60. for(size_t fi{0u};fi < fds.size();++fi)
  61. {
  62. for(uint ei{fds[fi].mEvStart};ei < fds[fi].mEvCount;++ei)
  63. used_elems += fds[fi].mAzCounts[ei];
  64. }
  65. fprintf(stdout, "Compatible Layout (%u of %u measurements):\n\ndistance = %.3f", used_elems, m,
  66. fds[0].mDistance);
  67. for(size_t fi{1u};fi < fds.size();fi++)
  68. fprintf(stdout, ", %.3f", fds[fi].mDistance);
  69. fprintf(stdout, "\nazimuths = ");
  70. for(size_t fi{0u};fi < fds.size();++fi)
  71. {
  72. for(uint ei{0u};ei < fds[fi].mEvStart;++ei)
  73. fprintf(stdout, "%d%s", fds[fi].mAzCounts[fds[fi].mEvCount - 1 - ei], ", ");
  74. for(uint ei{fds[fi].mEvStart};ei < fds[fi].mEvCount;++ei)
  75. fprintf(stdout, "%d%s", fds[fi].mAzCounts[ei],
  76. (ei < (fds[fi].mEvCount - 1)) ? ", " :
  77. (fi < (fds.size() - 1)) ? ";\n " : "\n");
  78. }
  79. }
  80. // Load and inspect the given SOFA file.
  81. static void SofaInfo(const char *filename)
  82. {
  83. int err;
  84. MySofaHrtfPtr sofa{mysofa_load(filename, &err)};
  85. if(!sofa)
  86. {
  87. fprintf(stdout, "Error: Could not load source file '%s' (%s).\n", filename,
  88. SofaErrorStr(err));
  89. return;
  90. }
  91. /* NOTE: Some valid SOFA files are failing this check. */
  92. err = mysofa_check(sofa.get());
  93. if(err != MYSOFA_OK)
  94. fprintf(stdout, "Warning: Supposedly malformed source file '%s' (%s).\n", filename,
  95. SofaErrorStr(err));
  96. mysofa_tocartesian(sofa.get());
  97. PrintSofaAttributes("Info", sofa->attributes);
  98. fprintf(stdout, "Measurements: %u\n", sofa->M);
  99. fprintf(stdout, "Receivers: %u\n", sofa->R);
  100. fprintf(stdout, "Emitters: %u\n", sofa->E);
  101. fprintf(stdout, "Samples: %u\n", sofa->N);
  102. PrintSofaArray("SampleRate", &sofa->DataSamplingRate);
  103. PrintSofaArray("DataDelay", &sofa->DataDelay);
  104. PrintCompatibleLayout(sofa->M, sofa->SourcePosition.values);
  105. }
  106. int main(int argc, char *argv[])
  107. {
  108. if(argc != 2)
  109. {
  110. fprintf(stdout, "Usage: %s <sofa-file>\n", argv[0]);
  111. return 0;
  112. }
  113. SofaInfo(argv[1]);
  114. return 0;
  115. }