mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-22 12:52:29 +00:00
81 lines
3.3 KiB
JavaScript
81 lines
3.3 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
function freqToMidi(f) { return 69 + 12 * Math.log2(f / 440); }
|
|
function midiToFreq(m) { return Math.pow(2, (m - 69) / 12) * 440; }
|
|
|
|
const _NOTE_NAMES = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
|
|
const _NOTE_FLAT = ['C','Db','D','Eb', 'E','F','Gb','G','Ab','A','Bb', 'B'];
|
|
// Returns true when the tuning name implies flat notation (e.g. "Eb Standard", "Bb Standard").
|
|
function preferFlats(tuningName) {
|
|
return typeof tuningName === 'string' && /\b[A-G]b\b/.test(tuningName);
|
|
}
|
|
function midiToNote(m, useFlats) {
|
|
return (useFlats ? _NOTE_FLAT : _NOTE_NAMES)[((Math.round(m) % 12) + 12) % 12];
|
|
}
|
|
|
|
|
|
// Per-string-count standard open-string MIDI arrays
|
|
const _BASE_MIDI = {
|
|
4: [28, 33, 38, 43], // bass 4: E1 A1 D2 G2
|
|
5: [23, 28, 33, 38, 43], // bass 5: B0 E1 A1 D2 G2
|
|
6: [40, 45, 50, 55, 59, 64], // guitar 6: E2 A2 D3 G3 B3 E4
|
|
7: [35, 40, 45, 50, 55, 59, 64], // guitar 7: B1 E2 A2 D3 G3 B3 E4
|
|
8: [30, 35, 40, 45, 50, 55, 59, 64], // guitar 8: F#1 B1 E2 A2 D3 G3 B3 E4
|
|
};
|
|
|
|
function offsetsToFreqs(offsets, isBass) {
|
|
const len = offsets.length;
|
|
let base;
|
|
if (len === 4 || len === 5) {
|
|
base = isBass ? _BASE_MIDI[len] : _BASE_MIDI[6];
|
|
} else {
|
|
base = _BASE_MIDI[len] || _BASE_MIDI[6];
|
|
}
|
|
return offsets.map((offset, i) => {
|
|
const root = i < base.length ? base[i] : base[base.length - 1];
|
|
return midiToFreq(root + offset);
|
|
});
|
|
}
|
|
|
|
function getTuningName(offsets) {
|
|
if (!offsets || offsets.length === 0) return 'Unknown';
|
|
const len = offsets.length;
|
|
if (len < 4 || len > 8) return offsets.join(' ');
|
|
|
|
// First-string open MIDI for this length (same table as _BASE_MIDI column 0).
|
|
const firstStringMidi = (_BASE_MIDI[len] || _BASE_MIDI[6])[0];
|
|
const noteNames = ['C','C#','D','Eb','E','F','F#','G','Ab','A','A#','B'];
|
|
|
|
// All-equal: name by the note the lowest string becomes at this offset.
|
|
if (offsets.every(o => o === offsets[0])) {
|
|
const noteIdx = ((firstStringMidi + offsets[0]) % 12 + 12) % 12;
|
|
return noteNames[noteIdx] + ' Standard';
|
|
}
|
|
|
|
// Drop tuning: first string is exactly 2 semitones below the rest (all equal).
|
|
if (offsets[0] === offsets[1] - 2 && offsets.slice(1).every(o => o === offsets[1])) {
|
|
const noteIdx = ((firstStringMidi + offsets[0]) % 12 + 12) % 12;
|
|
return 'Drop ' + noteNames[noteIdx];
|
|
}
|
|
|
|
// Named lookup table for specific patterns
|
|
const named = {
|
|
// 6-string
|
|
'-2,0,0,0,0,0': 'Drop D', '-4,-2,-2,-2,-2,-2': 'Drop C',
|
|
'-2,-2,0,0,0,0': 'Double Drop D', '0,0,0,-1,0,0': 'Open G',
|
|
'-2,-2,0,0,-2,-2': 'Open D', '-2,0,0,0,-2,0': 'DADGAD',
|
|
'0,2,2,1,0,0': 'Open E', '-2,0,0,2,3,2': 'Open D (alt)',
|
|
// 7-string
|
|
'-2,0,0,0,0,0,0': 'Drop A',
|
|
// 8-string
|
|
'-2,0,0,0,0,0,0,0': 'Drop E',
|
|
};
|
|
const key = offsets.join(',');
|
|
if (named[key]) return named[key];
|
|
|
|
return offsets.join(' ');
|
|
}
|
|
|
|
window._tunerUtils = { freqToMidi, midiToFreq, midiToNote, offsetsToFreqs, getTuningName, preferFlats };
|
|
})();
|