diff options
Diffstat (limited to 'utils/sofa-info.cpp')
-rw-r--r-- | utils/sofa-info.cpp | 274 |
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]); |