aboutsummaryrefslogtreecommitdiffstats
path: root/utils/sofa-info.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sofa-info.cpp')
-rw-r--r--utils/sofa-info.cpp274
1 files changed, 21 insertions, 253 deletions
diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp
index bc5b709a..6dffef44 100644
--- a/utils/sofa-info.cpp
+++ b/utils/sofa-info.cpp
@@ -23,45 +23,16 @@
#include <stdio.h>
-#include <array>
-#include <cmath>
#include <memory>
#include <vector>
-#include <mysofa.h>
+#include "sofa-support.h"
-#include "win_main_utf8.h"
+#include "mysofa.h"
+#include "win_main_utf8.h"
using uint = unsigned int;
-using double3 = std::array<double,3>;
-
-struct MySofaDeleter {
- void operator()(MYSOFA_HRTF *sofa) { mysofa_free(sofa); }
-};
-using MySofaHrtfPtr = std::unique_ptr<MYSOFA_HRTF,MySofaDeleter>;
-
-// Per-field measurement info.
-struct HrirFdT {
- double mDistance{0.0};
- uint mEvCount{0u};
- uint mEvStart{0u};
- std::vector<uint> mAzCounts;
-};
-
-static const char *SofaErrorStr(int err)
-{
- switch(err)
- {
- case MYSOFA_OK: return "OK";
- case MYSOFA_INVALID_FORMAT: return "Invalid format";
- case MYSOFA_UNSUPPORTED_FORMAT: return "Unsupported format";
- case MYSOFA_INTERNAL_ERROR: return "Internal error";
- case MYSOFA_NO_MEMORY: return "Out of memory";
- case MYSOFA_READ_ERROR: return "Read error";
- }
- return "Unknown";
-}
static void PrintSofaAttributes(const char *prefix, struct MYSOFA_ATTRIBUTE *attribute)
{
@@ -75,121 +46,10 @@ static void PrintSofaAttributes(const char *prefix, struct MYSOFA_ATTRIBUTE *att
static void PrintSofaArray(const char *prefix, struct MYSOFA_ARRAY *array)
{
PrintSofaAttributes(prefix, array->attributes);
-
for(uint i{0u};i < array->elements;i++)
fprintf(stdout, "%s[%u]: %.6f\n", prefix, i, array->values[i]);
}
-/* Produces a sorted array of unique elements from a particular axis of the
- * triplets array. The filters are used to focus on particular coordinates
- * of other axes as necessary. The epsilons are used to constrain the
- * equality of unique elements.
- */
-static uint GetUniquelySortedElems(const uint m, const double3 *aers, const uint axis,
- const double *const (&filters)[3], const double (&epsilons)[3], double *elems)
-{
- uint count{0u};
- for(uint i{0u};i < m;++i)
- {
- const double elem{aers[i][axis]};
-
- uint j;
- for(j = 0;j < 3;j++)
- {
- if(filters[j] && std::fabs(aers[i][j] - *filters[j]) > epsilons[j])
- break;
- }
- if(j < 3)
- continue;
-
- for(j = 0;j < count;j++)
- {
- const double delta{elem - elems[j]};
-
- if(delta > epsilons[axis])
- continue;
-
- if(delta >= -epsilons[axis])
- break;
-
- for(uint k{count};k > j;k--)
- elems[k] = elems[k - 1];
-
- elems[j] = elem;
- count++;
- break;
- }
-
- if(j >= count)
- elems[count++] = elem;
- }
-
- return count;
-}
-
-/* Given a list of elements, this will produce the smallest step size that
- * can uniformly cover a fair portion of the list. Ideally this will be over
- * half, but in degenerate cases this can fall to a minimum of 5 (the lower
- * limit on elevations necessary to build a layout).
- */
-static double GetUniformStepSize(const double epsilon, const uint m, const double *elems)
-{
- auto steps = std::vector<double>(m, 0.0);
- auto counts = std::vector<uint>(m, 0u);
- uint count{0u};
-
- for(uint stride{1u};stride < m/2;stride++)
- {
- for(uint i{0u};i < m-stride;i++)
- {
- const double step{elems[i + stride] - elems[i]};
-
- uint j;
- for(j = 0;j < count;j++)
- {
- if(std::fabs(step - steps[j]) < epsilon)
- {
- counts[j]++;
- break;
- }
- }
-
- if(j >= count)
- {
- steps[j] = step;
- counts[j] = 1;
- count++;
- }
- }
-
- for(uint i{1u};i < count;i++)
- {
- if(counts[i] > counts[0])
- {
- steps[0] = steps[i];
- counts[0] = counts[i];
- }
- }
-
- count = 1;
-
- if(counts[0] > m/2)
- break;
- }
-
- if(counts[0] > 255)
- {
- uint i{2u};
- while(counts[0]/i > 255 && (counts[0]%i) != 0)
- ++i;
- counts[0] /= i;
- steps[0] *= i;
- }
- if(counts[0] > 5)
- return steps[0];
- return 0.0;
-}
-
/* Attempts to produce a compatible layout. Most data sets tend to be
* uniform and have the same major axis as used by OpenAL Soft's HRTF model.
* This will remove outliers and produce a maximally dense layout when
@@ -198,127 +58,36 @@ static double GetUniformStepSize(const double epsilon, const uint m, const doubl
*/
static void PrintCompatibleLayout(const uint m, const float *xyzs)
{
- auto aers = std::vector<double3>(m, double3{});
- auto elems = std::vector<double>(m, {});
+ fputc('\n', stdout);
- fprintf(stdout, "\n");
-
- for(uint i{0u};i < m;++i)
+ auto fds = GetCompatibleLayout(m, xyzs);
+ if(fds.empty())
{
- float aer[3]{xyzs[i*3], xyzs[i*3 + 1], xyzs[i*3 + 2]};
- mysofa_c2s(&aer[0]);
- aers[i][0] = aer[0];
- aers[i][1] = aer[1];
- aers[i][2] = aer[2];
- }
-
- uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr },
- { 0.1, 0.1, 0.001 }, elems.data())};
- if(fdCount > (m / 3))
- {
- fprintf(stdout, "Incompatible layout (inumerable radii).\n");
+ fprintf(stdout, "No compatible field layouts in SOFA file.\n");
return;
}
- std::vector<HrirFdT> fds(fdCount);
- for(uint fi{0u};fi < fdCount;fi++)
- fds[fi].mDistance = elems[fi];
-
- for(uint fi{0u};fi < fdCount;fi++)
+ uint used_elems{0};
+ for(size_t fi{0u};fi < fds.size();++fi)
{
- const double dist{fds[fi].mDistance};
- uint evCount{GetUniquelySortedElems(m, aers.data(), 1, { nullptr, nullptr, &dist },
- { 0.1, 0.1, 0.001 }, elems.data())};
-
- if(evCount > (m / 3))
- {
- fprintf(stdout, "Incompatible layout (innumerable elevations).\n");
- return;
- }
-
- double step{GetUniformStepSize(0.1, evCount, elems.data())};
- if(step <= 0.0)
- {
- fprintf(stdout, "Incompatible layout (non-uniform elevations).\n");
- return;
- }
-
- uint evStart{0u};
- for(uint ei{0u};ei < evCount;ei++)
- {
- double ev{90.0 + elems[ei]};
- double eif{std::round(ev / step)};
- const uint ev_start{static_cast<uint>(eif)};
-
- if(std::fabs(eif - static_cast<double>(ev_start)) < (0.1/step))
- {
- evStart = ev_start;
- break;
- }
- }
-
- evCount = static_cast<uint>(std::round(180.0 / step)) + 1;
- if(evCount < 5)
- {
- fprintf(stdout, "Incompatible layout (too few uniform elevations).\n");
- return;
- }
-
- fds[fi].mEvCount = evCount;
- fds[fi].mEvStart = evStart;
- fds[fi].mAzCounts.resize(evCount);
- auto &azCounts = fds[fi].mAzCounts;
-
- for(uint ei{evStart};ei < evCount;ei++)
- {
- double ev{-90.0 + static_cast<double>(ei)*180.0/static_cast<double>(evCount - 1)};
- uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist },
- { 0.1, 0.1, 0.001 }, elems.data())};
-
- if(azCount > (m / 3))
- {
- fprintf(stdout, "Incompatible layout (innumerable azimuths).\n");
- return;
- }
-
- if(ei > 0 && ei < (evCount - 1))
- {
- step = GetUniformStepSize(0.1, azCount, elems.data());
- if(step <= 0.0)
- {
- fprintf(stdout, "Incompatible layout (non-uniform azimuths).\n");
- return;
- }
-
- azCounts[ei] = static_cast<uint>(std::round(360.0f / step));
- }
- else if(azCount != 1)
- {
- fprintf(stdout, "Incompatible layout (non-singular poles).\n");
- return;
- }
- else
- {
- azCounts[ei] = 1;
- }
- }
-
- for(uint ei{0u};ei < evStart;ei++)
- azCounts[ei] = azCounts[evCount - ei - 1];
+ for(uint ei{fds[fi].mEvStart};ei < fds[fi].mEvCount;++ei)
+ used_elems += fds[fi].mAzCounts[ei];
}
- fprintf(stdout, "Compatible Layout:\n\ndistance = %.3f", fds[0].mDistance);
-
- for(uint fi{1u};fi < fdCount;fi++)
+ fprintf(stdout, "Compatible Layout (%u of %u measurements):\n\ndistance = %.3f", used_elems, m,
+ fds[0].mDistance);
+ for(size_t fi{1u};fi < fds.size();fi++)
fprintf(stdout, ", %.3f", fds[fi].mDistance);
fprintf(stdout, "\nazimuths = ");
- for(uint fi{0u};fi < fdCount;fi++)
+ for(size_t fi{0u};fi < fds.size();++fi)
{
- for(uint ei{0u};ei < fds[fi].mEvCount;ei++)
+ for(uint ei{0u};ei < fds[fi].mEvStart;++ei)
+ fprintf(stdout, "%d%s", fds[fi].mAzCounts[fds[fi].mEvCount - 1 - ei], ", ");
+ for(uint ei{fds[fi].mEvStart};ei < fds[fi].mEvCount;++ei)
fprintf(stdout, "%d%s", fds[fi].mAzCounts[ei],
(ei < (fds[fi].mEvCount - 1)) ? ", " :
- (fi < (fdCount - 1)) ? ";\n " : "\n");
+ (fi < (fds.size() - 1)) ? ";\n " : "\n");
}
}
@@ -329,7 +98,8 @@ static void SofaInfo(const char *filename)
MySofaHrtfPtr sofa{mysofa_load(filename, &err)};
if(!sofa)
{
- fprintf(stdout, "Error: Could not load source file '%s'.\n", filename);
+ fprintf(stdout, "Error: Could not load source file '%s' (%s).\n", filename,
+ SofaErrorStr(err));
return;
}
@@ -356,8 +126,6 @@ static void SofaInfo(const char *filename)
int main(int argc, char *argv[])
{
- GET_UNICODE_ARGS(&argc, &argv);
-
if(argc != 2)
{
fprintf(stdout, "Usage: %s <sofa-file>\n", argv[0]);