aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/makehrtf.cpp225
1 files changed, 118 insertions, 107 deletions
diff --git a/utils/makehrtf.cpp b/utils/makehrtf.cpp
index 52aa5404..af6a40ca 100644
--- a/utils/makehrtf.cpp
+++ b/utils/makehrtf.cpp
@@ -84,12 +84,20 @@
#include <limits>
#include <vector>
#include <complex>
+#include <numeric>
#include <algorithm>
+#include <functional>
#include "mysofa.h"
#include "win_main_utf8.h"
+namespace {
+
+using namespace std::placeholders;
+
+} // namespace
+
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
@@ -2323,14 +2331,14 @@ static void ResampleHrirs(const uint rate, HrirDataT *hData)
* the two HRIRs that bound the coordinate along with a factor for
* calculating the continuous HRIR using interpolation.
*/
-static void CalcAzIndices(const HrirDataT *hData, const uint fi, const uint ei, const double az, uint *a0, uint *a1, double *af)
+static void CalcAzIndices(const HrirFdT &field, const uint ei, const double az, uint *a0, uint *a1, double *af)
{
- double f = (2.0*M_PI + az) * hData->mFds[fi].mEvs[ei].mAzCount / (2.0*M_PI);
- uint i = static_cast<uint>(f) % hData->mFds[fi].mEvs[ei].mAzCount;
+ double f{(2.0*M_PI + az) * field.mEvs[ei].mAzCount / (2.0*M_PI)};
+ uint i{static_cast<uint>(f) % field.mEvs[ei].mAzCount};
f -= std::floor(f);
*a0 = i;
- *a1 = (i + 1) % hData->mFds[fi].mEvs[ei].mAzCount;
+ *a1 = (i + 1) % field.mEvs[ei].mAzCount;
*af = f;
}
@@ -2340,38 +2348,38 @@ static void CalcAzIndices(const HrirDataT *hData, const uint fi, const uint ei,
*/
static void SynthesizeOnsets(HrirDataT *hData)
{
- uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
- uint ti, fi, oi, ai, ei, a0, a1;
- double t, of, af;
+ const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
- for(fi = 0;fi < hData->mFdCount;fi++)
+ auto proc_field = [channels](HrirFdT &field) -> void
{
- if(hData->mFds[fi].mEvStart <= 0)
- continue;
- oi = hData->mFds[fi].mEvStart;
+ const uint oi{field.mEvStart};
+ if(oi <= 0) return;
- for(ti = 0;ti < channels;ti++)
+ for(uint ti{0u};ti < channels;ti++)
{
- t = 0.0;
- for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++)
- t += hData->mFds[fi].mEvs[oi].mAzs[ai].mDelays[ti];
- hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti] = 1.32e-4 + (t / hData->mFds[fi].mEvs[oi].mAzCount);
- for(ei = 1;ei < hData->mFds[fi].mEvStart;ei++)
+ double t{0.0};
+ for(uint ai{0u};ai < field.mEvs[oi].mAzCount;ai++)
+ t += field.mEvs[oi].mAzs[ai].mDelays[ti];
+ field.mEvs[0].mAzs[0].mDelays[ti] = 1.32e-4 + (t / field.mEvs[oi].mAzCount);
+
+ for(uint ei{1u};ei < field.mEvStart;ei++)
{
- of = static_cast<double>(ei) / hData->mFds[fi].mEvStart;
- for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
+ const double of{static_cast<double>(ei) / field.mEvStart};
+ for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
{
- CalcAzIndices(hData, fi, oi, hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af);
- hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] = Lerp(
- hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti],
- Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mDelays[ti],
- hData->mFds[fi].mEvs[oi].mAzs[a1].mDelays[ti], af),
- of
- );
+ uint a0, a1;
+ double af;
+
+ CalcAzIndices(field, oi, field.mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af);
+ double other{Lerp(field.mEvs[oi].mAzs[a0].mDelays[ti],
+ field.mEvs[oi].mAzs[a1].mDelays[ti], af)};
+ field.mEvs[ei].mAzs[ai].mDelays[ti] = Lerp(field.mEvs[0].mAzs[0].mDelays[ti],
+ other, of);
}
}
}
- }
+ };
+ std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc_field);
}
/* Attempt to synthesize any missing HRIRs at the bottom elevations of each
@@ -2381,106 +2389,106 @@ static void SynthesizeOnsets(HrirDataT *hData)
*/
static void SynthesizeHrirs(HrirDataT *hData)
{
- uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
- uint n = hData->mIrPoints;
- uint ti, fi, ai, ei, i;
- double lp[4], s0, s1;
- double of, b;
- uint a0, a1;
- double af;
+ const uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1;
+ const uint irSize{hData->mIrPoints};
+ const double beta{3.5e-6 * hData->mIrRate};
- for(fi = 0;fi < hData->mFdCount;fi++)
+ auto proc_field = [channels,irSize,beta](HrirFdT &field) -> void
{
- const uint oi = hData->mFds[fi].mEvStart;
- if(oi <= 0) continue;
+ const uint oi{field.mEvStart};
+ if(oi <= 0) return;
- for(ti = 0;ti < channels;ti++)
+ for(uint ti{0u};ti < channels;ti++)
{
- for(i = 0;i < n;i++)
- hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = 0.0;
- for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++)
+ for(uint i{0u};i < irSize;i++)
+ field.mEvs[0].mAzs[0].mIrs[ti][i] = 0.0;
+ for(uint ai{0u};ai < field.mEvs[oi].mAzCount;ai++)
{
- for(i = 0;i < n;i++)
- hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] += hData->mFds[fi].mEvs[oi].mAzs[ai].mIrs[ti][i] /
- hData->mFds[fi].mEvs[oi].mAzCount;
+ for(uint i{0u};i < irSize;i++)
+ field.mEvs[0].mAzs[0].mIrs[ti][i] += field.mEvs[oi].mAzs[ai].mIrs[ti][i] /
+ field.mEvs[oi].mAzCount;
}
- for(ei = 1;ei < hData->mFds[fi].mEvStart;ei++)
+ for(uint ei{1u};ei < field.mEvStart;ei++)
{
- of = static_cast<double>(ei) / hData->mFds[fi].mEvStart;
- b = (1.0 - of) * (3.5e-6 * hData->mIrRate);
- for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
+ const double of{static_cast<double>(ei) / field.mEvStart};
+ const double b{(1.0 - of) * beta};
+ for(uint ai{0u};ai < field.mEvs[ei].mAzCount;ai++)
{
- CalcAzIndices(hData, fi, oi, hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af);
- lp[0] = 0.0;
- lp[1] = 0.0;
- lp[2] = 0.0;
- lp[3] = 0.0;
- for(i = 0;i < n;i++)
+ uint a0, a1;
+ double af;
+
+ CalcAzIndices(field, oi, field.mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af);
+ double lp[4]{};
+ for(uint i{0u};i < irSize;i++)
{
- s0 = hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i];
- s1 = Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mIrs[ti][i],
- hData->mFds[fi].mEvs[oi].mAzs[a1].mIrs[ti][i], af);
+ double s0{field.mEvs[0].mAzs[0].mIrs[ti][i]};
+ const double s1{Lerp(field.mEvs[oi].mAzs[a0].mIrs[ti][i],
+ field.mEvs[oi].mAzs[a1].mIrs[ti][i], af)};
s0 = Lerp(s0, s1, of);
lp[0] = Lerp(s0, lp[0], b);
lp[1] = Lerp(lp[0], lp[1], b);
lp[2] = Lerp(lp[1], lp[2], b);
lp[3] = Lerp(lp[2], lp[3], b);
- hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[ti][i] = lp[3];
+ field.mEvs[ei].mAzs[ai].mIrs[ti][i] = lp[3];
}
}
}
- b = 3.5e-6 * hData->mIrRate;
- lp[0] = 0.0;
- lp[1] = 0.0;
- lp[2] = 0.0;
- lp[3] = 0.0;
- for(i = 0;i < n;i++)
+ const double b{beta};
+ double lp[4]{};
+ for(uint i{0u};i < irSize;i++)
{
- s0 = hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i];
+ const double s0{field.mEvs[0].mAzs[0].mIrs[ti][i]};
lp[0] = Lerp(s0, lp[0], b);
lp[1] = Lerp(lp[0], lp[1], b);
lp[2] = Lerp(lp[1], lp[2], b);
lp[3] = Lerp(lp[2], lp[3], b);
- hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = lp[3];
+ field.mEvs[0].mAzs[0].mIrs[ti][i] = lp[3];
}
}
- hData->mFds[fi].mEvStart = 0;
- }
+ field.mEvStart = 0;
+ };
+ std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc_field);
}
// The following routines assume a full set of HRIRs for all elevations.
// Normalize the HRIR set and slightly attenuate the result.
-static void NormalizeHrirs(const HrirDataT *hData)
+static void NormalizeHrirs(HrirDataT *hData)
{
- uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
- uint n{hData->mIrPoints};
- uint ti, fi, ei, ai, i;
- double maxLevel{0.0};
- double maxRms{0.0};
+ const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
+ const uint irSize{hData->mIrPoints};
- for(fi = 0;fi < hData->mFdCount;fi++)
+ /* Find the maximum amplitude and RMS out of all the IRs. */
+ struct LevelPair { double amp, rms; };
+ auto proc0_field = [channels,irSize](const LevelPair levels, const HrirFdT &field) -> LevelPair
{
- for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
+ auto proc_elev = [channels,irSize](const LevelPair levels, const HrirEvT &elev) -> LevelPair
{
- for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
+ auto proc_azi = [channels,irSize](const LevelPair levels, const HrirAzT &azi) -> LevelPair
{
- HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
- for(ti = 0;ti < channels;ti++)
+ auto proc_channel = [irSize](const LevelPair levels, const double *ir) -> LevelPair
{
- double rms{0.0};
-
- for(i = 0;i < n;i++)
- {
- maxLevel = std::max(std::abs(azd->mIrs[ti][i]), maxLevel);
- rms += azd->mIrs[ti][i] * azd->mIrs[ti][i];
- }
- rms = std::sqrt(rms / n);
- maxRms = std::max(rms, maxRms);
- }
- }
- }
- }
+ /* Calculate the peak amplitude and RMS of this IR. */
+ auto current = std::accumulate(ir, ir+irSize, LevelPair{0.0, 0.0},
+ [](const LevelPair current, const double impulse) -> LevelPair
+ {
+ return LevelPair{std::max(std::abs(impulse), current.amp),
+ current.rms + impulse*impulse};
+ });
+ current.rms = std::sqrt(current.rms / irSize);
+
+ /* Accumulate levels by taking the maximum amplitude and RMS. */
+ return LevelPair{std::max(current.amp, levels.amp),
+ std::max(current.rms, levels.rms)};
+ };
+ return std::accumulate(azi.mIrs, azi.mIrs+channels, levels, proc_channel);
+ };
+ return std::accumulate(elev.mAzs, elev.mAzs+elev.mAzCount, levels, proc_azi);
+ };
+ return std::accumulate(field.mEvs, field.mEvs+field.mEvCount, levels, proc_elev);
+ };
+ const auto maxlev = std::accumulate(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount,
+ LevelPair{0.0, 0.0}, proc0_field);
/* Normalize using the maximum RMS of the HRIRs. The RMS measure for the
* non-filtered signal is of an impulse with equal length (to the filter):
@@ -2491,27 +2499,30 @@ static void NormalizeHrirs(const HrirDataT *hData)
* This helps keep a more consistent volume between the non-filtered signal
* and various data sets.
*/
- double factor{std::sqrt(1.0 / n) / maxRms};
+ double factor{std::sqrt(1.0 / irSize) / maxlev.rms};
- /* Also ensure the impulse samples themselves won't clip. */
- factor = std::min(factor, 0.99/maxLevel);
+ /* Also ensure the samples themselves won't clip. */
+ factor = std::min(factor, 0.99/maxlev.amp);
- for(fi = 0;fi < hData->mFdCount;fi++)
+ /* Now scale all IRs by the given factor. */
+ auto proc1_field = [channels,irSize,factor](HrirFdT &field) -> void
{
- for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++)
+ auto proc_elev = [channels,irSize,factor](HrirEvT &elev) -> void
{
- for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++)
+ auto proc_azi = [channels,irSize,factor](HrirAzT &azi) -> void
{
- HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
-
- for(ti = 0;ti < channels;ti++)
+ auto proc_channel = [irSize,factor](double *ir) -> void
{
- for(i = 0;i < n;i++)
- azd->mIrs[ti][i] *= factor;
- }
- }
- }
- }
+ std::transform(ir, ir+irSize, ir,
+ std::bind(std::multiplies<double>{}, _1, factor));
+ };
+ std::for_each(azi.mIrs, azi.mIrs+channels, proc_channel);
+ };
+ std::for_each(elev.mAzs, elev.mAzs+elev.mAzCount, proc_azi);
+ };
+ std::for_each(field.mEvs, field.mEvs+field.mEvCount, proc_elev);
+ };
+ std::for_each(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, proc1_field);
}
// Calculate the left-ear time delay using a spherical head model.