2 * SOFA info utility for inspecting SOFA file metrics and determining HRTF
3 * utility compatible layouts.
5 * Copyright (C) 2018-2019 Christopher Fitzgerald
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.
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.
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.
21 * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
27 #include <string_view>
30 #include "alnumeric.h"
34 #include "sofa-support.h"
38 #include "win_main_utf8.h"
42 using uint
= unsigned int;
44 void PrintSofaAttributes(const char *prefix
, MYSOFA_ATTRIBUTE
*attribute
)
48 printf("%s.%s: %s\n", prefix
, attribute
->name
, attribute
->value
);
49 attribute
= attribute
->next
;
53 void PrintSofaArray(const char *prefix
, MYSOFA_ARRAY
*array
, bool showValues
=true)
55 PrintSofaAttributes(prefix
, array
->attributes
);
58 const auto values
= al::span
{array
->values
, array
->elements
};
59 for(size_t i
{0u};i
< values
.size();++i
)
60 printf("%s[%zu]: %.6f\n", prefix
, i
, values
[i
]);
63 printf("%s[...]: <%u values suppressed>\n", prefix
, array
->elements
);
66 /* Attempts to produce a compatible layout. Most data sets tend to be
67 * uniform and have the same major axis as used by OpenAL Soft's HRTF model.
68 * This will remove outliers and produce a maximally dense layout when
69 * possible. Those sets that contain purely random measurements or use
70 * different major axes will fail.
72 void PrintCompatibleLayout(const al::span
<const float> xyzs
)
76 auto fds
= GetCompatibleLayout(xyzs
);
79 fputs("No compatible field layouts in SOFA file.\n", stdout
);
84 for(size_t fi
{0u};fi
< fds
.size();++fi
)
86 for(uint ei
{fds
[fi
].mEvStart
};ei
< fds
[fi
].mEvCount
;++ei
)
87 used_elems
+= fds
[fi
].mAzCounts
[ei
];
90 printf("Compatible Layout (%u of %zu measurements):\n\ndistance = %.3f", used_elems
,
91 xyzs
.size()/3, fds
[0].mDistance
);
92 for(size_t fi
{1u};fi
< fds
.size();fi
++)
93 printf(", %.3f", fds
[fi
].mDistance
);
95 fputs("\nazimuths = ", stdout
);
96 for(size_t fi
{0u};fi
< fds
.size();++fi
)
98 for(uint ei
{0u};ei
< fds
[fi
].mEvStart
;++ei
)
99 printf("%d%s", fds
[fi
].mAzCounts
[fds
[fi
].mEvCount
- 1 - ei
], ", ");
100 for(uint ei
{fds
[fi
].mEvStart
};ei
< fds
[fi
].mEvCount
;++ei
)
101 printf("%d%s", fds
[fi
].mAzCounts
[ei
],
102 (ei
< (fds
[fi
].mEvCount
- 1)) ? ", " :
103 (fi
< (fds
.size() - 1)) ? ";\n " : "\n");
107 // Load and inspect the given SOFA file.
108 void SofaInfo(const std::string
&filename
)
111 MySofaHrtfPtr sofa
{mysofa_load(filename
.c_str(), &err
)};
114 printf("Error: Could not load source file '%s' (%s).\n", filename
.c_str(),
119 /* NOTE: Some valid SOFA files are failing this check. */
120 err
= mysofa_check(sofa
.get());
122 printf("Warning: Supposedly malformed source file '%s' (%s).\n", filename
.c_str(),
125 mysofa_tocartesian(sofa
.get());
127 PrintSofaAttributes("Info", sofa
->attributes
);
129 printf("Measurements: %u\n", sofa
->M
);
130 printf("Receivers: %u\n", sofa
->R
);
131 printf("Emitters: %u\n", sofa
->E
);
132 printf("Samples: %u\n", sofa
->N
);
134 PrintSofaArray("SampleRate", &sofa
->DataSamplingRate
);
135 PrintSofaArray("DataDelay", &sofa
->DataDelay
);
136 PrintSofaArray("SourcePosition", &sofa
->SourcePosition
, false);
138 PrintCompatibleLayout(al::span
{sofa
->SourcePosition
.values
, sofa
->M
*3_uz
});
141 int main(al::span
<std::string_view
> args
)
145 printf("Usage: %.*s <sofa-file>\n", al::sizei(args
[0]), args
[0].data());
149 SofaInfo(std::string
{args
[1]});
156 int main(int argc
, char **argv
)
159 auto args
= std::vector
<std::string_view
>(static_cast<unsigned int>(argc
));
160 std::copy_n(argv
, args
.size(), args
.begin());
161 return main(al::span
{args
});