42 analyze(
double sampleRate,
int hop, std::size_t count, FrameAt frameAt,
43 double minimumBpm,
double maximumBpm,
double tightness,
OfflineSession &job,
44 std::pmr::memory_resource *workspace =
nullptr)
46 if (!std::isfinite(sampleRate) || sampleRate < 8000 || sampleRate > 384000 || hop < 1 ||
47 hop > sampleRate || !std::isfinite(minimumBpm) || !std::isfinite(maximumBpm) ||
48 minimumBpm < 20 || maximumBpm > 480 || minimumBpm > maximumBpm ||
49 !std::isfinite(tightness) || tightness < 0.001 ||
50 tightness >
static_cast<double>(std::numeric_limits<T>::max()))
54 if (count >
static_cast<std::size_t
>(std::numeric_limits<int>::max() / 2))
61 tracker.allocationAccount_ = {&job, [](
void *context, std::size_t bytes) {
65 tracker.allocationAccount_ = {
67 [](
void *context, std::size_t bytes, std::size_t alignment) {
68 return static_cast<std::pmr::memory_resource *
>(context)->allocate(bytes, alignment);
70 [](
void *context,
void *p, std::size_t bytes, std::size_t alignment) {
71 static_cast<std::pmr::memory_resource *
>(context)->deallocate(p, bytes, alignment);
73 tracker.offlineCheckpointContext_ = &job;
74 tracker.offlineCheckpoint_ = [](
void *context) {
77 tracker.sampleRate_ = sampleRate;
79 tracker.frameRate_ = sampleRate / hop;
81 tracker.
setTempoRange(
static_cast<T
>(minimumBpm),
static_cast<T
>(maximumBpm));
83 tracker.env_.reserve(count);
84 tracker.envRef_.reserve(count);
85 for (
auto ®isters : tracker.envReg_)
86 registers.reserve(count);
87 std::int64_t previous = 0;
88 for (std::size_t i = 0; i < count; ++i)
92 static_cast<std::int64_t
>(count));
93 const auto frame = frameAt(i);
94 if (!std::isfinite(frame.value) || frame.value < T(0))
96 if (i && (previous > std::numeric_limits<std::int64_t>::max() - hop ||
97 frame.referenceSample != previous + hop))
100 if ((frame.referenceSample < std::numeric_limits<std::int64_t>::min() + hop) ||
101 (frame.referenceSample > std::numeric_limits<std::int64_t>::max() - hop))
103 tracker.env_.push_back(
static_cast<double>(frame.value));
104 tracker.envRef_.push_back(frame.referenceSample);
105 for (std::size_t r = 0; r < frame.registers.size(); ++r)
107 const auto value = frame.registers[r];
108 if (!std::isfinite(value) || value < T(0))
110 tracker.envReg_[r].push_back(
static_cast<double>(value));
112 previous = frame.referenceSample;
119 } output{result, job};
120 const auto summary = tracker.finishEnvelope(
121 &output, [](
void *context, std::span<const std::int64_t> beats) {
122 auto &out = *
static_cast<Output *
>(context);
125 out.result.positions = out.job.template allocate<std::int64_t>(beats.size());
126 std::copy(beats.begin(), beats.end(), out.result.positions.get());
127 out.result.count = beats.size();
137 static_cast<std::int64_t
>(count));