|
DSPark 1.8.0
Header-only C++20 DSP for real-time and offline audio
|
Key estimation by profile correlation over an accumulated chroma. More...
#include <KeyDetector.h>
Classes | |
| struct | Key |
| One key estimate. More... | |
Public Types | |
| enum class | Profile : std::uint8_t { KrumhanslKessler = 0 , Temperley } |
| Which published key profile to correlate against. More... | |
Public Member Functions | |
| void | prepare (const AudioSpec &spec, int windowSize=0) |
| Prepares the analysis pipeline. | |
| void | reset () noexcept |
| Clears the accumulated chroma and forgets the estimate. | |
| void | setProfile (Profile p) noexcept |
| Selects the key profile (default KrumhanslKessler). | |
| Profile | getProfile () const noexcept |
| int | getWindowSize () const noexcept |
| void | processBlock (AudioBufferView< const T > buffer) noexcept |
| Feeds a block (channels averaged to mono). Allocation-free. | |
| void | pushSamples (std::span< const T > samples) noexcept |
| Feeds mono samples directly. Allocation-free. | |
| Key | getKey () const noexcept |
| const std::array< T, 12 > & | chroma () const noexcept |
| The accumulated chroma the estimate was formed from. | |
| std::uint64_t | getFrameCount () const noexcept |
Static Public Member Functions | |
| static int | getKeyName (const Key &key, char *dest, int size) noexcept |
Writes a key name ("C", "F#m", "Bbm") into dest. | |
Static Public Attributes | |
| static constexpr std::array< double, 12 > | kKrumhanslKesslerMajor |
| Krumhansl & Kessler (1982) probe-tone ratings, major. | |
| static constexpr std::array< double, 12 > | kKrumhanslKesslerMinor |
| Krumhansl & Kessler (1982) probe-tone ratings, minor. | |
| static constexpr std::array< double, 12 > | kTemperleyMajor |
| Temperley (1999) revised profiles, major. | |
| static constexpr std::array< double, 12 > | kTemperleyMinor |
| Temperley (1999) revised profiles, minor. | |
Key estimation by profile correlation over an accumulated chroma.
Threading: getKey() is the atomic foreign-thread publication. chroma() is a stream-owner reference readout and is valid only on the thread that owns processBlock() / pushSamples(), between that thread's own calls. Calling chroma() from another thread while processing runs would race the non-atomic chroma storage.
| T | Sample type (float or double). |
Definition at line 92 of file KeyDetector.h.
|
strong |
Which published key profile to correlate against.
The two are different objects, not two spellings of one:
Beware the name in other software: several widely used libraries label their "Temperley" profile with the corpus-derived Kostka-Payne probabilities of Temperley, "Music and Probability" (2007), which are a different vector entirely. The values here are the 1999 ones the architecture's citation names.
| Enumerator | |
|---|---|
| KrumhanslKessler | Krumhansl & Kessler 1982 probe-tone ratings. |
| Temperley | Temperley 1999 revised profiles. |
Definition at line 118 of file KeyDetector.h.
|
inlinenoexcept |
The accumulated chroma the estimate was formed from.
Twelve bins, index 0 = C, normalized to sum to 1 so it can be compared against a profile directly and does not grow with programme length. That normalization is a property of this readout and of nothing else: the correlation behind getKey() is computed from the unnormalized accumulator, and scaling a chroma cannot move a Pearson correlation. All zeros before the first frame is accumulated.
stream-owner reference readout: the reference is to state owned by the thread that calls processBlock()/pushSamples(), and it is valid on that thread only, between that thread's own calls. A caller on any other thread would be reading these words while the owning thread writes them. getKey() is the readout for any other thread.
Definition at line 297 of file KeyDetector.h.
|
inlinenoexcept |
Definition at line 300 of file KeyDetector.h.
|
inlinenoexcept |
confidence is the numerical top-two margin, (top - numericalSecond) / top, clamped to [0, 1]. It answers one question – how far ahead the winner is – and deliberately not "is this the right
key": a passage that is genuinely between two keys reports a low margin whether or not the winner is correct, and a short excerpt that happens to fit one profile well reports a high one.
runnerUpPitchClass and runnerUpMinor are always numerical rank two of the same 24-score ordering as the winner. Exact score ties follow the fixed candidate order C major through B major, then C minor through B minor. relativeAlternativePitchClass, relativeAlternativeMinor and relativeAlternativeRank separately name the winner's relative key and its actual 1-based numerical rank. This keeps estimator rank and a useful relative-key policy visible as two different facts.
The clamp is not cosmetic. The numerical runner-up correlation can be negative, in which case the raw ratio exceeds 1; and where the winning correlation is itself zero or negative – silence, noise, or a chroma with no tonal structure at all – the ratio has no meaning and the confidence is reported as 0 rather than as whatever the division produced.
Definition at line 276 of file KeyDetector.h.
|
inlinestaticnoexcept |
Writes a key name ("C", "F#m", "Bbm") into dest.
| key | Key to name. |
| dest | Destination buffer. |
| size | Capacity of dest (8+ recommended). |
Spelling follows the framework's own convention for the tonic, so a key whose tonic is usually written flat is written flat.
Definition at line 312 of file KeyDetector.h.
|
inlinenoexcept |
Definition at line 200 of file KeyDetector.h.
|
inlinenoexcept |
Definition at line 212 of file KeyDetector.h.
|
inline |
Prepares the analysis pipeline.
| spec | Audio environment specification. |
| windowSize | Analysis window in samples, passed straight to the shared chroma front end. Values <= 0 (the default) select the AUTOMATIC window: the smallest power of two in [1024, 16384] spanning at least 4096/48000 s (~85 ms) at spec.sampleRate – 4096 at 44.1/48 kHz, 8192 at 88.2/96 kHz, 16384 at 176.4/192 kHz. Explicit values are clamped to [1024, 16384]. |
The register the estimate is trustworthy in is the front end's, because the chroma is the front end's. At the automatic window the Hann main lobe stays at or below 46.9 Hz for every rate up to 192 kHz, which keeps notes from about F#3 to E5 resolved; below that floor adjacent-semitone leakage adds pitch classes that were never played, and above MIDI 83 (B5) there are no bins at all, so an octave-6 melody contributes nothing. A key estimate is a sum over those bins and inherits every one of those limits. See ChordDetector::prepare() for the measured register table.
Definition at line 159 of file KeyDetector.h.
|
inlinenoexcept |
Feeds a block (channels averaged to mono). Allocation-free.
The block is handed to the front end in chunks no longer than one hop, so every analysis frame it produces is seen: frames are exactly one hop apart, and a chunk that long can contain at most one of them.
Definition at line 223 of file KeyDetector.h.
|
inlinenoexcept |
Feeds mono samples directly. Allocation-free.
Definition at line 237 of file KeyDetector.h.
|
inlinenoexcept |
Clears the accumulated chroma and forgets the estimate.
Allocation-free, but it rewrites the stream state: call it from the thread that owns the stream (or while processing is stopped), not concurrently with processBlock()/pushSamples().
Definition at line 176 of file KeyDetector.h.
|
inlinenoexcept |
Selects the key profile (default KrumhanslKessler).
Callable from any thread; it takes effect at the next analysis frame, like every other parameter in the framework. It does not disturb the accumulated chroma, so switching profiles re-reads the same evidence.
Definition at line 194 of file KeyDetector.h.
|
staticconstexpr |
Krumhansl & Kessler (1982) probe-tone ratings, major.
Index 0 is the tonic, ascending chromatically. Verified digit for digit against Temperley, Musicae Scientiae 8(2) (2004), Table 1, column "K-S model / major", which reprints them; the same twelve numbers appear again in that paper's worked example of the Krumhansl-Schmuckler model.
Definition at line 345 of file KeyDetector.h.
|
staticconstexpr |
Krumhansl & Kessler (1982) probe-tone ratings, minor.
Same source and column "K-S model / minor". Note the two features that make the mode decidable at all: the raised third of the relative major (index 4) drops to 2.60 while the minor third (index 3) carries 5.38, and the subtonic (index 10, 3.34) outranks the leading tone (index 11, 3.17), which is the natural-minor scale asserting itself over the harmonic one.
Definition at line 357 of file KeyDetector.h.
|
staticconstexpr |
Temperley (1999) revised profiles, major.
From "What's Key for Key? The Krumhansl-Schmuckler Key-Finding Algorithm Reconsidered", Music Perception 17(1), Figure 4; reprinted as the "CBMS model / major" column of Temperley 2004 Table 1. Every chromatic degree sits at 2.0 except the subtonic at 1.5, and the leading tone is raised to 4.0 – the deliberate departure from the measured ratings.
Definition at line 369 of file KeyDetector.h.
|
staticconstexpr |
Temperley (1999) revised profiles, minor.
Same source, minor panel. It assumes the HARMONIC minor scale, so the flat sixth (index 8) is diatonic at 3.5 and the natural sixth (index 9) is chromatic at 2.0 – the opposite of the Krumhansl-Kessler minor ordering, and the reason the two profiles disagree most on modal material.
Definition at line 381 of file KeyDetector.h.