var Transposer = (function ($) {
const wrapRegex = /(?:(?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)?(?:\d+[\+\-]?)?(?:m?(?:aug|dim|add|b|#)?(?:\d+[\+\-]?)?(?:\/?\d+[\+\-]?)?)(?:\/(?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)*)?)/g;
const lineRegex = /^\s*(?:(?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)?(?:\d+[\+\-]?)?(?:m?(?:aug|dim|add|b|#)?(?:\d+[\+\-]?)?(?:\/?\d+[\+\-]?)?)(?:\/(?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)*)?\s*)+$/;
const noteRegex = /\b(?:((?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)?)(?=(?:aug|m|dim)?(?:\s|\/))*)/;
const noteGRe = new RegExp(noteRegex, "g");
const simpleRegex = /(?:((?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)?)((?:\d+[\+\-]?)?(m|aug|dim|add|b|#)?(?:\d+[\+\-]?)?(?:\/?\d+[\+\-]?)?(?:\/((?:DO|RE|MI|FA|SOL|LA|SI)(?:b|\#)*))?))/;
const legalNotes = ["DO", "REb", "RE", "MIb", "MI", "FA", "FA#", "SOL", "LAb", "LA", "SIb", "SI"];
const N_KEYS = 12;
const scales = {
'#': ['DO', 'DO#', 'RE', 'RE#', 'MI', 'FA', 'FA#', 'SOL', 'SOL#', 'LA', 'LA#', 'SI'],
'b': ['DO', 'REb', 'RE', 'MIb', 'MI', 'FA', 'SOLb', 'SOL', 'LAb', 'LA', 'SIb', 'SI']
};
const Notes = {
"DO": {
index: 0,
type: "N"
},
"DO#": {
index: 1,
type: "#"
},
"REb": {
index: 1,
type: "b"
},
"RE": {
index: 2,
type: "#"
},
"RE#": {
index: 3,
type: "#"
},
"MIb": {
index: 3,
type: "b"
},
"MI": {
index: 4,
type: "#"
},
"FA": {
index: 5,
type: "b"
},
"FA#": {
index: 6,
type: "#"
},
"SOLb": {
index: 6,
type: "b"
},
"SOL": {
index: 7,
type: "#"
},
"SOL#": {
index: 8,
type: "#"
},
"LAb": {
index: 8,
type: "b"
},
"LA": {
index: 9,
type: "#"
},
"LA#": {
index: 10,
type: "#"
},
"SIb": {
index: 10,
type: "b"
},
"SI": {
index: 11,
type: "#"
}
};
let diffToSimple = {};
var IS_SIMPLE = 0;
String.prototype.insertAt = function (pos, str) {
return [this.slice(0, pos), str, this.slice(pos)].join('');
};
function init() {
var $pre = $('pre');
var $chiave = $("div.chiave", $pre);
if ($chiave) {
var lines = $pre.html().split('\n');
wrapChords(lines);
$pre.html(lines.join('\n'));
/* ---- CONTROLS ---- */
$('body').on('keydown', function (e) {
switch (e.which) {
case 107: // +
pitchUp();
break;
case 109: // -
pitchDown();
break;
default:
break;
}
})
.on('click', '#pitchUp', pitchUp)
.on('click', '#pitchDown', pitchDown)
.on('click', '#pitchUpresp', pitchUpresp)
.on('click', '#pitchDownresp', pitchDownresp)
.on("click", "#simplify", onSClick)
.on("click", "#unsimplify", onUSClick);
$('span.chord').on("mouseover", onChordOver);
$("#text-magnify, #text-magnify-responsive").click(function () {
$("#text-reduce, #text-reduce-responsive").removeClass("disabled");
$('#output-text').html(function (i, val) {
if (val < 3) {
var prePosition = $('.bottom-ad').offset();
var fontSize = parseFloat($('pre').css("font-size"));
var fontSize = fontSize + 3 + "px";
var lineHeight = parseFloat($('pre').css("line-height"));
var lineHeight = lineHeight + 2.8 + "px";
$('pre').css({'font-size':fontSize});
$('pre').css({'line-height':lineHeight});
var ret = val * 1 + 1;
return ret > 0 ? "+" + ret : ret;
} else {
$("#text-magnify, #text-magnify-responsive").addClass("disabled");
}
});
});
$("#text-reduce, #text-reduce-responsive").click(function () {
$("#text-magnify, #text-magnify-responsive").removeClass("disabled");
$('#output-text').html(function (i, val) {
if (val > -1) {
var prePosition = $('.bottom-ad').offset();
var fontSize = parseFloat($('pre').css("font-size"));
var fontSize = fontSize - 3 + "px";
var lineHeight = parseFloat($('pre').css("line-height"));
var lineHeight = lineHeight - 2.8 + "px";
$('pre').css({'font-size':fontSize});
$('pre').css({'line-height':lineHeight});
var ret = val * 1 - 1;
return ret > 0 ? "+" + ret : ret;
} else {
$("#text-reduce, #text-reduce-responsive").addClass("disabled");
}
});
});
restoreFavouriteK($chiave.attr('name'));
}
}
function pitchUp(e) {
e.preventDefault();
e.stopPropagation();
$('#output').html(function (i, val) {
if (val < 11) {
transpose(1);
var ret = val * 1 + 1;
return ret > 0 ? "+" + ret : ret;
}
});
}
function pitchUpresp(e) {
e.preventDefault();
e.stopPropagation();
$('#output-responsive').html(function (i, val) {
if (val < 11) {
transpose(1);
var ret = val * 1 + 1;
return ret > 0 ? "+" + ret : ret;
}
});
}
function pitchDown(e) {
e.preventDefault();
e.stopPropagation();
$('#output').html(function (i, val) {
if (val > -11) {
transpose(-1);
var ret = val * 1 - 1;
return ret > 0 ? "+" + ret : ret;
}
});
}
function pitchDownresp(e) {
e.preventDefault();
e.stopPropagation();
$('#output-responsive').html(function (i, val) {
if (val > -11) {
transpose(-1);
var ret = val * 1 - 1;
return ret > 0 ? "+" + ret : ret;
}
});
}
function onSClick(e) {
e.preventDefault();
e.stopPropagation();
if (!IS_SIMPLE) {
simplify();
IS_SIMPLE = 1;
$(this).addClass('checked');
$(this).attr("id", "unsimplify");
$('.chord').addClass('simplified');
}
}
function onUSClick(e) {
e.preventDefault();
e.stopPropagation();
if (IS_SIMPLE) {
unsimplify();
IS_SIMPLE = 0;
$(this).removeClass('checked');
$(this).attr("id", "simplify");
$('.chord').removeClass('simplified');
}
}
function onChordOver(e) {
e.preventDefault();
e.stopPropagation();
WidgetFactory.newWidget(this);
}
function restoreFavouriteK(oldK) {
var $btn = $('button#asfp-remove-fav-btn');
if ($btn.length) {
var newK = $btn.data("key");
var dlt = delta(Notes[oldK].index, Notes[newK].index);
for (var i = 1; i < N_KEYS; i++) {
var posDlt = delta(Notes[oldK].index, i);
var negDlt = delta(Notes[oldK].index, - i);
if (newK == shiftKey(oldK, posDlt)) {
dlt = posDlt;
break;
}
else if (newK == shiftKey(oldK, negDlt)) {
dlt = negDlt;
break;
}
}
transpose(dlt);
if (dlt == 0 || dlt == 12 || dlt == -12) {
$('#output').html("0");
$('#output-responsive').html("0");
} else if (dlt < -6) {
var dlt2 = 12 + dlt;
$('#output').html(dlt2);
$('#output-responsive').html(dlt2);
} else if (dlt > 6) {
var dlt2 = - 12 + dlt;
$('#output').html(dlt2);
$('#output-responsive').html(dlt2);
} else if (dlt > 0) {
var dlt2 = 12 - dlt;
$('#output').html("+" + dlt);
$('#output-responsive').html("+" + dlt);
} else {
$('#output').html(dlt);
$('#output-responsive').html(dlt);
}
}
}
function transpose(amount) {
var keys = $('pre > div.chiave');
keys.each(function () {
var $key = $(this);
var oldK = $key.attr("name");
switch (oldK) {
case "DO#":
oldK = "REb";
break;
case "RE#":
oldK = "MIb";
break;
case "SOLb":
oldK = "FA#";
break;
case "SOL#":
oldK = "LAb";
break;
case "LA#":
oldK = "SIb";
break;
}
var newK = shiftKey(oldK, amount);
changeNotes(oldK, newK, $key);
$key.attr("name", newK);
});
}
function changeNotes(oldK, newK, context) {
$("span.note", context).each(function () {
var $note = $(this);
var newNote = changePitch($note.html(), oldK, newK);
$note.html(newNote);
});
$("span.chord[data-old-bass]", context).each(function () {
var $chord = $(this);
var $newB = changePitch($chord.attr("data-old-bass"), oldK, newK);
$chord.attr("data-old-bass", $newB);
})
}
function changePitch(note, oldK, newK) {
var keyDelta = delta(Notes[oldK].index, Notes[newK].index);
var newKType = Notes[newK].type;
var newNoteIndex = circularIndex(Notes[note].index, keyDelta, N_KEYS);
return (newKType === "N") ? legalNotes[newNoteIndex] : scales[newKType][newNoteIndex];
}
function simplify() {
var chords = $('span.chord');
chords.each(function () {
var $chord = $(this);
var $oldText = $chord.text();
var matches = simpleRegex.exec($oldText);
if (matches[2] !== "") {
$chord.replaceWith(simplifyChord(matches));
}
});
}
function simplifyChord(matches) {
var erer = /(\d+[+-]?\d*)/.exec(matches[2]);
var $rootNote = $("", {"class": "note"})
.text(matches[1]);
var alter = matches[2];
var $simpleChord = $("", {"class": "chord"})
.on("mouseover", onChordOver)
.append($rootNote);
var whiteSp = 0;
var $simpleText = "";
if (!/dim/.test(alter)) {
if (/m/.test(alter)) {
if (!/d/.test(alter)) {
whiteSp--;
}
$simpleText = "m";
alter = alter.replace(/m/, "");
}
}
whiteSp = whiteSp + alter.length;
for (var i = 0; i < whiteSp; i++) {
$simpleText = $simpleText + " ";
}
$simpleChord.html($simpleChord.html() + $simpleText);
if (matches[4]) {
var alters = alter.split("/");
if (alters[0]) {
$simpleChord.attr("data-old", alters[0]);
}
$simpleChord.attr("data-old-bass", alters[1]);
} else {
$simpleChord.attr("data-old", alter);
}
return $simpleChord;
}
function unsimplify() {
$("span.chord[data-old]").each(function () {
var $chord = $(this);
var oldAlt = $chord.attr("data-old");
$chord.html($chord.html().trim());
$chord.html($chord.html() + oldAlt);
$chord.removeAttr("data-old");
});
$("span.chord[data-old-bass]").each(function () {
var $chord = $(this);
var oldB = $chord.attr("data-old-bass");
$chord.html($chord.html().trim());
$chord.html($chord.html() + "/")
.append(
$("", {
"class": "note"
})
.text(oldB)
);
$chord.removeAttr("data-old-bass");
});
}
function wrapChords(lines) {
lines.forEach(function (line, i) {
if (lineRegex.test(line)) {
line = insertChordTag(line);
line = insertNoteTag(line);
lines[i] = line;
}
});
}
function insertChordTag(line) {
var chord;
var chords = [];
while ((chord = wrapRegex.exec(line)) !== null) {
chords.push(chord);
}
chords.reverse().forEach(function (chord) {
line = line.insertAt(chord.index + chord[0].length, '');
line = line.insertAt(chord.index, '');
});
return line;
}
function insertNoteTag(line) {
var note;
var notes = [];
while ((note = noteGRe.exec(line)) !== null) {
notes.push(note);
}
notes.reverse().forEach(function (note) {
line = line.insertAt(note.index + note[0].length, '');
line = line.insertAt(note.index, '');
});
return line;
}
function shiftKey(note, amount) {
return legalNotes[circularIndex(legalNotes.indexOf(note), amount, N_KEYS)];
}
return {
init: init,
transpose: transpose
}
})(jQuery);