tuner-cli 2026.4.1

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.
@@ -0,0 +1,457 @@
1
+ import process from 'node:process';
2
+ import Decibri from 'decibri';
3
+ import { INSTRUMENTS, TunerSession, createPitchDetector, findInstrument, findTuning, mergeTunerSettings, } from 'tuner-core';
4
+ import { DecibriAudioProvider } from './decibri-audio.js';
5
+ import { DISPLAY_STYLES, defaultDisplayStyle, displayStyleLabel, renderTunerLine, } from './display/styles.js';
6
+ import { installKeypress } from './input/keys.js';
7
+ import { feedSelectListKey, isSelectListActive, startSelectList, } from './menus/select-list.js';
8
+ import { CLI_DETECTORS, parseDeviceArg } from './parse-args.js';
9
+ import { writeVerboseStartup } from './verbose-startup.js';
10
+ const RATE_PRESETS = [44100, 48000, 96000];
11
+ const CENTS_PRESETS = [1, 2, 3, 5, 7, 10, 15, 20, 25];
12
+ const COLOR_CHOICES = ['auto', 'always', 'never'];
13
+ /** Marks the row that matches the active setting (cursor ▸ is separate). */
14
+ function menuLabelCurrent(text, isCurrent) {
15
+ return isCurrent ? `${text} — current` : text;
16
+ }
17
+ function colorMenuBase(label) {
18
+ if (label === 'auto')
19
+ return 'auto (TTY / env)';
20
+ if (label === 'always')
21
+ return 'always';
22
+ return 'never';
23
+ }
24
+ function deviceSummaryShort(raw) {
25
+ if (raw === undefined)
26
+ return 'default (host)';
27
+ const devices = Decibri.devices();
28
+ const n = Number(raw);
29
+ if (Number.isInteger(n) && String(n) === raw) {
30
+ const d = devices.find((x) => x.index === n);
31
+ if (d)
32
+ return `[${d.index}] ${d.name}`;
33
+ }
34
+ return raw.length > 28 ? `${raw.slice(0, 25)}…` : raw;
35
+ }
36
+ export async function runTunerSession(args) {
37
+ const instrument0 = findInstrument(args.instrumentId);
38
+ if (!instrument0) {
39
+ console.error(`Unknown instrument: ${args.instrumentId}`);
40
+ process.exitCode = 1;
41
+ return;
42
+ }
43
+ const tuning0 = findTuning(args.instrumentId, args.tuningId);
44
+ if (!tuning0) {
45
+ console.error(`Unknown tuning "${args.tuningId}" for instrument ${args.instrumentId}`);
46
+ process.exitCode = 1;
47
+ return;
48
+ }
49
+ const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
50
+ let instrumentId = args.instrumentId;
51
+ let tuningId = args.tuningId;
52
+ let instrument = instrument0;
53
+ let tuning = tuning0;
54
+ let displayStyle = args.style ?? defaultDisplayStyle(isTTY, process.env);
55
+ const live = {
56
+ detector: args.detector,
57
+ rate: args.rate,
58
+ deviceRaw: args.device,
59
+ centsThreshold: args.centsThreshold,
60
+ color: args.color,
61
+ };
62
+ let termWidth = process.stdout.columns ?? 80;
63
+ process.stdout.on('resize', () => {
64
+ termWidth = process.stdout.columns ?? 80;
65
+ });
66
+ let session = null;
67
+ let lastTunerLine = '';
68
+ const renderCtx = () => ({
69
+ style: displayStyle,
70
+ colorChoice: live.color,
71
+ termWidth,
72
+ isTTY: Boolean(process.stdout.isTTY),
73
+ env: process.env,
74
+ });
75
+ const formatBanner = () => `Listening (${instrument.name} — ${tuning.name} @ ${live.rate} Hz). ` +
76
+ `${isTTY ? '[i/t/s/a] menus · ' : ''}[q / Esc] to quit.`;
77
+ const refreshBanner = () => {
78
+ if (!process.stdout.isTTY)
79
+ return;
80
+ process.stdout.write(`\x1b[1A\r\x1b[K${formatBanner()}\n\r\x1b[K${lastTunerLine}`);
81
+ };
82
+ function reprintVerboseConfig() {
83
+ if (!args.verbose)
84
+ return;
85
+ const tunerSettings = mergeTunerSettings({
86
+ pitchDetector: live.detector,
87
+ audioFrameSamples: 4096,
88
+ });
89
+ const snapshot = {
90
+ verbose: args.verbose,
91
+ rate: live.rate,
92
+ instrumentId,
93
+ tuningExplicit: args.tuningExplicit,
94
+ tuningId,
95
+ detector: live.detector,
96
+ centsThreshold: live.centsThreshold,
97
+ color: live.color,
98
+ ...(live.deviceRaw !== undefined ? { device: live.deviceRaw } : {}),
99
+ ...(displayStyle !== undefined ? { style: displayStyle } : {}),
100
+ };
101
+ writeVerboseStartup(process.stderr, {
102
+ args: snapshot,
103
+ displayStyle,
104
+ isTTY,
105
+ stdoutTTY: Boolean(process.stdout.isTTY),
106
+ instrumentId,
107
+ instrumentName: instrument.name,
108
+ tuningId,
109
+ tuningName: tuning.name,
110
+ audioFrameSamples: tunerSettings.audioFrameSamples,
111
+ deviceRaw: live.deviceRaw,
112
+ deviceParsed: parseDeviceArg(live.deviceRaw),
113
+ afterChange: true,
114
+ });
115
+ }
116
+ function wireSessionHandlers(s) {
117
+ s.on('result', (result) => {
118
+ if (isSelectListActive())
119
+ return;
120
+ const line = renderTunerLine(result, renderCtx());
121
+ lastTunerLine = line;
122
+ process.stdout.write(`\r\x1b[K${line}`);
123
+ });
124
+ s.on('error', (err) => {
125
+ console.error(`\n${err.message}`);
126
+ process.exitCode = 1;
127
+ });
128
+ }
129
+ async function restartEngine(fatalOnError) {
130
+ try {
131
+ session?.stop();
132
+ session = null;
133
+ const tunerSettings = mergeTunerSettings({
134
+ pitchDetector: live.detector,
135
+ audioFrameSamples: 4096,
136
+ });
137
+ const deviceOpt = parseDeviceArg(live.deviceRaw);
138
+ const audio = new DecibriAudioProvider(live.rate, tunerSettings.audioFrameSamples, {
139
+ ...(deviceOpt !== undefined ? { device: deviceOpt } : {}),
140
+ onStreamError: (err) => {
141
+ console.error(`\nAudio error: ${err.message}`);
142
+ session?.stop();
143
+ process.exitCode = 1;
144
+ process.exit();
145
+ },
146
+ });
147
+ const pitchDetector = createPitchDetector(tunerSettings);
148
+ const s = new TunerSession(audio, pitchDetector, tunerSettings);
149
+ s.setTuning(tuning);
150
+ s.applyPreferences({ centsThreshold: live.centsThreshold });
151
+ wireSessionHandlers(s);
152
+ await s.start();
153
+ session = s;
154
+ return true;
155
+ }
156
+ catch (e) {
157
+ const msg = e instanceof Error ? e.message : String(e);
158
+ console.error(`Failed to start audio: ${msg}`);
159
+ if (fatalOnError) {
160
+ process.exitCode = 1;
161
+ process.exit(1);
162
+ }
163
+ return false;
164
+ }
165
+ }
166
+ let uninstallKeys = null;
167
+ const shutdown = () => {
168
+ uninstallKeys?.();
169
+ uninstallKeys = null;
170
+ session?.stop();
171
+ process.stdout.write('\n');
172
+ process.exit(0);
173
+ };
174
+ process.on('SIGINT', shutdown);
175
+ process.on('SIGTERM', shutdown);
176
+ process.on('SIGBREAK', shutdown);
177
+ const tunerSettingsInitial = mergeTunerSettings({
178
+ pitchDetector: live.detector,
179
+ audioFrameSamples: 4096,
180
+ });
181
+ const deviceOptInitial = parseDeviceArg(live.deviceRaw);
182
+ if (args.verbose) {
183
+ writeVerboseStartup(process.stderr, {
184
+ args,
185
+ displayStyle,
186
+ isTTY,
187
+ stdoutTTY: Boolean(process.stdout.isTTY),
188
+ instrumentId,
189
+ instrumentName: instrument.name,
190
+ tuningId,
191
+ tuningName: tuning.name,
192
+ audioFrameSamples: tunerSettingsInitial.audioFrameSamples,
193
+ deviceRaw: live.deviceRaw,
194
+ deviceParsed: deviceOptInitial,
195
+ });
196
+ }
197
+ if (!(await restartEngine(false))) {
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+ process.stdout.write(`${formatBanner()}\n`);
202
+ let menuBusy = false;
203
+ const runMenu = (work) => {
204
+ menuBusy = true;
205
+ void work().finally(() => {
206
+ menuBusy = false;
207
+ });
208
+ };
209
+ const runInstrumentPicker = async () => {
210
+ const idx = await startSelectList({
211
+ title: 'Instrument',
212
+ items: INSTRUMENTS,
213
+ label: (it) => menuLabelCurrent(it.name, it.id === instrumentId),
214
+ stdout: process.stdout,
215
+ });
216
+ if (idx === null)
217
+ return;
218
+ const inst = INSTRUMENTS[idx];
219
+ if (!inst)
220
+ return;
221
+ instrumentId = inst.id;
222
+ instrument = inst;
223
+ const keep = inst.tunings.find((t) => t.id === tuningId);
224
+ tuningId = keep ? tuningId : (inst.tunings[0]?.id ?? tuningId);
225
+ const tun = findTuning(instrumentId, tuningId) ?? inst.tunings[0] ?? null;
226
+ if (tun) {
227
+ tuning = tun;
228
+ session?.setTuning(tun);
229
+ refreshBanner();
230
+ }
231
+ reprintVerboseConfig();
232
+ };
233
+ const runTuningPicker = async () => {
234
+ const idx = await startSelectList({
235
+ title: `Tuning — ${instrument.name}`,
236
+ items: instrument.tunings,
237
+ label: (t) => menuLabelCurrent(t.name, t.id === tuningId),
238
+ stdout: process.stdout,
239
+ });
240
+ if (idx === null)
241
+ return;
242
+ const tun = instrument.tunings[idx];
243
+ if (!tun)
244
+ return;
245
+ tuningId = tun.id;
246
+ tuning = tun;
247
+ session?.setTuning(tun);
248
+ refreshBanner();
249
+ reprintVerboseConfig();
250
+ };
251
+ const runAdvancedMenu = async () => {
252
+ while (true) {
253
+ const advancedRows = [
254
+ `Pitch detector — ${live.detector}`,
255
+ `Sample rate — ${live.rate} Hz`,
256
+ `Input device — ${deviceSummaryShort(live.deviceRaw)}`,
257
+ `Cents threshold — ±${live.centsThreshold}`,
258
+ `Color — ${live.color}`,
259
+ `Display style — ${displayStyleLabel(displayStyle)}`,
260
+ `Instrument — ${instrument.name}`,
261
+ `Tuning — ${tuning.name}`,
262
+ ];
263
+ const idx = await startSelectList({
264
+ title: 'Advanced options',
265
+ items: advancedRows,
266
+ label: (row) => row,
267
+ stdout: process.stdout,
268
+ });
269
+ if (idx === null)
270
+ return;
271
+ switch (idx) {
272
+ case 0: {
273
+ const j = await startSelectList({
274
+ title: 'Pitch detector',
275
+ items: [...CLI_DETECTORS],
276
+ label: (d) => menuLabelCurrent(d, d === live.detector),
277
+ stdout: process.stdout,
278
+ });
279
+ if (j === null)
280
+ break;
281
+ const d = CLI_DETECTORS[j];
282
+ if (d === undefined || d === live.detector)
283
+ break;
284
+ live.detector = d;
285
+ await restartEngine(true);
286
+ refreshBanner();
287
+ reprintVerboseConfig();
288
+ break;
289
+ }
290
+ case 1: {
291
+ const j = await startSelectList({
292
+ title: 'Sample rate (restarts audio)',
293
+ items: [...RATE_PRESETS],
294
+ label: (hz) => menuLabelCurrent(`${hz} Hz`, hz === live.rate),
295
+ stdout: process.stdout,
296
+ });
297
+ if (j === null)
298
+ break;
299
+ const hz = RATE_PRESETS[j];
300
+ if (hz === undefined || hz === live.rate)
301
+ break;
302
+ live.rate = hz;
303
+ await restartEngine(true);
304
+ refreshBanner();
305
+ reprintVerboseConfig();
306
+ break;
307
+ }
308
+ case 2: {
309
+ const devices = Decibri.devices();
310
+ const items = [
311
+ { label: 'Default (host input)', raw: undefined },
312
+ ...devices.map((dev) => ({
313
+ raw: String(dev.index),
314
+ label: `[${dev.index}] ${dev.name}${dev.isDefault ? ' (default)' : ''}`,
315
+ })),
316
+ ];
317
+ const j = await startSelectList({
318
+ title: 'Input device (restarts audio)',
319
+ items,
320
+ label: (row) => menuLabelCurrent(row.label, row.raw === live.deviceRaw),
321
+ stdout: process.stdout,
322
+ });
323
+ if (j === null)
324
+ break;
325
+ const row = items[j];
326
+ if (row === undefined)
327
+ break;
328
+ const nextRaw = row.raw;
329
+ if (nextRaw === live.deviceRaw)
330
+ break;
331
+ live.deviceRaw = nextRaw;
332
+ await restartEngine(true);
333
+ refreshBanner();
334
+ reprintVerboseConfig();
335
+ break;
336
+ }
337
+ case 3: {
338
+ const j = await startSelectList({
339
+ title: 'Cents threshold',
340
+ items: [...CENTS_PRESETS],
341
+ label: (n) => menuLabelCurrent(`±${n} cents`, n === live.centsThreshold),
342
+ stdout: process.stdout,
343
+ });
344
+ if (j === null)
345
+ break;
346
+ const n = CENTS_PRESETS[j];
347
+ if (n === undefined || n === live.centsThreshold)
348
+ break;
349
+ live.centsThreshold = n;
350
+ session?.applyPreferences({ centsThreshold: n });
351
+ reprintVerboseConfig();
352
+ break;
353
+ }
354
+ case 4: {
355
+ const j = await startSelectList({
356
+ title: 'Color (SGR)',
357
+ items: [...COLOR_CHOICES],
358
+ label: (c) => menuLabelCurrent(colorMenuBase(c), c === live.color),
359
+ stdout: process.stdout,
360
+ });
361
+ if (j === null)
362
+ break;
363
+ const c = COLOR_CHOICES[j];
364
+ if (c === undefined || c === live.color)
365
+ break;
366
+ live.color = c;
367
+ reprintVerboseConfig();
368
+ break;
369
+ }
370
+ case 5: {
371
+ const j = await startSelectList({
372
+ title: 'Display style',
373
+ items: DISPLAY_STYLES,
374
+ label: (s) => menuLabelCurrent(displayStyleLabel(s), s === displayStyle),
375
+ stdout: process.stdout,
376
+ });
377
+ if (j === null)
378
+ break;
379
+ const st = DISPLAY_STYLES[j];
380
+ if (st) {
381
+ displayStyle = st;
382
+ reprintVerboseConfig();
383
+ }
384
+ break;
385
+ }
386
+ case 6: {
387
+ await runInstrumentPicker();
388
+ break;
389
+ }
390
+ case 7: {
391
+ await runTuningPicker();
392
+ break;
393
+ }
394
+ default:
395
+ break;
396
+ }
397
+ }
398
+ };
399
+ const routeKey = (mk) => {
400
+ if (feedSelectListKey(mk))
401
+ return;
402
+ if (mk.kind === 'ctrl-c') {
403
+ shutdown();
404
+ return;
405
+ }
406
+ if (mk.kind === 'escape') {
407
+ shutdown();
408
+ return;
409
+ }
410
+ if (!isTTY || mk.kind !== 'letter')
411
+ return;
412
+ if (isSelectListActive() || menuBusy)
413
+ return;
414
+ if (mk.ch === 'q') {
415
+ shutdown();
416
+ return;
417
+ }
418
+ if (mk.ch === 'i') {
419
+ runMenu(runInstrumentPicker);
420
+ return;
421
+ }
422
+ if (mk.ch === 't') {
423
+ runMenu(runTuningPicker);
424
+ return;
425
+ }
426
+ if (mk.ch === 's') {
427
+ runMenu(async () => {
428
+ const idx = await startSelectList({
429
+ title: 'Display style',
430
+ items: DISPLAY_STYLES,
431
+ label: (s) => menuLabelCurrent(displayStyleLabel(s), s === displayStyle),
432
+ stdout: process.stdout,
433
+ });
434
+ if (idx === null)
435
+ return;
436
+ const st = DISPLAY_STYLES[idx];
437
+ if (st) {
438
+ displayStyle = st;
439
+ reprintVerboseConfig();
440
+ }
441
+ });
442
+ return;
443
+ }
444
+ if (mk.ch === 'a') {
445
+ runMenu(runAdvancedMenu);
446
+ }
447
+ };
448
+ if (isTTY) {
449
+ const { onKey, uninstall } = installKeypress(process.stdin);
450
+ uninstallKeys = uninstall;
451
+ onKey(routeKey);
452
+ }
453
+ await new Promise(() => {
454
+ /* until signal */
455
+ });
456
+ }
457
+ //# sourceMappingURL=run-tuner-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tuner-session.js","sourceRoot":"","sources":["../src/run-tuner-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import process from 'node:process';
2
+ import Decibri from 'decibri';
3
+ import { resolveColorMode } from './ansi.js';
4
+ import { displayStyleLabel } from './display/styles.js';
5
+ function describeInputDevice(raw, parsed) {
6
+ const devices = Decibri.devices();
7
+ if (devices.length === 0)
8
+ return '(no input devices reported)';
9
+ if (parsed === undefined) {
10
+ const d = devices.find((x) => x.isDefault) ?? devices[0];
11
+ return d ? `[${d.index}] ${d.name} (host default)` : '(none)';
12
+ }
13
+ if (typeof parsed === 'number') {
14
+ const d = devices.find((x) => x.index === parsed);
15
+ return d
16
+ ? `[${d.index}] ${d.name}`
17
+ : `[${parsed}] (no device at this index)`;
18
+ }
19
+ const lower = parsed.toLowerCase();
20
+ const matches = devices.filter((d) => d.name.toLowerCase().includes(lower));
21
+ if (matches.length === 1) {
22
+ const d = matches[0];
23
+ return d ? `"${raw}" → [${d.index}] ${d.name}` : String(raw);
24
+ }
25
+ if (matches.length === 0) {
26
+ return `"${raw}" (no substring match — open may fail)`;
27
+ }
28
+ return `"${raw}" (${matches.length} substring matches — open may fail)`;
29
+ }
30
+ export function writeVerboseStartup(out, opts) {
31
+ const { args } = opts;
32
+ const colorOn = resolveColorMode(args.color, opts.stdoutTTY, process.env);
33
+ if (opts.afterChange) {
34
+ out.write('\n');
35
+ }
36
+ const title = opts.afterChange
37
+ ? 'tuner: configuration (updated)'
38
+ : 'tuner: configuration';
39
+ const lines = [
40
+ title,
41
+ ` instrument: ${opts.instrumentName} (${opts.instrumentId})`,
42
+ ` tuning: ${opts.tuningName} (${opts.tuningId})`,
43
+ ` detector: ${args.detector}`,
44
+ ` sample rate: ${args.rate} Hz`,
45
+ ` frame samples: ${opts.audioFrameSamples}`,
46
+ ` device: ${opts.deviceRaw ?? '(default)'} — ${describeInputDevice(opts.deviceRaw, opts.deviceParsed)}`,
47
+ ` cents threshold: ${args.centsThreshold}`,
48
+ ` color: ${args.color} (SGR ${colorOn ? 'on' : 'off'})`,
49
+ ` display style: ${displayStyleLabel(opts.displayStyle)} (${opts.displayStyle})`,
50
+ ` stdin/stdout TTY: ${opts.isTTY}`,
51
+ ];
52
+ for (const line of lines) {
53
+ out.write(`${line}\n`);
54
+ }
55
+ }
56
+ //# sourceMappingURL=verbose-startup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verbose-startup.js","sourceRoot":"","sources":["../src/verbose-startup.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "tuner-cli",
3
+ "version": "2026.4.1",
4
+ "description": "Terminal chromatic instrument tuner (Node.js CLI) using tuner-core and decibri / PortAudio for microphone capture.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "tuner": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "keywords": [
16
+ "tuner",
17
+ "cli",
18
+ "chromatic",
19
+ "pitch",
20
+ "audio",
21
+ "terminal",
22
+ "microphone",
23
+ "decibri",
24
+ "portaudio",
25
+ "guitar"
26
+ ],
27
+ "engines": {
28
+ "node": ">=20.0.0"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/mducharme/Tuner.git",
33
+ "directory": "packages/tuner-cli"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/mducharme/Tuner/issues"
37
+ },
38
+ "homepage": "https://github.com/mducharme/Tuner/tree/main/packages/tuner-cli#readme",
39
+ "dependencies": {
40
+ "commander": "^14.0.3",
41
+ "decibri": "^1.0.0",
42
+ "tuner-core": "^2026.4.2"
43
+ },
44
+ "devDependencies": {
45
+ "@biomejs/biome": "^1.9.4",
46
+ "@types/node": "^25.5.2",
47
+ "@vitest/coverage-v8": "^4.1.2",
48
+ "publint": "^0.3.12",
49
+ "tsx": "^4.21.0",
50
+ "typescript": "^6.0.2",
51
+ "vitest": "^4.1.2"
52
+ },
53
+ "scripts": {
54
+ "dev": "tsx src/index.ts",
55
+ "dev:watch": "tsx watch src/index.ts",
56
+ "build": "tsc",
57
+ "start": "node dist/index.js",
58
+ "test": "vitest run",
59
+ "test:coverage": "vitest run --coverage",
60
+ "typecheck": "tsc --noEmit",
61
+ "lint": "biome check ./src ./tests",
62
+ "package:assert": "publint --strict"
63
+ }
64
+ }