320 lines
8.7 KiB
JavaScript
320 lines
8.7 KiB
JavaScript
const tau = 2*Math.PI
|
|
|
|
let vm = new Vue({
|
|
data(){
|
|
return{
|
|
canvas: null,
|
|
context: null,
|
|
ogglist: [
|
|
og00, og01, og02, og03, og04, og05,
|
|
og06, og07, og08, og09, og10, og11,
|
|
og12, og13, og14, og15, og16, og17,
|
|
og18, og19, og20, og21, og22, og23,
|
|
og24, og25, og26, og27, og28, og29,
|
|
og30, og31, og32, og33, og34, og35,
|
|
],
|
|
bwKeys: [0,1,0,1,0,0,1,0,1,0,1,0],
|
|
whiteKeyWidth: 30,
|
|
whiteKeyHeight: 100,
|
|
blackKeyWidth: 16,
|
|
blackKeyHeight: 60,
|
|
lastKey: 47,
|
|
whiteKeys: {
|
|
0:0 ,2:1,4:2,5:3,7:4,9:5,11:6,
|
|
12:7,14:8,16:9,17:10,19:11,21:12,23:13,
|
|
24:14,26:15,28:16,29:17,31:18,33:19,35:20,
|
|
36:21,38:22,40:23,41:24,43:25,45:26,47:27,
|
|
48:28,50:29,52:30,53:31,55:32,57:33,59:34
|
|
},
|
|
keyColors: [
|
|
0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0
|
|
],
|
|
rootKey: 0,
|
|
domKeyColor: '#000000',
|
|
colScale: "#25465d",
|
|
colInversion: "#ffbaba",
|
|
colChord: "#ef3932",
|
|
colKey: "#e9d2d2",
|
|
colLine: "#e9d2d2",
|
|
scale: [0,2,4,5,7,9,11],
|
|
currentChord: [],
|
|
mode: 0,
|
|
modes: [
|
|
[0,2,4,5,7,9,11], // Ionian
|
|
[0,2,3,5,7,9,10], // Dorian
|
|
[0,1,3,5,7,8,10], // Phrygian
|
|
[0,2,4,6,7,9,11], // Lydian
|
|
[0,2,4,5,7,9,10], // Mixolydian
|
|
[0,2,3,5,7,8,10], // Aeolian
|
|
[0,1,3,5,6,8,10], // Locrian
|
|
[0,2,3,6,7,9,10], // Misheberak
|
|
[0,1,4,5,7,8,10], // Freygish
|
|
[0,2,3,6,7,8,11], // Hungarian Minor
|
|
[0,3,4,6,7,9,10], // Hungarian Major
|
|
[0,1,4,5,6,8,11], // Persian
|
|
[0,2,4,6,8,10] // Whole tone
|
|
],
|
|
modesdegs: [
|
|
['I','ii','iii','IV','V','vi','vii°'], // Ionian
|
|
['i','ii','III','IV','v','vi°','VII'], // Dorian
|
|
['i','II','III','iv','v°','VI','vii'], // Phrygian
|
|
['I','II','iii','iv°','V','vi','vii'], // Lydian
|
|
['I','ii','iii°','IV','v','vi','VII'], // Mixolidian
|
|
['i','ii°','III','iv','v','VI','VII'], // Aeolian
|
|
['i°','II','iii','iv','V','VI','vii'], // Locrian
|
|
['i','II','III','iv°','v','vi°','VII⁺'], // Misheberak
|
|
['I','II','iii°','iv','v°','vi⁺','vi'], // Freygish
|
|
['i','IIb5','III⁺','iv°b3','V','VI','vii'], // Hungarian Minor
|
|
['I','ii°','iii°','iv°','II','vi°','ii'], // Hungarian Major
|
|
['Ib5','II','IIIsus2','iv','Vsus4','VI⁺','vii°b3'], // Persian
|
|
['WH','A','T','E','V','ER','↓?'], // Whole tone
|
|
|
|
],
|
|
baseNoteList: [
|
|
'C','Db','D','Eb','E','F',
|
|
'F#','G','Ab','A','Bb','B'
|
|
],
|
|
noteList: [
|
|
'C','Db','D','Eb','E','F',
|
|
'F#','G','Ab','A','Bb','B'
|
|
],
|
|
noteScale: ['C','D','E','F','G','A','B'],
|
|
flatSharpList: [
|
|
['C','C'] ,['C#','Db'],['D','D'],
|
|
['D#','Eb'],['E','E'] ,['E#','F'],
|
|
['F#','Gb'],['G','G'] ,['G#','Ab'],
|
|
['A','A'],['A#','Bb'] ,['B','Cb']
|
|
],
|
|
flatList: [
|
|
'C','Db','D',
|
|
'Eb','E','F',
|
|
'Gb','G','Ab',
|
|
'A','Bb','Cb'
|
|
],
|
|
sharpList: [
|
|
'C','C#','D',
|
|
'D#','E','E#',
|
|
'F#','G','G#',
|
|
'A','A#','B'
|
|
],
|
|
chords: {
|
|
'M': [0,4,7],
|
|
'M6': [0,4,7,9],
|
|
'M7m': [0,4,7,10],
|
|
'M7M': [0,4,7,11],
|
|
'M9': [0,4,7,10,14],
|
|
'M69': [0,4,7,9,14],
|
|
'Madd2': [0,2,4,7],
|
|
'Madd9': [0,4,7,14],
|
|
'm': [0,3,7],
|
|
'm6': [0,3,7,9],
|
|
'm7m': [0,3,7,10],
|
|
'm7M': [0,3,7,11],
|
|
'm9': [0,3,7,10,14],
|
|
'm69': [0,3,7,9,14],
|
|
'madd2': [0,2,3,7],
|
|
'madd9': [0,3,7,14],
|
|
'sus2': [0,2,7],
|
|
'sus26': [0,2,7,9],
|
|
'sus27': [0,2,7,10],
|
|
'sus27M': [0,2,7,11],
|
|
'sus4': [0,5,7],
|
|
'sus46': [0,5,7,9],
|
|
'sus47': [0,5,7,10],
|
|
'sus47M': [0,5,7,11],
|
|
'dimb3': [0,2,6],
|
|
'dim': [0,3,6],
|
|
'dim7': [0,3,6,9],
|
|
'b5': [0,4,6],
|
|
'aug': [0,4,8],
|
|
'aug7': [0,4,8,10],
|
|
'p4': [0,5],
|
|
'TT': [0,6],
|
|
'p5': [0,7],
|
|
'M7f5': [0,4,6,10],
|
|
'M7s5': [0,4,8,10]
|
|
}
|
|
}
|
|
},
|
|
methods:{
|
|
sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
},
|
|
drawKey(keyNumber) {
|
|
var keyColor = this.bwKeys[keyNumber%12]
|
|
var keyIndex
|
|
var x0, x1, xc
|
|
var circleXOffset, circleYOffset
|
|
var keyHeight
|
|
|
|
this.ctx.beginPath();
|
|
|
|
if (keyColor == 0){
|
|
keyIndex = this.whiteKeys[keyNumber.toString(10)]
|
|
x0 = this.whiteKeyWidth * keyIndex + 2
|
|
x1 = x0 + this.whiteKeyWidth - 4
|
|
keyHeight = this.whiteKeyHeight
|
|
|
|
this.ctx.fillStyle = "#d5d5d5";
|
|
circleYOffset = 85;
|
|
circleXOffset = 13;
|
|
|
|
} else {
|
|
keyIndex = this.whiteKeys[(keyNumber-1).toString(10)]
|
|
x0 = this.whiteKeyWidth * (keyIndex + 1)
|
|
x0 -= (this.blackKeyWidth / 2)
|
|
x1 = x0 + this.blackKeyWidth
|
|
xc = x1 - x0;
|
|
keyHeight = this.blackKeyHeight
|
|
|
|
this.ctx.fillStyle = "#000000";
|
|
circleYOffset = 50;
|
|
circleXOffset = 8;
|
|
}
|
|
|
|
this.ctx.moveTo(x0,0)
|
|
this.ctx.lineTo(x1,0)
|
|
this.ctx.lineTo(x1,keyHeight)
|
|
this.ctx.lineTo(x0,keyHeight)
|
|
this.ctx.closePath();
|
|
this.ctx.fill();
|
|
|
|
if (this.keyColors[keyNumber] != 0) {
|
|
switch (this.keyColors[keyNumber]){
|
|
case (1):
|
|
this.ctx.fillStyle = "#636e96";
|
|
break;
|
|
case (3):
|
|
this.ctx.fillStyle = "#f40000";
|
|
break;
|
|
}
|
|
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(x0+circleXOffset, circleYOffset, 6, 0, tau);
|
|
this.ctx.fill();
|
|
}
|
|
|
|
this.ctx.save();
|
|
|
|
if (this.bwKeys[(keyNumber-1+12)%12] == 1){
|
|
this.drawKey(keyNumber-1)
|
|
}
|
|
},
|
|
drawKeyBoard() {
|
|
var key
|
|
for (key=0;key<=this.lastKey;key++){
|
|
this.drawKey(key)
|
|
}
|
|
},
|
|
drawRoot() {
|
|
this.drawKey(this.rootKey + 12)
|
|
},
|
|
updateScale(clean){
|
|
if (clean == "clean") {
|
|
this.currentChord = [];
|
|
}
|
|
var deg, key
|
|
var scaleMode = this.modes[this.mode]
|
|
rootKey = Number(this.rootKey)
|
|
for (deg=0;deg<7;deg++){
|
|
nDeg = (scaleMode[deg] + rootKey) % 12;
|
|
this.scale[deg] = nDeg;
|
|
}
|
|
this.noteList = this.baseNoteList;
|
|
if (this.scale.includes(6)){
|
|
this.noteList = this.sharpList;
|
|
}
|
|
if (this.scale.includes(10) && (rootKey != 11)){
|
|
this.noteList = this.flatList;
|
|
if (this.scale.includes(3) && this.scale.includes(4)){
|
|
this.noteList[4] = 'Fb';
|
|
}
|
|
}
|
|
|
|
for (deg=0;deg<7;deg++){
|
|
nDeg = (scaleMode[deg] + rootKey) % 12;
|
|
this.noteScale[deg] = this.noteList[nDeg];
|
|
}
|
|
|
|
for (key=0;key<=this.lastKey;key++){
|
|
if (this.currentChord.includes(key-12)){
|
|
this.keyColors[key] = 3
|
|
} else if (this.scale.includes(key%12)){
|
|
this.keyColors[key] = 1
|
|
} else {
|
|
this.keyColors[key] = 0
|
|
}
|
|
}
|
|
this.drawKeyBoard();
|
|
vm.$forceUpdate();
|
|
},
|
|
playChord(root, chString){
|
|
notes = this.chords[chString];
|
|
c = notes.map(n => n + root);
|
|
this.currentChord = c;
|
|
for (n in c) {
|
|
this.ogglist[c[n]].currentTime = 0;
|
|
this.ogglist[c[n]].play()
|
|
}
|
|
this.updateScale();
|
|
},
|
|
getGoodNote(note) {
|
|
return this.noteList[note]
|
|
},
|
|
spicelvl(root, chString){
|
|
notes = this.chords[chString];
|
|
c = notes.map(n => n + root);
|
|
sl = 0;
|
|
for (n in c) {
|
|
if (!(this.scale.includes(c[n]%12))){
|
|
sl = sl + 1;
|
|
}
|
|
}
|
|
return sl;
|
|
},
|
|
spice2Color(root, chString) {
|
|
sl = this.spicelvl(root, chString);
|
|
if (sl == 0) {
|
|
color = "#ef3932";
|
|
} else {
|
|
color = "";
|
|
}
|
|
return color;
|
|
},
|
|
playScale() {
|
|
doSomething = async () => {
|
|
upBreak = false;
|
|
for (n in this.scale){
|
|
await this.sleep(200);
|
|
note = this.scale[n];
|
|
|
|
if (n > 0) {
|
|
if ((note < this.scale[n-1]) || upBreak ) {
|
|
upBreak = true;
|
|
note = note + 12;
|
|
}
|
|
}
|
|
|
|
this.ogglist[note].play();
|
|
}
|
|
await this.sleep(200);
|
|
this.ogglist[this.scale[0] + 12].play();
|
|
|
|
}
|
|
doSomething();
|
|
}
|
|
},
|
|
mounted: function() {
|
|
var vm = this
|
|
vm.canvas = vm.$refs.canvas
|
|
vm.ctx = vm.canvas.getContext("2d");
|
|
vm.ctx.lineWidth = 0;
|
|
this.drawKeyBoard();
|
|
this.updateScale();
|
|
},
|
|
|
|
}).$mount('#app')
|