Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
audio_spectrum.hpp
Go to the documentation of this file.
1#pragma once
2
40
41#include "audio_metrics.hpp" // kSilenceFloorDb + buffer types
42
43#include <pulp/audio/buffer.hpp>
44
45#include <cstdint>
46#include <span>
47#include <string>
48#include <vector>
49
50namespace pulp::test::audio {
51
52// ── Window functions ──────────────────────────────────────────────────────
53
129
151inline constexpr double kDefaultKaiserBeta = 14.0;
152
155std::string window_name(Window w);
156
168 double kaiser_beta = kDefaultKaiserBeta);
169
189std::vector<double> window_coefficients(Window w, int n,
190 double kaiser_beta = kDefaultKaiserBeta);
191
192// ── Magnitude / frequency response ────────────────────────────────────────
193
198 double hz = 0.0;
199 double magnitude_db = 0.0;
200};
201
215 std::string analyzer = "magnitude_response";
216 std::string stimulus;
218 int fft_length = 0;
220 double sample_rate = 0.0;
221 double bin_hz = 0.0;
222 std::vector<ResponsePoint> full;
223 std::vector<ResponsePoint> checkpoints;
224
227 double magnitude_db_at(double hz) const;
230 double attenuation_db_at(double hz) const { return -magnitude_db_at(hz); }
231};
232
249
260 const pulp::audio::BufferView<const float>& output, double sample_rate,
261 std::span<const double> checkpoints_hz, const ResponseOptions& options = {});
262
274 const pulp::audio::BufferView<const float>& signal, double sample_rate,
275 std::span<const double> checkpoints_hz, const ResponseOptions& options = {});
276
277// ── Phase / group delay ───────────────────────────────────────────────────
278
312 double hz = 0.0;
317 double phase_rad = 0.0;
323 bool defined = false;
327 bool phase_defined = false;
328};
329
348 std::string analyzer = "group_delay";
349 std::string stimulus;
351 int fft_length = 0;
353 double sample_rate = 0.0;
354 double bin_hz = 0.0;
360 double magnitude_floor_db = 0.0;
361 std::vector<PhasePoint> full;
362 std::vector<PhasePoint> checkpoints;
363
367 bool defined_at(double hz) const;
371 bool phase_defined_at(double hz) const;
376 double group_delay_samples_at(double hz) const;
378 double group_delay_seconds_at(double hz) const;
383 double phase_radians_at(double hz) const;
389 double magnitude_db_rel_peak_at(double hz) const;
390};
391
419
502 const pulp::audio::BufferView<const float>& output, double sample_rate,
503 std::span<const double> checkpoints_hz,
504 const GroupDelayOptions& options = {});
505
506// ── THD / THD+N ───────────────────────────────────────────────────────────
507
509struct Harmonic {
510 int index = 0;
511 double hz = 0.0;
518 double magnitude = 0.0;
519 double db_below_fundamental = 0.0;
520};
521
537struct ThdResult {
538 std::string analyzer = "thd";
539 double fundamental_hz = 0.0;
541 int fft_length = 0;
543 double sample_rate = 0.0;
544 double bin_hz = 0.0;
545 bool coherent = false;
547 double thd = 0.0;
548 double thd_plus_n = 0.0;
549 std::vector<Harmonic> harmonics;
550
551 double thd_db() const;
552 double thd_plus_n_db() const;
553 double thd_percent() const { return thd * 100.0; }
554};
555
586
600 double fundamental_hz, double sample_rate,
601 const ThdOptions& options = {});
602
603// ── Tone projection ───────────────────────────────────────────────────────
604//
605// Everything below this line is FFT-free. A windowed FFT answers "what is in
606// this signal?" and pays for the answer with leakage: a 0 dB tone smears a
607// skirt across its neighbors that no window removes, only reshapes (see the
608// `Window` table above — even Kaiser at β = 14 only pushes it to −124 dB).
609// Least-squares tone projection answers the narrower question "how much of
610// THIS exact frequency is present?" and has no skirt at all, because it never
611// truncates anything into a window: it fits the basis over the whole segment
612// and subtracts. That is what makes a −100 dBc claim measurable with margin.
613//
614// Use the FFT analyzers to DISCOVER content at unknown frequencies. Use these
615// when the frequencies of interest are known in advance — which, for an
616// oscillator's harmonics and their fold-back images, they are.
617
623struct ToneFit {
624 double cycles_per_sample = 0.0;
625 double sin_gain = 0.0;
626 double cos_gain = 0.0;
627 double amplitude = 0.0;
628 double fitted_energy = 0.0;
629 double residual_energy = 0.0;
630};
631
647ToneFit fit_tone(std::span<const double> samples, double cycles_per_sample);
648
662double tone_residual_db(std::span<const double> samples,
663 double cycles_per_sample);
664
669double tone_gain_db(std::span<const double> samples, double cycles_per_sample,
670 double input_amplitude);
671
672// ── Alias / image analysis ────────────────────────────────────────────────
673
683double fold_frequency(double frequency_hz, double sample_rate);
684
696
700 int index = 0;
702 double source_hz = 0.0;
703 double hz = 0.0;
708 double amplitude = 0.0;
709 double db_below_fundamental = 0.0;
713 bool in_band = true;
719 bool resolved = true;
720};
721
753 double max_alias_frequency_hz = 20000.0;
754
769
775 int channel = 0;
776
783};
784
801 std::string analyzer = "alias";
802 double fundamental_hz = 0.0;
803 double sample_rate = 0.0;
804 double nyquist_hz = 0.0;
809 double bin_hz = 0.0;
810
816 std::vector<AliasComponent> components;
817
822 double worst_alias_hz = 0.0;
824
831
837
858
863};
864
877 double fundamental_hz, double sample_rate,
878 const AliasOptions& options = {});
879
901
912 double carrier_hz = 0.0;
913 double modulation_hz = 0.0;
916 double carrier_power = 0.0;
921 int fft_length = 0;
922 double bin_hz = 0.0;
923};
924
937 double modulation_hz, double sample_rate,
938 const ModulationSidebandOptions& options = {});
939
940} // namespace pulp::test::audio
Deterministic offline signal metrics for rendered audio buffers.
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
Definition additive_bank.hpp:218
Definition audio_artifacts.hpp:20
double tone_gain_db(std::span< const double > samples, double cycles_per_sample, double input_amplitude)
Gain of a tone at cycles_per_sample relative to input_amplitude, in dB: 20·log10(fitted_amplitude / i...
ComponentClass
How measure_aliasing classified one expected component of the ideal harmonic series h · f0.
Definition audio_spectrum.hpp:687
@ alias
h · f0 is above Nyquist: it CANNOT exist at its own frequency, so whatever energy sits at its fold-ba...
Definition audio_spectrum.hpp:694
@ harmonic
h · f0 is below Nyquist: it lands on the f0 grid, where it belongs.
Definition audio_spectrum.hpp:690
constexpr double kDefaultKaiserBeta
Default Kaiser β.
Definition audio_spectrum.hpp:151
ThdResult measure_thd(const pulp::audio::BufferView< const float > &signal, double fundamental_hz, double sample_rate, const ThdOptions &options={})
Measure THD / THD+N of signal (one channel of an already-rendered buffer) at fundamental_hz.
ResponseCurve magnitude_spectrum_curve(const pulp::audio::BufferView< const float > &signal, double sample_rate, std::span< const double > checkpoints_hz, const ResponseOptions &options={})
The signal's OWN magnitude spectrum, one channel, in dB relative to its own peak bin (loudest frequen...
double fold_frequency(double frequency_hz, double sample_rate)
Where a component at frequency_hz LANDS once sampled at sample_rate.
double window_coherent_gain(Window w, int n, double kaiser_beta=kDefaultKaiserBeta)
Coherent gain (a.k.a.
double tone_residual_db(std::span< const double > samples, double cycles_per_sample)
Energy of samples NOT explained by a tone at cycles_per_sample, in dB relative to the fitted tone's o...
ToneFit fit_tone(std::span< const double > samples, double cycles_per_sample)
Fit one sinusoid at cycles_per_sample (frequency ÷ sample rate; 0.5 is Nyquist) to samples by least s...
std::string window_name(Window w)
Human-readable window name for artifacts/messages ("rectangular", "hann", "hamming",...
constexpr double kSilenceFloorDb
Floor used when converting a zero/negative linear level to dBFS, so summaries and messages stay finit...
Definition audio_metrics.hpp:29
AliasReport measure_aliasing(const pulp::audio::BufferView< const float > &signal, double fundamental_hz, double sample_rate, const AliasOptions &options={})
Classify signal (one channel of an already-rendered buffer) against the ideal harmonic series of fund...
Window
Analysis window.
Definition audio_spectrum.hpp:91
@ hamming
Periodic Hamming.
Definition audio_spectrum.hpp:107
@ blackman
Periodic Blackman.
Definition audio_spectrum.hpp:113
@ flat_top
Periodic flat-top (5-term).
Definition audio_spectrum.hpp:122
@ kaiser
Periodic Kaiser, side-lobe level dialed by β (kaiser_beta on the options structs, default kDefaultKai...
Definition audio_spectrum.hpp:127
@ hann
Periodic Hann (0.5 - 0.5*cos(2π n / N)).
Definition audio_spectrum.hpp:102
@ rectangular
Rectangular (no taper).
Definition audio_spectrum.hpp:96
PhaseCurve measure_group_delay(const pulp::audio::BufferView< const float > &input, const pulp::audio::BufferView< const float > &output, double sample_rate, std::span< const double > checkpoints_hz, const GroupDelayOptions &options={})
Phase and group delay of output relative to input, one channel.
ModulationSidebandReport measure_modulation_sidebands(const pulp::audio::BufferView< const float > &signal, double carrier_hz, double modulation_hz, double sample_rate, const ModulationSidebandOptions &options={})
Classify signal (one channel of an already-rendered buffer) as a tone at carrier_hz modulated at modu...
ResponseCurve response_relative_to_input(const pulp::audio::BufferView< const float > &input, const pulp::audio::BufferView< const float > &output, double sample_rate, std::span< const double > checkpoints_hz, const ResponseOptions &options={})
Compute the magnitude response of output relative to input, one channel.
std::vector< double > window_coefficients(Window w, int n, double kaiser_beta=kDefaultKaiserBeta)
Coefficients of w for an n-sample analysis segment.
One expected component of the ideal series, and what was measured where it landed.
Definition audio_spectrum.hpp:699
bool resolved
False when this component's landing site could not be separated from another component's,...
Definition audio_spectrum.hpp:719
double db_below_fundamental
20·log10(amplitude / fundamental).
Definition audio_spectrum.hpp:709
bool in_band
Inside the measurement band — i.e.
Definition audio_spectrum.hpp:713
double amplitude
Linear amplitude from the joint fit, in the SAME units as the input samples — directly comparable to ...
Definition audio_spectrum.hpp:708
double hz
Where it actually landed (== source_hz for a harmonic; the fold site for an alias).
Definition audio_spectrum.hpp:703
double source_hz
h · f0: where it would sit at infinite fs.
Definition audio_spectrum.hpp:702
ComponentClass component_class
Definition audio_spectrum.hpp:701
int index
h — 1 is the fundamental.
Definition audio_spectrum.hpp:700
Options for measure_aliasing.
Definition audio_spectrum.hpp:723
int analysis_length
Samples analyzed; 0 means "to the end of the buffer".
Definition audio_spectrum.hpp:774
int analysis_offset
Samples skipped (settling / plugin latency).
Definition audio_spectrum.hpp:770
int channel
Definition audio_spectrum.hpp:775
double min_separation_bins
Minimum separation between two fitted landing sites, in units of 1 / analysis-duration (the natural r...
Definition audio_spectrum.hpp:782
int num_harmonics
Harmonics of the ideal series to account for, from the fundamental up.
Definition audio_spectrum.hpp:768
double max_alias_frequency_hz
── THE MOST IMPORTANT FIELD IN THIS HEADER.
Definition audio_spectrum.hpp:753
Three-way classification of an oscillator's output into harmonic / alias / noise, with the worst in-b...
Definition audio_spectrum.hpp:800
double fundamental_amplitude
Fitted amplitude of the fundamental — the reference every dB below is relative to.
Definition audio_spectrum.hpp:813
int num_harmonics
Definition audio_spectrum.hpp:806
double sample_rate
Definition audio_spectrum.hpp:803
double full_band_worst_alias_hz
Definition audio_spectrum.hpp:830
int analysis_length
Samples actually fitted.
Definition audio_spectrum.hpp:808
double nyquist_hz
Definition audio_spectrum.hpp:804
bool has_unresolved_in_band_alias
True when at least one ALIAS inside the band could not be resolved.
Definition audio_spectrum.hpp:862
std::string analyzer
Definition audio_spectrum.hpp:801
double worst_alias_hz
Where it landed.
Definition audio_spectrum.hpp:822
double noise_db
Everything the fit could not attribute to any expected component: RMS of the residual,...
Definition audio_spectrum.hpp:836
std::vector< AliasComponent > components
Every expected component h = 1..num_harmonics, in order, each labeled harmonic or alias by where h · ...
Definition audio_spectrum.hpp:816
double worst_alias_db
Worst (loudest) alias landing at or below max_alias_frequency_hz, in dB relative to the fundamental.
Definition audio_spectrum.hpp:821
int analysis_offset
Definition audio_spectrum.hpp:807
double bin_hz
Fit resolution: sample_rate / analysis_length.
Definition audio_spectrum.hpp:809
double fundamental_hz
Definition audio_spectrum.hpp:802
int worst_alias_index
Which h produced it (0 = none).
Definition audio_spectrum.hpp:823
double full_band_worst_alias_db
The unqualified worst alias at ANY frequency up to Nyquist.
Definition audio_spectrum.hpp:829
double max_alias_frequency_hz
The band qualifier that was used.
Definition audio_spectrum.hpp:805
double detection_floor_db
The quietest single component this measurement could have detected, in dB relative to the fundamental...
Definition audio_spectrum.hpp:857
Options for the phase/group-delay analyzer. Lengths must be powers of two.
Definition audio_spectrum.hpp:393
int channel
Definition audio_spectrum.hpp:410
int fft_length
Power of two; also the impulse render length.
Definition audio_spectrum.hpp:396
Window window
Rectangular by default, for the same reason as the response analyzer (an impulse at frame 0 would be ...
Definition audio_spectrum.hpp:409
double magnitude_floor_db
Magnitude gate in dB below the curve's peak transfer magnitude.
Definition audio_spectrum.hpp:417
int analysis_offset
Samples skipped before the analysis segment.
Definition audio_spectrum.hpp:404
One harmonic's contribution to a distortion measurement.
Definition audio_spectrum.hpp:509
double db_below_fundamental
0 for the fundamental, negative below.
Definition audio_spectrum.hpp:519
int index
1 = fundamental, 2 = 2nd harmonic, ...
Definition audio_spectrum.hpp:510
double hz
Definition audio_spectrum.hpp:511
double magnitude
Linear bin magnitude, analyzer-relative scale (the FFT backend's absolute normalization is arbitrary ...
Definition audio_spectrum.hpp:518
Options for measure_modulation_sidebands.
Definition audio_spectrum.hpp:881
int fft_length
Definition audio_spectrum.hpp:897
double band_low_hz
The residual is summed over [band_low_hz, band_high_hz].
Definition audio_spectrum.hpp:889
int max_order
Lines counted as the modulation's own: the carrier +/- k times the modulation frequency for k = 1....
Definition audio_spectrum.hpp:884
double tolerance_bins
Half-width of each expected line, in bins: the window's main lobe, so a line's own skirt is counted a...
Definition audio_spectrum.hpp:887
int channel
Definition audio_spectrum.hpp:899
double kaiser_beta
Definition audio_spectrum.hpp:896
double band_high_hz
Definition audio_spectrum.hpp:890
Window window
A Kaiser window: a Hann window's side lobes (-31 dB, falling 18 dB an octave) around a carrier that i...
Definition audio_spectrum.hpp:895
int analysis_offset
Samples skipped (settling / plugin latency).
Definition audio_spectrum.hpp:898
Where a steady tone's energy went after a periodic modulation was applied to it.
Definition audio_spectrum.hpp:911
int fft_length
Definition audio_spectrum.hpp:921
double carrier_hz
Definition audio_spectrum.hpp:912
double bin_hz
Definition audio_spectrum.hpp:922
double modulation_hz
Definition audio_spectrum.hpp:913
double sideband_db
Power at the carrier +/- k * modulation_hz, re the carrier, dB.
Definition audio_spectrum.hpp:918
double carrier_power
Power at the carrier's own line (the carrier itself); the reference the two ratios are relative to.
Definition audio_spectrum.hpp:916
double residual_db
Power everywhere else in the band, re the carrier, dB.
Definition audio_spectrum.hpp:920
Phase / group-delay curve of a transfer function.
Definition audio_spectrum.hpp:347
std::string stimulus
Definition audio_spectrum.hpp:349
double phase_radians_at(double hz) const
Unwrapped transfer phase in radians at hz.
std::string analyzer
Definition audio_spectrum.hpp:348
double group_delay_samples_at(double hz) const
Group delay in samples at the bin nearest hz.
bool defined_at(double hz) const
True when the bin nearest hz carries enough energy for its group delay to be a measurement.
int analysis_offset
Definition audio_spectrum.hpp:352
Window window
Definition audio_spectrum.hpp:350
std::vector< PhasePoint > checkpoints
Requested frequencies only.
Definition audio_spectrum.hpp:362
double magnitude_db_rel_peak_at(double hz) const
Transfer magnitude at hz in dB relative to this curve's own peak transfer magnitude — always defined ...
double magnitude_floor_db
Magnitude gate, in dB relative to the curve's peak transfer magnitude.
Definition audio_spectrum.hpp:360
int fft_length
Definition audio_spectrum.hpp:351
double bin_hz
Definition audio_spectrum.hpp:354
double group_delay_seconds_at(double hz) const
Group delay in seconds at hz (samples / sample_rate). NaN when undefined.
std::vector< PhasePoint > full
Bin 0..N/2, monotonic in hz.
Definition audio_spectrum.hpp:361
double sample_rate
Definition audio_spectrum.hpp:353
bool phase_defined_at(double hz) const
True when the bin nearest hz is defined_at AND the unwrap reached it over an unbroken run of defined ...
One point on a phase/group-delay curve.
Definition audio_spectrum.hpp:311
double hz
Definition audio_spectrum.hpp:312
double group_delay_samples
-dφ/dω in samples; NaN unless defined.
Definition audio_spectrum.hpp:319
bool defined
Gates group_delay_samples.
Definition audio_spectrum.hpp:323
bool phase_defined
Gates phase_rad.
Definition audio_spectrum.hpp:327
double magnitude_db_rel_peak
Transfer magnitude in dB relative to the curve's own peak transfer magnitude (peak bin = 0 dB,...
Definition audio_spectrum.hpp:315
double phase_rad
Unwrapped transfer phase; NaN unless phase_defined.
Definition audio_spectrum.hpp:317
Magnitude/frequency-response curve.
Definition audio_spectrum.hpp:214
std::vector< ResponsePoint > full
Bin 0..N/2, monotonic in hz.
Definition audio_spectrum.hpp:222
double sample_rate
Definition audio_spectrum.hpp:220
std::string analyzer
Definition audio_spectrum.hpp:215
int analysis_offset
Definition audio_spectrum.hpp:219
int fft_length
Definition audio_spectrum.hpp:218
std::string stimulus
e.g. "impulse" / "log_sweep 20..20000".
Definition audio_spectrum.hpp:216
double bin_hz
Frequency resolution (sample_rate / fft_length).
Definition audio_spectrum.hpp:221
double attenuation_db_at(double hz) const
Positive attenuation in dB at hz (0 dB = unity, larger = more cut).
Definition audio_spectrum.hpp:230
std::vector< ResponsePoint > checkpoints
Requested frequencies only.
Definition audio_spectrum.hpp:223
double magnitude_db_at(double hz) const
Magnitude (dB) at the bin nearest hz on the full curve.
Window window
Definition audio_spectrum.hpp:217
Options for the response analyzer. Lengths must be powers of two.
Definition audio_spectrum.hpp:234
int channel
Output channel analyzed.
Definition audio_spectrum.hpp:245
double kaiser_beta
β for Window::kaiser; ignored by every other window.
Definition audio_spectrum.hpp:247
int analysis_offset
Samples skipped before the analysis segment.
Definition audio_spectrum.hpp:236
int fft_length
Power of two; also the impulse render length.
Definition audio_spectrum.hpp:235
Window window
Rectangular by default: the stimulus is an impulse at frame 0, so a Hann window (zero weight at n=0) ...
Definition audio_spectrum.hpp:244
One point on a response curve: frequency and magnitude in dB.
Definition audio_spectrum.hpp:197
double hz
Definition audio_spectrum.hpp:198
double magnitude_db
Definition audio_spectrum.hpp:199
Options for the THD analyzer.
Definition audio_spectrum.hpp:558
int num_harmonics
Harmonics above the fundamental to include.
Definition audio_spectrum.hpp:561
int channel
Definition audio_spectrum.hpp:562
int fft_length
Definition audio_spectrum.hpp:559
Window non_coherent_window
Window used when the tone is NOT bin-coherent (a coherent tone always uses rectangular — it leaks not...
Definition audio_spectrum.hpp:582
float amplitude
Sine amplitude (linear) used when a scenario-driven analyzer synthesizes the stimulus tone (see test/...
Definition audio_spectrum.hpp:568
int analysis_offset
Definition audio_spectrum.hpp:560
double kaiser_beta
β for Window::kaiser; ignored by every other window.
Definition audio_spectrum.hpp:584
Total harmonic distortion result.
Definition audio_spectrum.hpp:537
double thd_plus_n
Ratio (all non-fundamental / fundamental).
Definition audio_spectrum.hpp:548
std::string analyzer
Definition audio_spectrum.hpp:538
double fundamental_hz
Definition audio_spectrum.hpp:539
double bin_hz
Definition audio_spectrum.hpp:544
Window window
Definition audio_spectrum.hpp:540
std::vector< Harmonic > harmonics
[0] = fundamental, then 2nd, 3rd, ...
Definition audio_spectrum.hpp:549
double sample_rate
Definition audio_spectrum.hpp:543
int num_harmonics
Harmonics summed (beyond the fundamental).
Definition audio_spectrum.hpp:546
int fft_length
Definition audio_spectrum.hpp:541
double thd_percent() const
Definition audio_spectrum.hpp:553
int analysis_offset
Definition audio_spectrum.hpp:542
double thd
Ratio (Σ harmonics / fundamental).
Definition audio_spectrum.hpp:547
bool coherent
True when the tone is bin-coherent (see above).
Definition audio_spectrum.hpp:545
double thd_plus_n_db() const
20·log10(thd_plus_n).
double thd_db() const
20·log10(thd), kSilenceFloorDb at zero.
Least-squares fit of a single sinusoid at a known frequency.
Definition audio_spectrum.hpp:623
double fitted_energy
Σ of the fitted tone squared.
Definition audio_spectrum.hpp:628
double amplitude
hypot(sin_gain, cos_gain).
Definition audio_spectrum.hpp:627
double sin_gain
Coefficient of sin(2π·f·n).
Definition audio_spectrum.hpp:625
double cos_gain
Coefficient of cos(2π·f·n).
Definition audio_spectrum.hpp:626
double residual_energy
Σ of (samples − fitted) squared.
Definition audio_spectrum.hpp:629
double cycles_per_sample
The frequency fitted (f / sample_rate).
Definition audio_spectrum.hpp:624