tuner-core 2026.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/detectors/autocorrelation.d.ts +19 -0
- package/dist/detectors/autocorrelation.d.ts.map +1 -0
- package/dist/detectors/autocorrelation.js +60 -0
- package/dist/detectors/autocorrelation.js.map +1 -0
- package/dist/detectors/create-pitch-detector.d.ts +4 -0
- package/dist/detectors/create-pitch-detector.d.ts.map +1 -0
- package/dist/detectors/create-pitch-detector.js +39 -0
- package/dist/detectors/create-pitch-detector.js.map +1 -0
- package/dist/detectors/mpm.d.ts +21 -0
- package/dist/detectors/mpm.d.ts.map +1 -0
- package/dist/detectors/mpm.js +95 -0
- package/dist/detectors/mpm.js.map +1 -0
- package/dist/detectors/pyin.d.ts +49 -0
- package/dist/detectors/pyin.d.ts.map +1 -0
- package/dist/detectors/pyin.js +205 -0
- package/dist/detectors/pyin.js.map +1 -0
- package/dist/detectors/yin-cmnd.d.ts +13 -0
- package/dist/detectors/yin-cmnd.d.ts.map +1 -0
- package/dist/detectors/yin-cmnd.js +53 -0
- package/dist/detectors/yin-cmnd.js.map +1 -0
- package/dist/detectors/yin.d.ts +20 -0
- package/dist/detectors/yin.d.ts.map +1 -0
- package/dist/detectors/yin.js +66 -0
- package/dist/detectors/yin.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/notes.d.ts +25 -0
- package/dist/notes.d.ts.map +1 -0
- package/dist/notes.js +56 -0
- package/dist/notes.js.map +1 -0
- package/dist/preferences.d.ts +8 -0
- package/dist/preferences.d.ts.map +1 -0
- package/dist/preferences.js +7 -0
- package/dist/preferences.js.map +1 -0
- package/dist/session.d.ts +25 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +131 -0
- package/dist/session.js.map +1 -0
- package/dist/tuner-settings.d.ts +58 -0
- package/dist/tuner-settings.d.ts.map +1 -0
- package/dist/tuner-settings.js +69 -0
- package/dist/tuner-settings.js.map +1 -0
- package/dist/tunings.d.ts +5 -0
- package/dist/tunings.d.ts.map +1 -0
- package/dist/tunings.js +231 -0
- package/dist/tunings.js.map +1 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/median.d.ts +3 -0
- package/dist/utils/median.d.ts.map +1 -0
- package/dist/utils/median.js +15 -0
- package/dist/utils/median.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tuner contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# tuner-core
|
|
2
|
+
|
|
3
|
+
Pitch detection (**YIN**, **pYIN / HMM**, **MPM / McLeod**, **autocorrelation**) and a small **tuner session** API (smoothing, confidence gating, note / cents, tunings registry). Made for browsers, Node, or native shells by injecting an `AudioProvider`.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- **Node.js 20+**
|
|
8
|
+
- **ESM only** (`import`, not `require`). CommonJS callers must use dynamic `import()`.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install tuner-core
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Why several detectors?
|
|
17
|
+
|
|
18
|
+
Different algorithms trade off **latency**, **stability**, **CPU cost**, and **robustness** to noise, vibrato, and false subharmonics. Shipping multiple implementations lets you **benchmark under real rooms and instruments**, A/B in your UI, and fall back when one misbehaves on a given platform.
|
|
19
|
+
|
|
20
|
+
**YIN** is the **default** in `DEFAULT_TUNER_SETTINGS**: a direct **cumulative mean normalized difference (CMND)** detector with **`yinThreshold`** as the main knob. **Predictive YIN (pYIN)** uses the same observations with a small HMM for a steadier monophonic track—pick it when that trade-off suits your app. **MPM** and **autocorrelation** stay in the box for comparison and platform-specific behavior.
|
|
21
|
+
|
|
22
|
+
## Using `TunerSession` and reading results
|
|
23
|
+
|
|
24
|
+
You bring an **`AudioProvider`** (mic / `AudioWorklet` / native capture): it exposes sample rate, registers a frame callback, and implements `start()` / `stop()`. **`TunerSession`** wires that stream to a **`PitchDetector`**, applies median smoothing and confidence gating, then emits **`TunerResult`** on each analyzed frame.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import {
|
|
28
|
+
TunerSession,
|
|
29
|
+
createPitchDetector,
|
|
30
|
+
mergeTunerSettings,
|
|
31
|
+
findTuning,
|
|
32
|
+
type AudioProvider,
|
|
33
|
+
type TunerResult,
|
|
34
|
+
} from 'tuner-core'
|
|
35
|
+
|
|
36
|
+
const settings = mergeTunerSettings({
|
|
37
|
+
pitchDetector: 'yin', // or 'pyin' | 'mpm' | 'autocorrelation'
|
|
38
|
+
medianWindowSize: 7,
|
|
39
|
+
minConfidence: 0.28,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const audio: AudioProvider = {
|
|
43
|
+
/* your implementation: getSampleRate, onFrame, start, stop */
|
|
44
|
+
}
|
|
45
|
+
const detector = createPitchDetector(settings)
|
|
46
|
+
const session = new TunerSession(audio, detector, settings)
|
|
47
|
+
|
|
48
|
+
// Optional: guitar / bass context for string dots and in-tune hints
|
|
49
|
+
const tuning = findTuning('guitar', 'guitar-standard')
|
|
50
|
+
session.setTuning(tuning ?? null)
|
|
51
|
+
session.applyPreferences({ centsThreshold: 5 })
|
|
52
|
+
|
|
53
|
+
session.on('started', () => {
|
|
54
|
+
console.log('capture started')
|
|
55
|
+
})
|
|
56
|
+
session.on('stopped', () => {
|
|
57
|
+
console.log('capture stopped')
|
|
58
|
+
})
|
|
59
|
+
session.on('error', (err) => {
|
|
60
|
+
console.error(err.message)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
session.on('result', (r: TunerResult) => {
|
|
64
|
+
// Smoothed display pitch (Hz); may hold last confident value if current frame is weak
|
|
65
|
+
console.log(r.frequency)
|
|
66
|
+
|
|
67
|
+
// Nearest chromatic note
|
|
68
|
+
console.log(r.note, r.octave) // e.g. "A", 4
|
|
69
|
+
|
|
70
|
+
// Cents from that semitone (-50 … +50 after rounding in core helpers)
|
|
71
|
+
console.log(r.cents)
|
|
72
|
+
|
|
73
|
+
// If setTuning() was used: nearest string, how far in cents, and in-tune vs prefs
|
|
74
|
+
if (r.closestString) {
|
|
75
|
+
console.log(
|
|
76
|
+
r.closestString.name,
|
|
77
|
+
r.closestString.centsOff,
|
|
78
|
+
r.closestString.inTune,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Copy of open strings for UI pills / labels, or null if no tuning selected
|
|
83
|
+
console.log(r.tuningStrings)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
await session.start()
|
|
87
|
+
// … later …
|
|
88
|
+
session.stop()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Each **`result`** event is one synthesis of the pipeline: **raw detector output → median window → confidence gate (hold last good pitch when unsure) → MIDI / note / cents / optional string math**.
|
|
92
|
+
|
|
93
|
+
## More
|
|
94
|
+
|
|
95
|
+
Source and CLI: [github.com/mducharme/Tuner](https://github.com/mducharme/Tuner).
|
|
96
|
+
|
|
97
|
+
## Publish (maintainers)
|
|
98
|
+
|
|
99
|
+
From the monorepo root (with a clean build and tests green):
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pnpm --filter tuner-core build
|
|
103
|
+
pnpm --filter tuner-core run package:assert
|
|
104
|
+
pnpm --filter tuner-core publish --access public
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Prefer **npm provenance** via GitHub Actions (see `.github/workflows/publish.yml`) and [trusted publishers](https://docs.npmjs.com/trusted-publishers).
|
|
108
|
+
|
|
109
|
+
`prepublishOnly` runs `tsc`, `publint --strict`, and **Are The Types Wrong?** (`attw --pack . --profile esm-only`).
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PitchDetection, PitchDetector } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Autocorrelation-based pitch detector.
|
|
4
|
+
* Fast and simple — good enough for v1, swappable for YIN/McLeod later.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AutocorrelationDetector implements PitchDetector {
|
|
7
|
+
private readonly minFrequency;
|
|
8
|
+
private readonly maxFrequency;
|
|
9
|
+
private readonly clarityThreshold;
|
|
10
|
+
constructor({ minFrequency, // ~B1, covers bass guitar low B
|
|
11
|
+
maxFrequency, // covers most instruments
|
|
12
|
+
clarityThreshold, }?: {
|
|
13
|
+
minFrequency?: number | undefined;
|
|
14
|
+
maxFrequency?: number | undefined;
|
|
15
|
+
clarityThreshold?: number | undefined;
|
|
16
|
+
});
|
|
17
|
+
detect(samples: Float32Array, sampleRate: number): PitchDetection;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=autocorrelation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocorrelation.d.ts","sourceRoot":"","sources":["../../src/detectors/autocorrelation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhE;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,aAAa;IAC3D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;gBAE7B,EACV,YAAiB,EAAE,gCAAgC;IACnD,YAAmB,EAAE,0BAA0B;IAE/C,gBAAsB,GACvB;;;;KAAK;IAMN,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc;CAkDlE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocorrelation-based pitch detector.
|
|
3
|
+
* Fast and simple — good enough for v1, swappable for YIN/McLeod later.
|
|
4
|
+
*/
|
|
5
|
+
export class AutocorrelationDetector {
|
|
6
|
+
minFrequency;
|
|
7
|
+
maxFrequency;
|
|
8
|
+
clarityThreshold;
|
|
9
|
+
constructor({ minFrequency = 60, // ~B1, covers bass guitar low B
|
|
10
|
+
maxFrequency = 1400, // covers most instruments
|
|
11
|
+
// Mic + room noise yields much lower "clarity" than synthetic sines; 0.9 rejected almost all real input.
|
|
12
|
+
clarityThreshold = 0.2, } = {}) {
|
|
13
|
+
this.minFrequency = minFrequency;
|
|
14
|
+
this.maxFrequency = maxFrequency;
|
|
15
|
+
this.clarityThreshold = clarityThreshold;
|
|
16
|
+
}
|
|
17
|
+
detect(samples, sampleRate) {
|
|
18
|
+
const minPeriod = Math.ceil(sampleRate / this.maxFrequency);
|
|
19
|
+
const maxPeriod = Math.floor(sampleRate / this.minFrequency);
|
|
20
|
+
const n = samples.length;
|
|
21
|
+
let bestPeriod = -1;
|
|
22
|
+
let bestCorrelation = 0;
|
|
23
|
+
let rms = 0;
|
|
24
|
+
for (let i = 0; i < n; i++) {
|
|
25
|
+
rms += (samples[i] ?? 0) * (samples[i] ?? 0);
|
|
26
|
+
}
|
|
27
|
+
rms = Math.sqrt(rms / n);
|
|
28
|
+
if (rms < 0.01) {
|
|
29
|
+
return { frequency: null, confidence: 0 };
|
|
30
|
+
}
|
|
31
|
+
for (let period = minPeriod; period <= maxPeriod; period++) {
|
|
32
|
+
let correlation = 0;
|
|
33
|
+
for (let i = 0; i < n - period; i++) {
|
|
34
|
+
correlation += (samples[i] ?? 0) * (samples[i + period] ?? 0);
|
|
35
|
+
}
|
|
36
|
+
correlation /= n - period;
|
|
37
|
+
if (correlation > bestCorrelation) {
|
|
38
|
+
bestCorrelation = correlation;
|
|
39
|
+
bestPeriod = period;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (bestPeriod === -1) {
|
|
43
|
+
return { frequency: null, confidence: 0 };
|
|
44
|
+
}
|
|
45
|
+
let maxValue = 0;
|
|
46
|
+
for (let i = 0; i < n; i++) {
|
|
47
|
+
maxValue = Math.max(maxValue, Math.abs(samples[i] ?? 0));
|
|
48
|
+
}
|
|
49
|
+
const clarity = maxValue > 0 ? bestCorrelation / (maxValue * maxValue) : 0;
|
|
50
|
+
const confidence = Math.min(1, Math.max(0, clarity));
|
|
51
|
+
if (clarity < this.clarityThreshold) {
|
|
52
|
+
return { frequency: null, confidence };
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
frequency: sampleRate / bestPeriod,
|
|
56
|
+
confidence,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=autocorrelation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocorrelation.js","sourceRoot":"","sources":["../../src/detectors/autocorrelation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-pitch-detector.d.ts","sourceRoot":"","sources":["../../src/detectors/create-pitch-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAqC1E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AutocorrelationDetector } from './autocorrelation.js';
|
|
2
|
+
import { MpmDetector } from './mpm.js';
|
|
3
|
+
import { PyinDetector } from './pyin.js';
|
|
4
|
+
import { YinDetector } from './yin.js';
|
|
5
|
+
export function createPitchDetector(settings) {
|
|
6
|
+
const d = settings.detector;
|
|
7
|
+
const bounds = { minFrequency: d.minFrequency, maxFrequency: d.maxFrequency };
|
|
8
|
+
if (settings.pitchDetector === 'autocorrelation') {
|
|
9
|
+
return new AutocorrelationDetector({
|
|
10
|
+
...bounds,
|
|
11
|
+
clarityThreshold: d.clarityThreshold,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (settings.pitchDetector === 'pyin') {
|
|
15
|
+
const p = d.pyin;
|
|
16
|
+
return new PyinDetector({
|
|
17
|
+
...bounds,
|
|
18
|
+
yinSharpness: p.yinSharpness,
|
|
19
|
+
transitionSigmaSemitones: p.transitionSigmaSemitones,
|
|
20
|
+
maxJumpSemitones: p.maxJumpSemitones,
|
|
21
|
+
logPitchToUv: p.logPitchToUv,
|
|
22
|
+
logUvToPitch: p.logUvToPitch,
|
|
23
|
+
logUvToUv: p.logUvToUv,
|
|
24
|
+
firstDipSemitoneWeight: p.firstDipSemitoneWeight,
|
|
25
|
+
firstDipThreshold: p.firstDipThreshold,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (settings.pitchDetector === 'mpm') {
|
|
29
|
+
return new MpmDetector({
|
|
30
|
+
...bounds,
|
|
31
|
+
peakThreshold: d.mpmPeakThreshold,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return new YinDetector({
|
|
35
|
+
...bounds,
|
|
36
|
+
threshold: d.yinThreshold,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=create-pitch-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-pitch-detector.js","sourceRoot":"","sources":["../../src/detectors/create-pitch-detector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtC,MAAM,UAAU,mBAAmB,CAAC,QAAuB;IACzD,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAA;IAC3B,MAAM,MAAM,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAA;IAE7E,IAAI,QAAQ,CAAC,aAAa,KAAK,iBAAiB,EAAE,CAAC;QACjD,OAAO,IAAI,uBAAuB,CAAC;YACjC,GAAG,MAAM;YACT,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;SACrC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,aAAa,KAAK,MAAM,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;QAChB,OAAO,IAAI,YAAY,CAAC;YACtB,GAAG,MAAM;YACT,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,wBAAwB,EAAE,CAAC,CAAC,wBAAwB;YACpD,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;YACpC,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,sBAAsB,EAAE,CAAC,CAAC,sBAAsB;YAChD,iBAAiB,EAAE,CAAC,CAAC,iBAAiB;SACvC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;QACrC,OAAO,IAAI,WAAW,CAAC;YACrB,GAAG,MAAM;YACT,aAAa,EAAE,CAAC,CAAC,gBAAgB;SAClC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,IAAI,WAAW,CAAC;QACrB,GAAG,MAAM;QACT,SAAS,EAAE,CAAC,CAAC,YAAY;KAC1B,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PitchDetection, PitchDetector } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* McLeod Pitch Method (MPM) via the Normalized Square Difference Function (NSDF).
|
|
4
|
+
* McLeod & Wyvill — peaks in NSDF indicate candidate periods; we take the first
|
|
5
|
+
* qualifying peak from short τ upward to reduce octave/subharmonic confusion.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MpmDetector implements PitchDetector {
|
|
8
|
+
private readonly minFrequency;
|
|
9
|
+
private readonly maxFrequency;
|
|
10
|
+
/** Minimum NSDF peak height (0…1, typ. 0.85–0.95) */
|
|
11
|
+
private readonly peakThreshold;
|
|
12
|
+
private readonly rmsThreshold;
|
|
13
|
+
constructor({ minFrequency, maxFrequency, peakThreshold, rmsThreshold, }?: {
|
|
14
|
+
minFrequency?: number | undefined;
|
|
15
|
+
maxFrequency?: number | undefined;
|
|
16
|
+
peakThreshold?: number | undefined;
|
|
17
|
+
rmsThreshold?: number | undefined;
|
|
18
|
+
});
|
|
19
|
+
detect(samples: Float32Array, sampleRate: number): PitchDetection;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=mpm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mpm.d.ts","sourceRoot":"","sources":["../../src/detectors/mpm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhE;;;;GAIG;AACH,qBAAa,WAAY,YAAW,aAAa;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,qDAAqD;IACrD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;gBAEzB,EACV,YAAiB,EACjB,YAAmB,EACnB,aAAoB,EACpB,YAAmB,GACpB;;;;;KAAK;IAON,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc;CAqFlE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McLeod Pitch Method (MPM) via the Normalized Square Difference Function (NSDF).
|
|
3
|
+
* McLeod & Wyvill — peaks in NSDF indicate candidate periods; we take the first
|
|
4
|
+
* qualifying peak from short τ upward to reduce octave/subharmonic confusion.
|
|
5
|
+
*/
|
|
6
|
+
export class MpmDetector {
|
|
7
|
+
minFrequency;
|
|
8
|
+
maxFrequency;
|
|
9
|
+
/** Minimum NSDF peak height (0…1, typ. 0.85–0.95) */
|
|
10
|
+
peakThreshold;
|
|
11
|
+
rmsThreshold;
|
|
12
|
+
constructor({ minFrequency = 60, maxFrequency = 1400, peakThreshold = 0.88, rmsThreshold = 0.01, } = {}) {
|
|
13
|
+
this.minFrequency = minFrequency;
|
|
14
|
+
this.maxFrequency = maxFrequency;
|
|
15
|
+
this.peakThreshold = peakThreshold;
|
|
16
|
+
this.rmsThreshold = rmsThreshold;
|
|
17
|
+
}
|
|
18
|
+
detect(samples, sampleRate) {
|
|
19
|
+
const n = samples.length;
|
|
20
|
+
if (n < 4) {
|
|
21
|
+
return { frequency: null, confidence: 0 };
|
|
22
|
+
}
|
|
23
|
+
let rms = 0;
|
|
24
|
+
for (let i = 0; i < n; i++) {
|
|
25
|
+
const v = samples[i] ?? 0;
|
|
26
|
+
rms += v * v;
|
|
27
|
+
}
|
|
28
|
+
rms = Math.sqrt(rms / n);
|
|
29
|
+
if (rms < this.rmsThreshold) {
|
|
30
|
+
return { frequency: null, confidence: 0 };
|
|
31
|
+
}
|
|
32
|
+
const tauMin = Math.max(1, Math.ceil(sampleRate / this.maxFrequency));
|
|
33
|
+
const tauMaxFreq = Math.floor(sampleRate / this.minFrequency);
|
|
34
|
+
const tauMaxWin = Math.floor(n / 2) - 1;
|
|
35
|
+
const tauMax = Math.min(tauMaxFreq, tauMaxWin);
|
|
36
|
+
if (tauMin > tauMax) {
|
|
37
|
+
return { frequency: null, confidence: 0 };
|
|
38
|
+
}
|
|
39
|
+
const nsdf = new Float32Array(tauMax + 1);
|
|
40
|
+
nsdf[0] = 1;
|
|
41
|
+
for (let tau = 1; tau <= tauMax; tau++) {
|
|
42
|
+
let num = 0;
|
|
43
|
+
let den = 0;
|
|
44
|
+
for (let i = 0; i < n - tau; i++) {
|
|
45
|
+
const a = samples[i] ?? 0;
|
|
46
|
+
const b = samples[i + tau] ?? 0;
|
|
47
|
+
num += a * b;
|
|
48
|
+
den += a * a + b * b;
|
|
49
|
+
}
|
|
50
|
+
nsdf[tau] = den > 1e-20 ? (2 * num) / den : 0;
|
|
51
|
+
}
|
|
52
|
+
const searchLo = Math.max(2, tauMin);
|
|
53
|
+
const searchHi = tauMax - 1;
|
|
54
|
+
if (searchLo > searchHi) {
|
|
55
|
+
return { frequency: null, confidence: 0 };
|
|
56
|
+
}
|
|
57
|
+
let peakTau = -1;
|
|
58
|
+
let peakVal = 0;
|
|
59
|
+
for (let tau = searchLo; tau <= searchHi; tau++) {
|
|
60
|
+
const v = nsdf[tau] ?? 0;
|
|
61
|
+
const vp = nsdf[tau - 1] ?? 0;
|
|
62
|
+
const vn = nsdf[tau + 1] ?? 0;
|
|
63
|
+
if (v >= this.peakThreshold && v >= vp && v >= vn) {
|
|
64
|
+
peakTau = tau;
|
|
65
|
+
peakVal = v;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (peakTau < 0) {
|
|
70
|
+
let best = 0;
|
|
71
|
+
for (let tau = searchLo; tau <= searchHi; tau++) {
|
|
72
|
+
best = Math.max(best, nsdf[tau] ?? 0);
|
|
73
|
+
}
|
|
74
|
+
return { frequency: null, confidence: Math.max(0, Math.min(1, best)) };
|
|
75
|
+
}
|
|
76
|
+
let refinedTau = peakTau;
|
|
77
|
+
const alpha = nsdf[peakTau - 1] ?? 0;
|
|
78
|
+
const beta = nsdf[peakTau] ?? 0;
|
|
79
|
+
const gamma = nsdf[peakTau + 1] ?? 0;
|
|
80
|
+
const denom = alpha - 2 * beta + gamma;
|
|
81
|
+
if (Math.abs(denom) > 1e-12) {
|
|
82
|
+
const offset = (gamma - alpha) / (2 * denom);
|
|
83
|
+
refinedTau = peakTau + Math.max(-1, Math.min(1, offset));
|
|
84
|
+
}
|
|
85
|
+
const frequency = sampleRate / refinedTau;
|
|
86
|
+
if (frequency < this.minFrequency || frequency > this.maxFrequency) {
|
|
87
|
+
return { frequency: null, confidence: Math.max(0, Math.min(1, peakVal)) };
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
frequency,
|
|
91
|
+
confidence: Math.max(0, Math.min(1, peakVal)),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=mpm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mpm.js","sourceRoot":"","sources":["../../src/detectors/mpm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PitchDetection, PitchDetector } from '../types.js';
|
|
2
|
+
export interface PyinDetectorOptions {
|
|
3
|
+
minFrequency?: number;
|
|
4
|
+
maxFrequency?: number;
|
|
5
|
+
rmsThreshold?: number;
|
|
6
|
+
/** Maps YIN CMND value to emission cost; higher → sharper peaks matter more */
|
|
7
|
+
yinSharpness?: number;
|
|
8
|
+
/** Gaussian σ (semitones) for pitch continuity in the HMM */
|
|
9
|
+
transitionSigmaSemitones?: number;
|
|
10
|
+
/** Max MIDI index jump per frame when scoring transitions */
|
|
11
|
+
maxJumpSemitones?: number;
|
|
12
|
+
/** log P(voiced → unvoiced) */
|
|
13
|
+
logPitchToUv?: number;
|
|
14
|
+
/** log P(unvoiced → voiced) */
|
|
15
|
+
logUvToPitch?: number;
|
|
16
|
+
/** log P(unvoiced → unvoiced) */
|
|
17
|
+
logUvToUv?: number;
|
|
18
|
+
firstDipSemitoneWeight?: number;
|
|
19
|
+
firstDipThreshold?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Probabilistic YIN–style observations + discrete-pitch HMM (Viterbi forward step).
|
|
23
|
+
* Stateful: call `reset()` when stopping capture so the Markov chain does not bridge sessions.
|
|
24
|
+
*/
|
|
25
|
+
export declare class PyinDetector implements PitchDetector {
|
|
26
|
+
private readonly minFrequency;
|
|
27
|
+
private readonly maxFrequency;
|
|
28
|
+
private readonly rmsThreshold;
|
|
29
|
+
private readonly yinSharpness;
|
|
30
|
+
private readonly transitionSigmaSemitones;
|
|
31
|
+
private readonly maxJumpSemitones;
|
|
32
|
+
private readonly logPitchToUv;
|
|
33
|
+
private readonly logUvToPitch;
|
|
34
|
+
private readonly logUvToUv;
|
|
35
|
+
private readonly firstDipSemitoneWeight;
|
|
36
|
+
private readonly firstDipThreshold;
|
|
37
|
+
private readonly midiMin;
|
|
38
|
+
private readonly midiMax;
|
|
39
|
+
private readonly nPitch;
|
|
40
|
+
private readonly uvIndex;
|
|
41
|
+
private readonly nStates;
|
|
42
|
+
private prevLog;
|
|
43
|
+
private hasPrev;
|
|
44
|
+
constructor(options?: PyinDetectorOptions);
|
|
45
|
+
reset(): void;
|
|
46
|
+
detect(samples: Float32Array, sampleRate: number): PitchDetection;
|
|
47
|
+
private secondBestLog;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=pyin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pyin.d.ts","sourceRoot":"","sources":["../../src/detectors/pyin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKhE,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;;GAGG;AACH,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAQ;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAE1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAEhC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,GAAE,mBAAwB;IAqB7C,KAAK,IAAI,IAAI;IAKb,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc;IAoIjE,OAAO,CAAC,aAAa;CAatB"}
|