chordsong
Version:
ChordSong is a simple text format for the notation of lyrics with guitar chords, and an application that renders them to portable HTML pages.
174 lines • 6.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Diagram = exports.fretStringsRegEx = exports.stringsFretsRegEx = void 0;
exports.stringsFretsRegEx = /^([oOxX\d]{6}|(?:(?:[xXoO]|\d{1,2}),){5}(?:[xXoO]|\d{1,2}))$/;
exports.fretStringsRegEx = /^(([12]?\d):([1-6](-[1-6])?)(,[1-6](-[1-6])?){0,5})(\/([12]?\d):([1-6](-[1-6])?)(,[1-6](-[1-6])?){0,5}){1,3}$/;
class Diagram {
constructor(parsedDiagram, chordName, chordVariant, chordRenderName) {
this._stringFrets = [];
this.fretStrings = {};
this._fingersAndBarres = [];
this.chordName = chordName;
this.chordVariant = chordVariant;
this.chordRenderName = chordRenderName ?? chordName;
try {
this.fromStringFrets(parsedDiagram);
}
catch (error) {
this.fromFingersAndBarres(parsedDiagram);
}
}
get stringFrets() {
return this._stringFrets;
}
set stringFrets(arr) {
this._stringFrets = arr;
this._computeFretStrings();
this._computeFingersAndBarrels();
}
get fingersAndBarrels() {
return this._fingersAndBarres;
}
set fingersAndBarrels(arr) {
this._fingersAndBarres = arr;
this._computeStringFrets();
this._computeFretStrings();
}
get minFret() {
return Math.min(...this.stringFrets.filter(fret => fret > 0));
}
get maxFret() {
return Math.max(...this.stringFrets);
}
fromStringFrets(parsedDiagram) {
if (!exports.stringsFretsRegEx.test(parsedDiagram)) {
throw new Error(`invalid stringFrets format for ${parsedDiagram}`);
}
parsedDiagram = parsedDiagram
.replace(/\|/g, '')
.replace(/[Oo]/g, '0')
.replace(/[Xx]/g, 'x');
this.stringFrets = (parsedDiagram.match(/[x0-9]{6}/) != null
? parsedDiagram.split('')
: parsedDiagram.split(',')).map((str) => str === 'x' ? -1 : Number(str));
}
fromFingersAndBarres(parsedDiagram) {
if (!exports.fretStringsRegEx.test(parsedDiagram)) {
throw new Error(`invalid format for ${parsedDiagram}`);
}
const fingersAndBarres = [];
parsedDiagram.split('/').forEach(item => {
const parsed = [];
let fret;
item.split(':').forEach((value, index) => {
if (index === 0) {
fret = Number(value);
}
else if (index === 1) {
value.split(',').forEach(range => {
let a = Number(range[0]);
a = 6 - a;
let b = Number(range[range.length - 1]);
b = 6 - b;
parsed.push({
fret,
stringFrom: (a < b) ? a : b,
stringTo: (a >= b) ? a : b
});
});
}
else {
throw new Error(`Invalid diagram ${parsedDiagram}`);
}
});
parsed.forEach(item => {
fingersAndBarres.push(item);
});
});
this.fingersAndBarrels = fingersAndBarres;
}
_computeBarrel() {
const fingeredFrets = this.stringFrets.filter((item) => item > 0);
if (fingeredFrets.length < 5 || (fingeredFrets.length === 5 && this.stringFrets[0] > 0)) {
return null;
}
const barrels = {};
for (const [fretPos, strings] of Object.entries(this.fretStrings)) {
if (Number(fretPos) <= 0)
continue;
const from = Math.min(...strings);
let to = from;
for (let i = from + 1; i < 6; i++) {
if (!strings.includes(i) && this.stringFrets[i] >= 0 && this.stringFrets[i] < Number(fretPos)) {
break;
}
else {
to++;
}
}
barrels[fretPos] = { from, to };
}
let fret = 0;
let stringFrom = 0;
let stringTo = 0;
for (const [fretPos, fromTo] of Object.entries(barrels)) {
if (fromTo.to - fromTo.from + 1 > stringTo - stringFrom) {
fret = Number(fretPos);
stringFrom = fromTo.from;
stringTo = fromTo.to;
}
}
return { fret, stringFrom, stringTo };
}
_computeStringFrets() {
this._stringFrets = [-1, -1, -1, -1, -1, -1];
this._fingersAndBarres.forEach(item => {
const fret = item.fret;
const strings = range(item.stringTo, item.stringFrom);
strings.forEach(item => {
if (fret > this._stringFrets[item]) {
this._stringFrets[item] = fret;
}
});
});
}
_computeFretStrings() {
this._stringFrets.forEach((fret, string) => {
if (String(fret) in this.fretStrings) {
this.fretStrings[String(fret)].push(string);
}
else {
this.fretStrings[String(fret)] = [string];
}
});
}
_computeFingersAndBarrels() {
const barrel = this._computeBarrel();
if (barrel != null) {
this._fingersAndBarres.push(barrel);
}
for (const [fretPos, strings] of Object.entries(this.fretStrings)) {
if (Number(fretPos) <= 0)
continue;
if (barrel === null || Number(fretPos) !== barrel.fret) {
strings.forEach((fretStr) => this._fingersAndBarres.push({
fret: Number(fretPos),
stringFrom: fretStr,
stringTo: fretStr
}));
}
}
}
toString() {
return this.stringFrets.join(',').replace(/-1/g, 'x').replace(/0/g, 'o');
}
}
exports.Diagram = Diagram;
function range(max, min = 0, step = 1) {
const arr = [];
for (let i = min; i <= max; i += step) {
arr.push(i);
}
return arr;
}
//# sourceMappingURL=Diagram.js.map