DSPark 1.8.0
Header-only C++20 DSP for real-time and offline audio
Loading...
Searching...
No Matches
dspark::PitchDetector< T > Class Template Reference

Thread-safe YIN pitch detector with lock-free readout. More...

#include <PitchDetector.h>

Public Member Functions

void prepare (double sampleRate, int windowSize=0, int hopSize=0)
 Prepares the detector and allocates internal structures.
 
void pushSamples (std::span< const T > samples) noexcept
 Pushes audio samples into the analysis buffer.
 
T getFrequencyHz () const noexcept
 Returns the detected frequency in Hz safely from any thread.
 
T getConfidence () const noexcept
 Returns the detection confidence [0.0 - 1.0] safely from any thread.
 
int getMidiNote () const noexcept
 Returns nearest MIDI note (69 = A4), or -1 if unvoiced.
 
T getCentsOffset () const noexcept
 Returns cent offset from the nearest MIDI note [-50, +50].
 
void setThreshold (T threshold) noexcept
 Sets the sensitivity threshold (clamped to 0.01 - 0.5). Lower is stricter. Non-finite values are ignored.
 
T getThreshold () const noexcept
 Returns the sensitivity threshold.
 
int getWindowSize () const noexcept
 
int getHopSize () const noexcept
 
void reset () noexcept
 Resets state buffers. Not thread-safe with pushSamples().
 

Detailed Description

template<FloatType T>
class dspark::PitchDetector< T >

Thread-safe YIN pitch detector with lock-free readout.

A non-finite stretch in the input signal simply reads as "unvoiced" (frequency 0, confidence 0) and flushes out of the analysis window on its own: the pipeline holds no recursive state, so the detector self-recovers once clean samples refill the window.

Template Parameters
TSample type (float or double).

Definition at line 54 of file PitchDetector.h.

Member Function Documentation

◆ getCentsOffset()

template<FloatType T>
T dspark::PitchDetector< T >::getCentsOffset ( ) const
inlinenoexcept

Returns cent offset from the nearest MIDI note [-50, +50].

Definition at line 232 of file PitchDetector.h.

◆ getConfidence()

template<FloatType T>
T dspark::PitchDetector< T >::getConfidence ( ) const
inlinenoexcept

Returns the detection confidence [0.0 - 1.0] safely from any thread.

Definition at line 218 of file PitchDetector.h.

◆ getFrequencyHz()

template<FloatType T>
T dspark::PitchDetector< T >::getFrequencyHz ( ) const
inlinenoexcept

Returns the detected frequency in Hz safely from any thread.

Definition at line 212 of file PitchDetector.h.

◆ getHopSize()

template<FloatType T>
int dspark::PitchDetector< T >::getHopSize ( ) const
inlinenoexcept
Returns
Samples between detections in effect (windowSize/4 by default), i.e. one detection every getHopSize()/sampleRate s.

Definition at line 267 of file PitchDetector.h.

◆ getMidiNote()

template<FloatType T>
int dspark::PitchDetector< T >::getMidiNote ( ) const
inlinenoexcept

Returns nearest MIDI note (69 = A4), or -1 if unvoiced.

Definition at line 224 of file PitchDetector.h.

◆ getThreshold()

template<FloatType T>
T dspark::PitchDetector< T >::getThreshold ( ) const
inlinenoexcept

Returns the sensitivity threshold.

Definition at line 251 of file PitchDetector.h.

◆ getWindowSize()

template<FloatType T>
int dspark::PitchDetector< T >::getWindowSize ( ) const
inlinenoexcept
Returns
The analysis window (samples) in effect: the automatic choice if prepare() was called with windowSize <= 0, the clamped explicit request otherwise (member default 2048 before the first successful prepare()). The lowest reachable fundamental is sampleRate / (getWindowSize()/2 - 1).

Definition at line 263 of file PitchDetector.h.

◆ prepare()

template<FloatType T>
void dspark::PitchDetector< T >::prepare ( double  sampleRate,
int  windowSize = 0,
int  hopSize = 0 
)
inline

Prepares the detector and allocates internal structures.

Must be called before audio processing begins. Zero allocations happen after this point. Release-safe: a non-finite or non-positive sample rate is ignored (no-op keeping the previous configuration); an explicit windowSize is clamped to [64, 1 << 20].

