tracker wip

This commit is contained in:
minjaesong
2026-04-20 17:38:02 +09:00
parent b2faab9377
commit 4e647f9fe1
6 changed files with 339 additions and 2 deletions

View File

@@ -0,0 +1,126 @@
/**
* TSVM Audio Device Tracker
*
* Created by minjaesong on 2026-04-20
*/
const win = require("wintex")
const sym = {
/* accidentals */
accnull:"\u0094\u0095"
demisharp:"\u0094\u0080",
sharp:"\u0094\u0081",
sesquisharp:"\u0082\u0083",
doublesharp:"\u0094\u0084",
triplesharp:"\u0081\u0084",
quadsharp:"\u0085\u0086",
demiflat:"\u0094\u0087",
flat:"\u0094\u0088",
sesquiflat:"\u0090\u0091",
doubleflat:"\u0089\u008A",
tripleflat:"\u008B\u008C",
quadflat:"\u008D\u008E",
/* special notes */
keyoff:"\u0092\u00CD\u00CD\u0093",
notecut:"\u008F\u008F\u008F\u008F",
/* miscellaneous */
cent:"\u009B",
unticked:"\u009E",
ticked:"\u009F",
}
const pitchTablePresets = [
{name:"null", table:[]},
/* Xenharmonic, equal temperament */
{name:"5-TET", table:[0x0,0x333,0x666,0x99A,0xCCD]},
{name:"7-TET", table:[0x0,0x249,0x492,0x6DB,0x925,0xB6E,0xDB7]},
{name:"10-TET", table:[0x0,0x19A,0x333,0x4CD,0x666,0x800,0x99A,0xB33,0xCCD,0xE66]},
{name:"16-TET", table:[0x0,0x100,0x200,0x300,0x400,0x500,0x600,0x700,0x800,0x900,0xA00,0xB00,0xC00,0xD00,0xE00,0xF00]},
{name:"19-TET", table:[0x0,0xD8,0x1AF,0x287,0x35E,0x436,0x50D,0x5E5,0x6BD,0x794,0x86C,0x943,0xA1B,0xAF3,0xBCA,0xCA2,0xD79,0xE51,0xF28]},
{name:"22-TET", table:[0x0,0xBA,0x174,0x22F,0x2E9,0x3A3,0x45D,0x517,0x5D1,0x68C,0x746,0x800,0x8BA,0x974,0xA2F,0xAE9,0xBA3,0xC5D,0xD17,0xDD1,0xE8C,0xF46]},
{name:"24-TET", table:[0x0,0xAB,0x155,0x200,0x2AB,0x355,0x400,0x4AB,0x555,0x600,0x6AB,0x755,0x800,0x8AB,0x955,0xA00,0xAAB,0xB55,0xC00,0xCAB,0xD55,0xE00,0xEAB,0xF55]},
{name:"31-TET", table:[0x0,0x84,0x108,0x18C,0x211,0x295,0x319,0x39D,0x421,0x4A5,0x529,0x5AD,0x632,0x6B6,0x73A,0x7BE,0x842,0x8C6,0x94A,0x9CE,0xA53,0xAD7,0xB5B,0xBDF,0xC63,0xCE7,0xD6B,0xDEF,0xE74,0xEF8,0xF7C]},
{name:"53-TET", table:[0x0,0x4D,0x9B,0xE8,0x135,0x182,0x1D0,0x21D,0x26A,0x2B8,0x305,0x352,0x39F,0x3ED,0x43A,0x487,0x4D5,0x522,0x56F,0x5BC,0x60A,0x657,0x6A4,0x6F2,0x73F,0x78C,0x7D9,0x827,0x874,0x8C1,0x90E,0x95C,0x9A9,0x9F6,0xA44,0xA91,0xADE,0xB2B,0xB79,0xBC6,0xC13,0xC61,0xCAE,0xCFB,0xD48,0xD96,0xDE3,0xE30,0xE7E,0xECB,0xF18,0xF65,0xFB3]},
/* 12-TET variations */
{name:"12-TET", table:[0x0,0x155,0x2AB,0x400,0x555,0x6AB,0x800,0x955,0xAAB,0xC00,0xD55,0xEAB]},
{name:"Pythagorean Diminished Fifth", table:[0x0,0x134,0x2B8,0x3EC,0x570,0x6A4,0x7D8,0x95C,0xA90,0xC14,0xD48,0xECC]},
{name:"Pythagorean Augmented Fourth", table:[0x0,0x134,0x2B8,0x3EC,0x570,0x6A4,0x828,0x95C,0xA90,0xC14,0xD48,0xECC]},
{name:"Shierlu", table:[0x0,0x184,0x2B8,0x43C,0x570,0x6F4,0x828,0x95C,0xAE0,0xC14,0xD98,0xECC]},
]
function noteName4096(n) {
const N = 4096;
// 12-TET natural note positions (C..B)
const d12 = [0, 2, 4, 5, 7, 9, 11];
const letters = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
// Precompute bases (integer-rounded)
// base[i] = round(d12[i] * N / 12)
const base = d12.map(d => ((d * N + 6) / 12) | 0);
// Scale everything by 24 (quarter-semitone grid)
const pitch24 = n * 24;
const N24 = N; // because k multiplies N directly in scaled space
let best_i = 0;
let best_k = 0;
let best_score = Infinity;
const KMAX = 8; // up to quad accidentals (±8 quarter-steps)
for (let i = 0; i < 7; i++) {
const base24 = base[i] * 24;
const delta = pitch24 - base24;
// nearest integer k ≈ delta / N
let k = ((delta + (delta >= 0 ? N24 / 2 : -N24 / 2)) / N24) | 0;
// clamp to allowed accidentals
if (k > KMAX) k = KMAX;
if (k < -KMAX) k = -KMAX;
const err = Math.abs(delta - k * N24);
// scoring: prioritize pitch accuracy, then smaller accidentals
const score = err * 1000 + Math.abs(k) * 10;
if (score < best_score) {
best_score = score;
best_i = i;
best_k = k;
}
}
// accidental mapping
function accidental(k) {
switch (k) {
case 0: return sym.accnull;
case 1: return sym.demisharp;
case 2: return sym.sharp;
case 3: return sym.sesquisharp;
case 4: return sym.doublesharp;
case 5: return sym.triplesharp;
case 6: return sym.quadsharp;
case -1: return sym.demiflat;
case -2: return sym.flat;
case -3: return sym.sesquiflat;
case -4: return sym.doubleflat;
case -5: return sym.tripleflat;
case -6: return sym.quadflat;
default:
// fallback if you extend beyond quad
return (k > 0 ? '+' : '-') + k.toString(36);
}
}
// octave (C-based)
const octave = ((n / N)|0) + 1;
return letters[best_i] + accidental(best_k) + octave;
}

Binary file not shown.

Binary file not shown.