54 double value = std::numeric_limits<double>::quiet_NaN();
100 std::int64_t streamOrigin = 0) noexcept
109 contextSilent_ =
true;
111 nextFrame_ = origin_ = streamOrigin;
114 requested.
begin < streamOrigin || requested.
end < requested.
begin ||
120 regionMeter_.prepare(spec);
132 std::int64_t firstFrame)
noexcept
136 const int count = block.getNumSamples();
137 if (count < 0 || count > maxBlockSize_ || block.getNumChannels() != result_.
channels ||
138 firstFrame < 0 || firstFrame > std::numeric_limits<std::int64_t>::max() - count)
141 if (count == 0)
return true;
142 for (
int ch = 0; ch < result_.
channels; ++ch)
144 const auto end = std::min(firstFrame + count, result_.
requested.
end);
147 const auto usedBegin = observe ? firstFrame : begin;
149 for (
auto frame = usedBegin; frame < end; ++frame)
150 for (
int ch = 0; ch < result_.
channels; ++ch)
151 if (!std::isfinite(block.getChannel(ch)[frame - firstFrame]))
155 feed(continuousMeter_, block, 0,
static_cast<int>(end - firstFrame));
156 for (
auto frame = firstFrame; frame < end; ++frame)
157 for (
int ch = 0; ch < result_.
channels; ++ch)
158 contextSilent_ &= block.getChannel(ch)[frame - firstFrame] == T(0);
162 feed(regionMeter_, block,
static_cast<int>(begin - firstFrame),
163 static_cast<int>(end - begin));
164 for (
auto frame = begin; frame < end; ++frame)
165 for (
int ch = 0; ch < result_.
channels; ++ch)
166 energy_.
add(
static_cast<double>(block.getChannel(ch)[frame - firstFrame]));
169 nextFrame_ = firstFrame + count;
181 if (sealed_)
return result_;
189 markLoudness(result_.
region, validity);
196 result_.
rms = { frames ? energy_.
rms(
static_cast<double>(frames) * result_.
channels) :
197 std::numeric_limits<double>::quiet_NaN(), validity, result_.
measured };
199 std::numeric_limits<double>::quiet_NaN(), validity, result_.
measured };
200 regionMeter_.finalizeTruePeak();
201 result_.
truePeakDbtp = { frames ?
static_cast<double>(regionMeter_.getTruePeakDb()) :
202 std::numeric_limits<double>::quiet_NaN(), validity, result_.
measured };
203 if (!regionMeter_.isMeasurementValid())
204 result_.
truePeakDbtp = { std::numeric_limits<double>::quiet_NaN(),
208 result_.
continuous = loudness(continuousMeter_,
209 { origin_, frames ? result_.
measured.
end : origin_ }, contextSilent_);
214 bool fail(
Status status)
noexcept { result_.
status = status;
return false; }
215 void feed(LoudnessMeter<T>& meter, AudioBufferView<const T> block,
int offset,
int count)
noexcept
217 if (result_.
channels == 1) meter.process(block.getChannel(0) + offset, count);
218 else meter.process(block.getChannel(0) + offset, block.getChannel(1) + offset, count);
220 static void markLoudness(Loudness& reading,
Validity validity)
noexcept
222 reading.momentary.validity = reading.shortTerm.validity =
223 reading.integrated.validity = reading.range.validity = validity;
225 static Loudness loudness(
const LoudnessMeter<T>& meter, Interval input,
bool silent)
noexcept
229 const auto info = meter.getMeasurementInfo();
230 out.committedEnd = input.begin + info.committedFrames;
231 out.pendingFrames = info.pendingFrames;
232 out.hopFrames = info.hopFrames;
233 out.integratedBlocks = info.integratedBlocks;
234 out.rangeBlocks = info.rangeBlocks;
235 if (input.begin == input.end) { markLoudness(out,
Validity::Empty);
return out; }
237 const auto metric = [&](
double value,
int hops,
bool gated, std::uint64_t blocks,
238 bool cumulative) -> Measurement
240 const auto length =
static_cast<std::int64_t
>(hops) * info.hopFrames;
241 if (info.committedFrames < length)
243 const Interval support { cumulative ? input.begin : out.committedEnd - length,
245 if (gated && blocks == 0 && !silent)
249 out.momentary = metric(meter.getMomentaryLUFS(), 4,
false, 0,
false);
250 out.shortTerm = metric(meter.getShortTermLUFS(), 30,
false, 0,
false);
251 out.integrated = metric(meter.getIntegratedLUFS(), 4,
true, info.integratedBlocks,
true);
252 out.range = metric(meter.getLoudnessRange(), 30,
true, info.rangeBlocks,
true);
256 LoudnessMeter<T> regionMeter_, continuousMeter_;
257 detail::ScaledSumSquares energy_;
259 std::int64_t origin_ = 0, nextFrame_ = 0;
260 int maxBlockSize_ = 0;
261 bool contextSilent_ =
true, sealed_ =
false;
bool prepare(const AudioSpec &spec, Interval requested, Context context=Context::Independent, std::int64_t streamOrigin=0) noexcept
Starts a fresh measurement, resetting all filters, windows and gates. streamOrigin is the first frame...