HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_loudest_bin_magnitude.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // max()
4#include <complex> // complex, norm()
5
7#include "metrics/hart_metric_query.hpp"
8#include "metrics/hart_metrics_common.hpp" // ChannelSubsets
9#include "hart_slice.hpp"
11#include "hart_units.hpp" // Unit
12#include "hart_utils.hpp" // nan()
13
14namespace hart
15{
16
17/// @brief Calculates the magnitude of the loudest FFT bin
18/// @details
19/// Finds the maximum-magnitude FFT bin independently for each channel.
20/// Use reducers to combine multi-channel results (see @ref Reducers).
21///
22/// Supports:
23/// - `Unit::linear` (native/default)
24/// - `Unit::dB` as linear ratio, not power
25///
26/// This metric operates on FFT bins exactly as stored in the Spectrum.
27///
28/// Typical use cases:
29/// - alias detection
30/// - spur detection
31/// - harmonic inspection
32/// - FFT sanity checks
33/// - spectral leakage diagnostics
34///
35/// Usage examples:
36/// @code
37/// // Loudest spectral component in dB
38/// const double loudestDb = loudestBinMagnitude (spectrum).as (dB).get();
39///
40/// // Loudest bin only inside a frequency range
41/// const double loudestMidBandDb =
42/// loudestBinMagnitude (spectrum)
43/// .as (dB)
44/// .at (Slice::frequency (500_Hz, 2000_Hz))
45/// .get();
46///
47/// // Loudest bin, but only inside a specific channel subset, as a
48/// // linear value (not dB). Calculated per chanel, then averaged.
49/// const double loudestBinLinear =
50/// loudestBinMagnitude (spectrum)
51/// .as (linear)
52/// .ch ({0, 2, 4})
53/// .get (mean());
54///
55/// @endcode
56///
57/// @param spectrum Input frequency-domain spectrum
58/// @throws hart::UnitError if unsupported unit is requested
59/// @ingroup Metrics
60inline MetricQuery<double> loudestBinMagnitude (const Spectrum& spectrum)
61{
62 typename MetricQuery<double>::SingleChannelMetricEvaluator evaluator =
63 [&spectrum]
64 (size_t channel, const Slice& slice, Unit requestedUnit)
65 -> double
66 {
67 hassert (channel < spectrum.getNumChannels());
68
69 const std::pair<size_t, size_t> binIndices = spectrum.getBinIndices (slice);
70 const size_t startBin = binIndices.first;
71 const size_t stopBin = binIndices.second;
72
73 if (slice.isEmpty() || stopBin - startBin == 0)
74 return hart::nan<double>();
75
76 hassert (startBin < stopBin);
77 hassert (stopBin <= spectrum.getNumBins());
78
79 const std::complex<double>* bins = spectrum[channel];
80 double maxSquaredMagnitude = 0.0;
81
82 for (size_t bin = startBin; bin < stopBin; ++bin)
83 maxSquaredMagnitude = std::max (std::norm (bins[bin]), maxSquaredMagnitude);
84
85 const double maxMagnitude = sqrt (maxSquaredMagnitude);
86
87 switch (requestedUnit)
88 {
89 case Unit::native:
90 case Unit::linear:
91 {
92 return maxMagnitude;
93 }
94
95 case Unit::dB:
96 {
97 return hart::ratioToDecibels (maxMagnitude);
98 }
99
100 default:
101 {
102 HART_THROW_OR_RETURN (hart::UnitError, "Unsupported unit", hart::nan<double>());
103 }
104 }
105 };
106
107 const size_t numChannels = spectrum.getNumChannels();
108 return MetricQuery<double> (
109 std::move (evaluator),
110 numChannels,
112 );
113}
114
115} // namespace hart
Manages the metrics calculations.
MetricQuery(SingleChannelMetricEvaluator evaluator, size_t totalNumChannels, std::vector< size_t > &&defaultChannelsToProcess)
Create a metric query object for a metric that operates on one channel at a time.
Frequency-domain representation of a multi-channel audio signal.
const std::complex< double > * operator[](size_t channel) const
Returns pointer to read-only magnitudes of a specific channel.
std::pair< size_t, size_t > getBinIndices(const Slice &slice) const
Returns a pair of indices representing a provided slice.
size_t getNumBins() const
Returns number of frequency bins per channel.
size_t getNumChannels() const
Returns number of channels.
Thrown when some metric is requested to return a value in an unsupported unit.
#define hassert(condition)
Triggers a HartAssertException if the condition is false
#define HART_THROW_OR_RETURN(ExceptionType, message, returnValue)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns a specified ...
MetricQuery< double > loudestBinMagnitude(const Spectrum &spectrum)
Calculates the magnitude of the loudest FFT bin.
FloatType nan()
Returns a quiet NaN value for the given floating-point type.
static SampleType ratioToDecibels(SampleType valueLinear)
Converts linear value (ratio) to dB.
Unit
Represents a physical unit.
@ dB
Value of something in decibels. Can represent voltage, power, or a domain-specific unit like "LUFS" o...
@ native
Default (native) unit of whatever returns some value.
@ linear
Value of a sample (voltage) in a linear domain.
Helpers to generate common default channel subsets.
static std::vector< size_t > allChannels(size_t numChannels)
Represents a slice of analysis data.
bool isEmpty() const