Parameters
sampleRateThe system sample rate in Hz.
windowSizeAnalysis window in samples. Values <= 0 (the default) select the AUTOMATIC window: the smallest power of two in [512, 16384] spanning at least 2048/48000 s (~42.7 ms) at sampleRate – 2048 at 44.1/48 kHz, 4096 at 88.2/96 kHz, 8192 at 176.4/192 kHz, 16384 at 384 kHz, 512 at 8 kHz. Read it back with getWindowSize().
hopSizeSamples between detections. Values <= 0 (the default) select windowSize/4, which is 512 at the 44.1/48 kHz window and keeps the detection RATE at ~one per 10.7 ms at every sample rate. Explicit positive values are clamped to [1, windowSize].

THE WINDOW IS A REGISTER, NOT A COUNT. YIN searches lags tau in [2, windowSize/2), so the lowest fundamental the detector can reach is

fmin = fs / (windowSize/2 - 1)      (approximately 2*fs/windowSize)

– a property of the RATIO fs/windowSize alone. Measured, identical across rates at equal ratio: fs/windowSize = 23.44 Hz recovers down to A1 55 Hz (48 kHz/2048, 96 kHz/4096, 192 kHz/8192 all agree to within 0.01 cents); fs/windowSize = 5.86 Hz reaches C1 32.7 Hz. Holding the COUNT fixed instead moves the floor with the rate: an explicit 2048 window gives fmin 46.9 Hz at 48 kHz but 93.8 Hz at 96 kHz and 187.7 Hz at 192 kHz, so E1/A1/E2 – and at 176.4/192 kHz A2 as well – are simply never reported. Out-of-register notes read as unvoiced (0 Hz, confidence 0) rather than as a wrong pitch: measured across 44.1..192 kHz on band-limited sawtooths from E1 to A5, every reading was either correct to within 0.1 cents or absent, never confidently wrong. The automatic window keeps fmin at 43.1 Hz (44.1 kHz family) / 46.9 Hz (48 kHz family) from 8 kHz all the way to 384 kHz, where it reaches the 16384 clamp. ABOVE 384 kHz the ceiling binds and the floor climbs again (measured 93.8 Hz at 768 kHz) – documented, not fixed; pass an explicit window there. For a lower floor at any rate pass an explicit window: fmin scales as fs/windowSize, so doubling the window halves it.

Definition at line 102 of file PitchDetector.h.

◆ pushSamples()

template<FloatType T>
void dspark::PitchDetector< T >::pushSamples ( std::span< const T >  samples)
inlinenoexcept

Pushes audio samples into the analysis buffer.

Automatically triggers pitch detection when the hop size is reached. Lock-free and allocation-free. No-op before prepare().

Note
The difference function runs as a frequency-domain cross-correlation (YIN-FFT): O(N log N) per detection - roughly 20x faster than the direct O(windowSize^2) form at the 2048-sample window the automatic policy picks at 44.1/48 kHz, and generally fine on the audio thread. Under the automatic policy the detection RATE is rate-invariant (hop = window/4, about one detection per 10.7 ms), but CPU per second of audio is NOT: each detection costs O(N log N) and N follows the rate, so the per-second cost grows by a measured ~2.0x at 96 kHz and ~4.6x at 192 kHz relative to 48 kHz (35.6 / 71.2 / 162.4 ms of CPU per 10 s of audio at 48/96/192 kHz; float, automatic window, g++ 13 -O2, min of 15 runs pinned to six cores with taskset -c 0-5 on an otherwise idle host, per-point spread under 4% – absolute numbers vary by machine, the growth tracks N log N). Against the old fixed-2048 default at the SAME rate the automatic window costs roughly 15% more (162.4 vs 142.0 ms at 192 kHz). prepare()-time heap grows the same way: ~160 KB at 44.1/48 kHz, ~320 KB at 88.2/96 kHz, ~640 KB at 176.4/192 kHz (float); the audio path stays allocation-free. Budget from these figures, not from the rate alone. For very low-latency callbacks you can still feed an SPSC queue (Core/SpscQueue.h) and detect on a worker.
Parameters
samplesSpan of input audio data (mono).

Definition at line 185 of file PitchDetector.h.

◆ reset()

template<FloatType T>
void dspark::PitchDetector< T >::reset ( )
inlinenoexcept

Resets state buffers. Not thread-safe with pushSamples().

Definition at line 270 of file PitchDetector.h.

◆ setThreshold()

template<FloatType T>
void dspark::PitchDetector< T >::setThreshold ( T  threshold)
inlinenoexcept

Sets the sensitivity threshold (clamped to 0.01 - 0.5). Lower is stricter. Non-finite values are ignored.

Definition at line 244 of file PitchDetector.h.


The documentation for this class was generated from the following file: