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')
 |