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
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { frequencyToMidi, midiToFrequency } from '../notes.js';
|
|
2
|
+
import { computeYinCmnd, yinAtTau } from './yin-cmnd.js';
|
|
3
|
+
const LOG_FLOOR = -1e8;
|
|
4
|
+
/**
|
|
5
|
+
* Probabilistic YIN–style observations + discrete-pitch HMM (Viterbi forward step).
|
|
6
|
+
* Stateful: call `reset()` when stopping capture so the Markov chain does not bridge sessions.
|
|
7
|
+
*/
|
|
8
|
+
export class PyinDetector {
|
|
9
|
+
minFrequency;
|
|
10
|
+
maxFrequency;
|
|
11
|
+
rmsThreshold;
|
|
12
|
+
yinSharpness;
|
|
13
|
+
transitionSigmaSemitones;
|
|
14
|
+
maxJumpSemitones;
|
|
15
|
+
logPitchToUv;
|
|
16
|
+
logUvToPitch;
|
|
17
|
+
logUvToUv;
|
|
18
|
+
firstDipSemitoneWeight;
|
|
19
|
+
firstDipThreshold;
|
|
20
|
+
midiMin;
|
|
21
|
+
midiMax;
|
|
22
|
+
nPitch;
|
|
23
|
+
uvIndex;
|
|
24
|
+
nStates;
|
|
25
|
+
prevLog;
|
|
26
|
+
hasPrev = false;
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
this.minFrequency = options.minFrequency ?? 60;
|
|
29
|
+
this.maxFrequency = options.maxFrequency ?? 1400;
|
|
30
|
+
this.rmsThreshold = options.rmsThreshold ?? 0.01;
|
|
31
|
+
this.yinSharpness = options.yinSharpness ?? 12;
|
|
32
|
+
this.transitionSigmaSemitones = options.transitionSigmaSemitones ?? 1.35;
|
|
33
|
+
this.maxJumpSemitones = options.maxJumpSemitones ?? 10;
|
|
34
|
+
this.logPitchToUv = options.logPitchToUv ?? -3.2;
|
|
35
|
+
this.logUvToPitch = options.logUvToPitch ?? -2.8;
|
|
36
|
+
this.logUvToUv = options.logUvToUv ?? -0.15;
|
|
37
|
+
this.firstDipSemitoneWeight = options.firstDipSemitoneWeight ?? 0.14;
|
|
38
|
+
this.firstDipThreshold = options.firstDipThreshold ?? 0.18;
|
|
39
|
+
this.midiMin = Math.floor(frequencyToMidi(this.minFrequency));
|
|
40
|
+
this.midiMax = Math.ceil(frequencyToMidi(this.maxFrequency));
|
|
41
|
+
this.nPitch = this.midiMax - this.midiMin + 1;
|
|
42
|
+
this.uvIndex = this.nPitch;
|
|
43
|
+
this.nStates = this.nPitch + 1;
|
|
44
|
+
this.prevLog = new Float32Array(this.nStates);
|
|
45
|
+
}
|
|
46
|
+
reset() {
|
|
47
|
+
this.hasPrev = false;
|
|
48
|
+
this.prevLog.fill(0);
|
|
49
|
+
}
|
|
50
|
+
detect(samples, sampleRate) {
|
|
51
|
+
const cmnd = computeYinCmnd(samples, sampleRate, this.minFrequency, this.maxFrequency);
|
|
52
|
+
if (!cmnd) {
|
|
53
|
+
this.hasPrev = false;
|
|
54
|
+
return { frequency: null, confidence: 0 };
|
|
55
|
+
}
|
|
56
|
+
if (cmnd.rms < this.rmsThreshold) {
|
|
57
|
+
this.hasPrev = false;
|
|
58
|
+
return { frequency: null, confidence: 0 };
|
|
59
|
+
}
|
|
60
|
+
const { yin, tauMin, tauMax } = cmnd;
|
|
61
|
+
let yMin = 1;
|
|
62
|
+
for (let tau = tauMin; tau <= tauMax; tau++) {
|
|
63
|
+
yMin = Math.min(yMin, yin[tau] ?? 1);
|
|
64
|
+
}
|
|
65
|
+
const midiHint = firstDipMidiHint(yin, tauMin, tauMax, sampleRate, this.firstDipThreshold);
|
|
66
|
+
const emitPitch = new Float32Array(this.nPitch);
|
|
67
|
+
for (let i = 0; i < this.nPitch; i++) {
|
|
68
|
+
const midi = this.midiMin + i;
|
|
69
|
+
const f = midiToFrequency(midi);
|
|
70
|
+
if (f < this.minFrequency || f > this.maxFrequency) {
|
|
71
|
+
emitPitch[i] = LOG_FLOOR;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const tau = sampleRate / f;
|
|
75
|
+
if (tau < tauMin || tau > tauMax) {
|
|
76
|
+
emitPitch[i] = LOG_FLOOR;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const y = yinAtTau(yin, tauMax, tau);
|
|
80
|
+
let logP = -this.yinSharpness * y;
|
|
81
|
+
if (midiHint !== null) {
|
|
82
|
+
const dm = midi - midiHint;
|
|
83
|
+
logP -= this.firstDipSemitoneWeight * dm * dm;
|
|
84
|
+
}
|
|
85
|
+
emitPitch[i] = logP;
|
|
86
|
+
}
|
|
87
|
+
const emitUv = -this.yinSharpness * (0.35 + 0.65 * yMin);
|
|
88
|
+
const cur = new Float32Array(this.nStates);
|
|
89
|
+
const twoSigma2 = 2 * this.transitionSigmaSemitones * this.transitionSigmaSemitones;
|
|
90
|
+
if (!this.hasPrev) {
|
|
91
|
+
const uniform = -Math.log(this.nStates);
|
|
92
|
+
for (let j = 0; j < this.nPitch; j++) {
|
|
93
|
+
cur[j] = uniform + (emitPitch.at(j) ?? LOG_FLOOR);
|
|
94
|
+
}
|
|
95
|
+
cur[this.uvIndex] = uniform + emitUv;
|
|
96
|
+
this.hasPrev = true;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
for (let j = 0; j < this.nPitch; j++) {
|
|
100
|
+
let best = LOG_FLOOR;
|
|
101
|
+
const mj = this.midiMin + j;
|
|
102
|
+
for (let i = 0; i < this.nPitch; i++) {
|
|
103
|
+
const mi = this.midiMin + i;
|
|
104
|
+
const dj = Math.abs(mi - mj);
|
|
105
|
+
if (dj > this.maxJumpSemitones) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const trans = -(dj * dj) / twoSigma2;
|
|
109
|
+
const v = (this.prevLog.at(i) ?? LOG_FLOOR) + trans;
|
|
110
|
+
if (v > best) {
|
|
111
|
+
best = v;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const fromUv = (this.prevLog.at(this.uvIndex) ?? LOG_FLOOR) + this.logUvToPitch;
|
|
115
|
+
if (fromUv > best) {
|
|
116
|
+
best = fromUv;
|
|
117
|
+
}
|
|
118
|
+
cur[j] = best + (emitPitch.at(j) ?? LOG_FLOOR);
|
|
119
|
+
}
|
|
120
|
+
let bestUv = LOG_FLOOR;
|
|
121
|
+
for (let i = 0; i < this.nPitch; i++) {
|
|
122
|
+
const v = (this.prevLog.at(i) ?? LOG_FLOOR) + this.logPitchToUv;
|
|
123
|
+
if (v > bestUv) {
|
|
124
|
+
bestUv = v;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const uvStay = (this.prevLog.at(this.uvIndex) ?? LOG_FLOOR) + this.logUvToUv;
|
|
128
|
+
if (uvStay > bestUv) {
|
|
129
|
+
bestUv = uvStay;
|
|
130
|
+
}
|
|
131
|
+
cur[this.uvIndex] = bestUv + emitUv;
|
|
132
|
+
}
|
|
133
|
+
let bestIdx = 0;
|
|
134
|
+
let bestVal = cur.at(0) ?? LOG_FLOOR;
|
|
135
|
+
for (let j = 1; j < this.nStates; j++) {
|
|
136
|
+
const cj = cur.at(j) ?? LOG_FLOOR;
|
|
137
|
+
if (cj > bestVal) {
|
|
138
|
+
bestVal = cj;
|
|
139
|
+
bestIdx = j;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (let j = 0; j < this.nStates; j++) {
|
|
143
|
+
this.prevLog[j] = cur.at(j) ?? LOG_FLOOR;
|
|
144
|
+
}
|
|
145
|
+
if (bestIdx === this.uvIndex) {
|
|
146
|
+
const second = this.secondBestLog(cur, this.uvIndex);
|
|
147
|
+
const confidence = logProbToConfidence(bestVal, second);
|
|
148
|
+
return { frequency: null, confidence };
|
|
149
|
+
}
|
|
150
|
+
const midi = this.midiMin + bestIdx;
|
|
151
|
+
const frequency = midiToFrequency(midi);
|
|
152
|
+
const second = this.secondBestLog(cur, bestIdx);
|
|
153
|
+
const confidence = logProbToConfidence(bestVal, second);
|
|
154
|
+
return { frequency, confidence };
|
|
155
|
+
}
|
|
156
|
+
secondBestLog(cur, exclude) {
|
|
157
|
+
let s = LOG_FLOOR;
|
|
158
|
+
for (let j = 0; j < this.nStates; j++) {
|
|
159
|
+
if (j === exclude) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const cj = cur.at(j) ?? LOG_FLOOR;
|
|
163
|
+
if (cj > s) {
|
|
164
|
+
s = cj;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return s;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function logProbToConfidence(best, second) {
|
|
171
|
+
const margin = best - second;
|
|
172
|
+
const c = 1 / (1 + Math.exp(-margin));
|
|
173
|
+
return Math.max(0, Math.min(1, c));
|
|
174
|
+
}
|
|
175
|
+
/** MIDI note at the first YIN dip (classic YIN τ pick), for a subharmonic-resistant hint */
|
|
176
|
+
function firstDipMidiHint(yin, tauMin, tauMax, sampleRate, threshold) {
|
|
177
|
+
let bestTau = -1;
|
|
178
|
+
for (let tau = tauMin; tau <= tauMax; tau++) {
|
|
179
|
+
const y = yin[tau] ?? 1;
|
|
180
|
+
if (y < threshold) {
|
|
181
|
+
let t = tau;
|
|
182
|
+
while (t + 1 <= tauMax && (yin[t + 1] ?? 1) < (yin[t] ?? 1)) {
|
|
183
|
+
t++;
|
|
184
|
+
}
|
|
185
|
+
bestTau = t;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (bestTau < 0) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
let refinedTau = bestTau;
|
|
193
|
+
if (bestTau > 1 && bestTau < tauMax) {
|
|
194
|
+
const y0 = yin[bestTau - 1] ?? 1;
|
|
195
|
+
const y1 = yin[bestTau] ?? 1;
|
|
196
|
+
const y2 = yin[bestTau + 1] ?? 1;
|
|
197
|
+
const denom = y0 - 2 * y1 + y2;
|
|
198
|
+
if (Math.abs(denom) > 1e-14) {
|
|
199
|
+
const offset = (y0 - y2) / (2 * denom);
|
|
200
|
+
refinedTau = bestTau + Math.max(-1, Math.min(1, offset));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return frequencyToMidi(sampleRate / refinedTau);
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=pyin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pyin.js","sourceRoot":"","sources":["../../src/detectors/pyin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared YIN cumulative mean normalized difference (Cheveigné & Kawahara).
|
|
3
|
+
* Used by YinDetector and PyinDetector.
|
|
4
|
+
*/
|
|
5
|
+
export interface YinCmndBuffer {
|
|
6
|
+
yin: Float32Array;
|
|
7
|
+
tauMin: number;
|
|
8
|
+
tauMax: number;
|
|
9
|
+
rms: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function computeYinCmnd(samples: Float32Array, sampleRate: number, minFrequency: number, maxFrequency: number): YinCmndBuffer | null;
|
|
12
|
+
export declare function yinAtTau(yin: Float32Array, tauMax: number, tau: number): number;
|
|
13
|
+
//# sourceMappingURL=yin-cmnd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yin-cmnd.d.ts","sourceRoot":"","sources":["../../src/detectors/yin-cmnd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,YAAY,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,aAAa,GAAG,IAAI,CAwCtB;AAED,wBAAgB,QAAQ,CACtB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,MAAM,CAWR"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared YIN cumulative mean normalized difference (Cheveigné & Kawahara).
|
|
3
|
+
* Used by YinDetector and PyinDetector.
|
|
4
|
+
*/
|
|
5
|
+
export function computeYinCmnd(samples, sampleRate, minFrequency, maxFrequency) {
|
|
6
|
+
const n = samples.length;
|
|
7
|
+
if (n < 4) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
let rms = 0;
|
|
11
|
+
for (let i = 0; i < n; i++) {
|
|
12
|
+
const v = samples[i] ?? 0;
|
|
13
|
+
rms += v * v;
|
|
14
|
+
}
|
|
15
|
+
rms = Math.sqrt(rms / n);
|
|
16
|
+
const tauMin = Math.max(1, Math.ceil(sampleRate / maxFrequency));
|
|
17
|
+
const tauMaxFreq = Math.floor(sampleRate / minFrequency);
|
|
18
|
+
const tauMaxWin = Math.floor(n / 2) - 1;
|
|
19
|
+
const tauMax = Math.min(tauMaxFreq, tauMaxWin);
|
|
20
|
+
if (tauMin > tauMax) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const d = new Float32Array(tauMax + 1);
|
|
24
|
+
for (let tau = 1; tau <= tauMax; tau++) {
|
|
25
|
+
let sum = 0;
|
|
26
|
+
for (let j = 0; j < n - tau; j++) {
|
|
27
|
+
const diff = (samples[j] ?? 0) - (samples[j + tau] ?? 0);
|
|
28
|
+
sum += diff * diff;
|
|
29
|
+
}
|
|
30
|
+
d[tau] = sum;
|
|
31
|
+
}
|
|
32
|
+
const yin = new Float32Array(tauMax + 1);
|
|
33
|
+
yin[0] = 1;
|
|
34
|
+
let running = 0;
|
|
35
|
+
for (let tau = 1; tau <= tauMax; tau++) {
|
|
36
|
+
running += d[tau] ?? 0;
|
|
37
|
+
yin[tau] = running > 0 ? ((d[tau] ?? 0) * tau) / running : 1;
|
|
38
|
+
}
|
|
39
|
+
return { yin, tauMin, tauMax, rms };
|
|
40
|
+
}
|
|
41
|
+
export function yinAtTau(yin, tauMax, tau) {
|
|
42
|
+
if (tau <= 1) {
|
|
43
|
+
return yin[1] ?? 1;
|
|
44
|
+
}
|
|
45
|
+
if (tau >= tauMax) {
|
|
46
|
+
return yin[tauMax] ?? 1;
|
|
47
|
+
}
|
|
48
|
+
const t0 = Math.floor(tau);
|
|
49
|
+
const t1 = t0 + 1;
|
|
50
|
+
const f = tau - t0;
|
|
51
|
+
return (yin[t0] ?? 1) * (1 - f) + (yin[t1] ?? 1) * f;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=yin-cmnd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yin-cmnd.js","sourceRoot":"","sources":["../../src/detectors/yin-cmnd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PitchDetection, PitchDetector } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* YIN pitch estimator (Cheveigné & Kawahara).
|
|
4
|
+
* Generally more robust than raw autocorrelation on real signals, especially low notes.
|
|
5
|
+
*/
|
|
6
|
+
export declare class YinDetector implements PitchDetector {
|
|
7
|
+
private readonly minFrequency;
|
|
8
|
+
private readonly maxFrequency;
|
|
9
|
+
/** Cumulative mean normalized difference; typical 0.10–0.20 */
|
|
10
|
+
private readonly threshold;
|
|
11
|
+
private readonly rmsThreshold;
|
|
12
|
+
constructor({ minFrequency, maxFrequency, threshold, rmsThreshold, }?: {
|
|
13
|
+
minFrequency?: number | undefined;
|
|
14
|
+
maxFrequency?: number | undefined;
|
|
15
|
+
threshold?: number | undefined;
|
|
16
|
+
rmsThreshold?: number | undefined;
|
|
17
|
+
});
|
|
18
|
+
detect(samples: Float32Array, sampleRate: number): PitchDetection;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=yin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yin.d.ts","sourceRoot":"","sources":["../../src/detectors/yin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhE;;;GAGG;AACH,qBAAa,WAAY,YAAW,aAAa;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;gBAEzB,EACV,YAAiB,EACjB,YAAmB,EACnB,SAAgB,EAChB,YAAmB,GACpB;;;;;KAAK;IAON,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc;CA0DlE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { computeYinCmnd } from './yin-cmnd.js';
|
|
2
|
+
/**
|
|
3
|
+
* YIN pitch estimator (Cheveigné & Kawahara).
|
|
4
|
+
* Generally more robust than raw autocorrelation on real signals, especially low notes.
|
|
5
|
+
*/
|
|
6
|
+
export class YinDetector {
|
|
7
|
+
minFrequency;
|
|
8
|
+
maxFrequency;
|
|
9
|
+
/** Cumulative mean normalized difference; typical 0.10–0.20 */
|
|
10
|
+
threshold;
|
|
11
|
+
rmsThreshold;
|
|
12
|
+
constructor({ minFrequency = 60, maxFrequency = 1400, threshold = 0.15, rmsThreshold = 0.01, } = {}) {
|
|
13
|
+
this.minFrequency = minFrequency;
|
|
14
|
+
this.maxFrequency = maxFrequency;
|
|
15
|
+
this.threshold = threshold;
|
|
16
|
+
this.rmsThreshold = rmsThreshold;
|
|
17
|
+
}
|
|
18
|
+
detect(samples, sampleRate) {
|
|
19
|
+
const cmnd = computeYinCmnd(samples, sampleRate, this.minFrequency, this.maxFrequency);
|
|
20
|
+
if (!cmnd || cmnd.rms < this.rmsThreshold) {
|
|
21
|
+
return { frequency: null, confidence: 0 };
|
|
22
|
+
}
|
|
23
|
+
const { yin, tauMin, tauMax } = cmnd;
|
|
24
|
+
let bestTau = -1;
|
|
25
|
+
let bestVal = 1;
|
|
26
|
+
for (let tau = tauMin; tau <= tauMax; tau++) {
|
|
27
|
+
const y = yin[tau] ?? 1;
|
|
28
|
+
if (y < this.threshold) {
|
|
29
|
+
let t = tau;
|
|
30
|
+
while (t + 1 <= tauMax && (yin[t + 1] ?? 1) < (yin[t] ?? 1)) {
|
|
31
|
+
t++;
|
|
32
|
+
}
|
|
33
|
+
bestTau = t;
|
|
34
|
+
bestVal = yin[t] ?? 1;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (bestTau < 0 || bestVal >= this.threshold || !Number.isFinite(bestVal)) {
|
|
39
|
+
const confidence = Number.isFinite(bestVal)
|
|
40
|
+
? Math.max(0, Math.min(1, 1 - bestVal))
|
|
41
|
+
: 0;
|
|
42
|
+
return { frequency: null, confidence };
|
|
43
|
+
}
|
|
44
|
+
let refinedTau = bestTau;
|
|
45
|
+
if (bestTau > 1 && bestTau < tauMax) {
|
|
46
|
+
const y0 = yin[bestTau - 1] ?? 1;
|
|
47
|
+
const y1 = yin[bestTau] ?? 1;
|
|
48
|
+
const y2 = yin[bestTau + 1] ?? 1;
|
|
49
|
+
const denom = y0 - 2 * y1 + y2;
|
|
50
|
+
if (Math.abs(denom) > 1e-14) {
|
|
51
|
+
const offset = (y0 - y2) / (2 * denom);
|
|
52
|
+
refinedTau = bestTau + Math.max(-1, Math.min(1, offset));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const frequency = sampleRate / refinedTau;
|
|
56
|
+
if (frequency < this.minFrequency || frequency > this.maxFrequency) {
|
|
57
|
+
return {
|
|
58
|
+
frequency: null,
|
|
59
|
+
confidence: Math.max(0, Math.min(1, 1 - bestVal)),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const confidence = Math.max(0, Math.min(1, 1 - bestVal));
|
|
63
|
+
return { frequency, confidence };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=yin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yin.js","sourceRoot":"","sources":["../../src/detectors/yin.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { AudioProvider, PitchDetection, PitchDetector, StringDef, Tuning, Instrument, ClosestString, TunerResult, HapticsProvider, UserPreferences, PreferencesProvider, TunerEventMap, TunerEventListener, } from './types.js';
|
|
2
|
+
export { TunerSession } from './session.js';
|
|
3
|
+
export { frequencyToMidi, midiToFrequency, midiToNote, midiToOctave, getCents, getCentsFromTarget, } from './notes.js';
|
|
4
|
+
export { AutocorrelationDetector } from './detectors/autocorrelation.js';
|
|
5
|
+
export { YinDetector } from './detectors/yin.js';
|
|
6
|
+
export { PyinDetector } from './detectors/pyin.js';
|
|
7
|
+
export { MpmDetector } from './detectors/mpm.js';
|
|
8
|
+
export { createPitchDetector } from './detectors/create-pitch-detector.js';
|
|
9
|
+
export { INSTRUMENTS, findInstrument, findTuning } from './tunings.js';
|
|
10
|
+
export { DEFAULT_PREFERENCES } from './preferences.js';
|
|
11
|
+
export type { TunerSettings, DetectorSettings, PitchDetectorKind, PyinHMMSettings, } from './tuner-settings.js';
|
|
12
|
+
export { DEFAULT_TUNER_SETTINGS, mergeTunerSettings, applySettingsPatch, } from './tuner-settings.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,cAAc,EACd,aAAa,EACb,SAAS,EACT,MAAM,EACN,UAAU,EACV,aAAa,EACb,WAAW,EACX,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,EACL,eAAe,EACf,eAAe,EACf,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAG1E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAGtD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Session
|
|
2
|
+
export { TunerSession } from './session.js';
|
|
3
|
+
// Note utilities
|
|
4
|
+
export { frequencyToMidi, midiToFrequency, midiToNote, midiToOctave, getCents, getCentsFromTarget, } from './notes.js';
|
|
5
|
+
// Detectors
|
|
6
|
+
export { AutocorrelationDetector } from './detectors/autocorrelation.js';
|
|
7
|
+
export { YinDetector } from './detectors/yin.js';
|
|
8
|
+
export { PyinDetector } from './detectors/pyin.js';
|
|
9
|
+
export { MpmDetector } from './detectors/mpm.js';
|
|
10
|
+
export { createPitchDetector } from './detectors/create-pitch-detector.js';
|
|
11
|
+
// Tuning data
|
|
12
|
+
export { INSTRUMENTS, findInstrument, findTuning } from './tunings.js';
|
|
13
|
+
// Preferences
|
|
14
|
+
export { DEFAULT_PREFERENCES } from './preferences.js';
|
|
15
|
+
export { DEFAULT_TUNER_SETTINGS, mergeTunerSettings, applySettingsPatch, } from './tuner-settings.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,iBAAiB;AACjB,OAAO,EACL,eAAe,EACf,eAAe,EACf,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAEnB,YAAY;AACZ,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAE1E,cAAc;AACd,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEtE,cAAc;AACd,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAStD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA"}
|
package/dist/notes.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a frequency in Hz to a MIDI note number (float).
|
|
3
|
+
*/
|
|
4
|
+
export declare function frequencyToMidi(frequency: number): number;
|
|
5
|
+
/**
|
|
6
|
+
* Convert a MIDI note number to frequency in Hz.
|
|
7
|
+
*/
|
|
8
|
+
export declare function midiToFrequency(midi: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* Get the note name for a MIDI note number.
|
|
11
|
+
*/
|
|
12
|
+
export declare function midiToNote(midi: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the octave for a MIDI note number.
|
|
15
|
+
*/
|
|
16
|
+
export declare function midiToOctave(midi: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Get cents deviation from the nearest semitone (-50 to +50).
|
|
19
|
+
*/
|
|
20
|
+
export declare function getCents(frequency: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Get cents deviation between a detected frequency and a target frequency.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getCentsFromTarget(detected: number, target: number): number;
|
|
25
|
+
//# sourceMappingURL=notes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3E"}
|
package/dist/notes.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const NOTE_NAMES = [
|
|
2
|
+
'C',
|
|
3
|
+
'C#',
|
|
4
|
+
'D',
|
|
5
|
+
'D#',
|
|
6
|
+
'E',
|
|
7
|
+
'F',
|
|
8
|
+
'F#',
|
|
9
|
+
'G',
|
|
10
|
+
'G#',
|
|
11
|
+
'A',
|
|
12
|
+
'A#',
|
|
13
|
+
'B',
|
|
14
|
+
];
|
|
15
|
+
const A4_FREQUENCY = 440;
|
|
16
|
+
const A4_MIDI = 69;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a frequency in Hz to a MIDI note number (float).
|
|
19
|
+
*/
|
|
20
|
+
export function frequencyToMidi(frequency) {
|
|
21
|
+
return 12 * Math.log2(frequency / A4_FREQUENCY) + A4_MIDI;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert a MIDI note number to frequency in Hz.
|
|
25
|
+
*/
|
|
26
|
+
export function midiToFrequency(midi) {
|
|
27
|
+
return A4_FREQUENCY * 2 ** ((midi - A4_MIDI) / 12);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the note name for a MIDI note number.
|
|
31
|
+
*/
|
|
32
|
+
export function midiToNote(midi) {
|
|
33
|
+
const name = NOTE_NAMES[Math.round(midi) % 12];
|
|
34
|
+
return name ?? 'A';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the octave for a MIDI note number.
|
|
38
|
+
*/
|
|
39
|
+
export function midiToOctave(midi) {
|
|
40
|
+
return Math.floor(Math.round(midi) / 12) - 1;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get cents deviation from the nearest semitone (-50 to +50).
|
|
44
|
+
*/
|
|
45
|
+
export function getCents(frequency) {
|
|
46
|
+
const midi = frequencyToMidi(frequency);
|
|
47
|
+
const nearestMidi = Math.round(midi);
|
|
48
|
+
return Math.round((midi - nearestMidi) * 100);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get cents deviation between a detected frequency and a target frequency.
|
|
52
|
+
*/
|
|
53
|
+
export function getCentsFromTarget(detected, target) {
|
|
54
|
+
return Math.round(1200 * Math.log2(detected / target));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=notes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notes.js","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG;IACjB,GAAG;IACH,IAAI;IACJ,GAAG;IACH,IAAI;IACJ,GAAG;IACH,GAAG;IACH,IAAI;IACJ,GAAG;IACH,IAAI;IACJ,GAAG;IACH,IAAI;IACJ,GAAG;CACK,CAAA;AAEV,MAAM,YAAY,GAAG,GAAG,CAAA;AACxB,MAAM,OAAO,GAAG,EAAE,CAAA;AAElB;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,YAAY,CAAC,GAAG,OAAO,CAAA;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC9C,OAAO,IAAI,IAAI,GAAG,CAAA;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,SAAiB;IACxC,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAA;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAc;IACjE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAA;AACxD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted app choices (instrument, tuning, cents threshold, custom tunings) — the kind of data
|
|
3
|
+
* a `PreferencesProvider` loads/saves. This is not engine configuration; for buffer size, detector
|
|
4
|
+
* kind, and smoothing see `tuner-settings.ts` and `TunerSettings`.
|
|
5
|
+
*/
|
|
6
|
+
import type { UserPreferences } from './types.js';
|
|
7
|
+
export declare const DEFAULT_PREFERENCES: UserPreferences;
|
|
8
|
+
//# sourceMappingURL=preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,eAAO,MAAM,mBAAmB,EAAE,eAKjC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preferences.js","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,mBAAmB,GAAoB;IAClD,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,EAAE;IACjB,gBAAgB,EAAE,IAAI;IACtB,YAAY,EAAE,IAAI;CACnB,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TunerSettings } from './tuner-settings.js';
|
|
2
|
+
import type { AudioProvider, PitchDetector, TunerEventListener, TunerEventMap, Tuning, UserPreferences } from './types.js';
|
|
3
|
+
export declare class TunerSession {
|
|
4
|
+
private readonly audio;
|
|
5
|
+
private readonly detector;
|
|
6
|
+
private readonly settings;
|
|
7
|
+
private activeTuning;
|
|
8
|
+
private centsThreshold;
|
|
9
|
+
private running;
|
|
10
|
+
private freqWindow;
|
|
11
|
+
private lastHeldHz;
|
|
12
|
+
private listeners;
|
|
13
|
+
constructor(audio: AudioProvider, detector: PitchDetector, settings?: Partial<TunerSettings>);
|
|
14
|
+
setTuning(tuning: Tuning | null): void;
|
|
15
|
+
applyPreferences(prefs: Partial<UserPreferences>): void;
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
stop(): void;
|
|
18
|
+
get isRunning(): boolean;
|
|
19
|
+
on<K extends keyof TunerEventMap>(event: K, listener: TunerEventListener<K>): void;
|
|
20
|
+
off<K extends keyof TunerEventMap>(event: K, listener: TunerEventListener<K>): void;
|
|
21
|
+
private emit;
|
|
22
|
+
private processFrame;
|
|
23
|
+
private findClosestString;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,aAAa,EAEb,MAAM,EACN,eAAe,EAChB,MAAM,YAAY,CAAA;AASnB,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,OAAO,CAAQ;IAEvB,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,UAAU,CAAsB;IAExC,OAAO,CAAC,SAAS,CAKhB;gBAGC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IASnC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAItC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAQjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,IAAI,IAAI,IAAI;IAUZ,IAAI,SAAS,IAAI,OAAO,CAEvB;IAID,EAAE,CAAC,CAAC,SAAS,MAAM,aAAa,EAC9B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,IAAI;IAIP,GAAG,CAAC,CAAC,SAAS,MAAM,aAAa,EAC/B,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,IAAI;IAIP,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,YAAY;IAyCpB,OAAO,CAAC,iBAAiB;CAsB1B"}
|