[29863] | 1 | function AudioSynthView() {
|
---|
| 2 |
|
---|
| 3 | var isMobile = !!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i);
|
---|
| 4 | if(isMobile) { var evtListener = ['touchstart', 'touchend']; } else { var evtListener = ['mousedown', 'mouseup']; }
|
---|
| 5 |
|
---|
| 6 | var __audioSynth = new AudioSynth();
|
---|
| 7 | __audioSynth.setVolume(0.5);
|
---|
| 8 | var __octave = 4;
|
---|
| 9 |
|
---|
| 10 | // Change octave
|
---|
| 11 | var fnChangeOctave = function(x) {
|
---|
| 12 |
|
---|
| 13 | x |= 0;
|
---|
| 14 |
|
---|
| 15 | __octave += x;
|
---|
| 16 |
|
---|
| 17 | __octave = Math.min(5, Math.max(3, __octave));
|
---|
| 18 |
|
---|
| 19 | var octaveName = document.getElementsByName('OCTAVE_LABEL');
|
---|
| 20 | var i = octaveName.length;
|
---|
| 21 | while(i--) {
|
---|
| 22 | var val = parseInt(octaveName[i].getAttribute('value'));
|
---|
| 23 | octaveName[i].innerHTML = (val + __octave);
|
---|
| 24 | }
|
---|
| 25 |
|
---|
| 26 | document.getElementById('OCTAVE_LOWER').innerHTML = __octave-1;
|
---|
| 27 | document.getElementById('OCTAVE_UPPER').innerHTML = __octave+1;
|
---|
| 28 |
|
---|
| 29 | };
|
---|
| 30 |
|
---|
| 31 | // Key bindings, notes to keyCodes.
|
---|
| 32 | var keyboard = {
|
---|
| 33 |
|
---|
| 34 | /* 2 */
|
---|
| 35 | 50: 'C#,-1',
|
---|
| 36 |
|
---|
| 37 | /* 3 */
|
---|
| 38 | 51: 'D#,-1',
|
---|
| 39 |
|
---|
| 40 | /* 5 */
|
---|
| 41 | 53: 'F#,-1',
|
---|
| 42 |
|
---|
| 43 | /* 6 */
|
---|
| 44 | 54: 'G#,-1',
|
---|
| 45 |
|
---|
| 46 | /* 7 */
|
---|
| 47 | 55: 'A#,-1',
|
---|
| 48 |
|
---|
| 49 | /* 9 */
|
---|
| 50 | 57: 'C#,0',
|
---|
| 51 |
|
---|
| 52 | /* 0 */
|
---|
| 53 | 48: 'D#,0',
|
---|
| 54 |
|
---|
| 55 | /* + */
|
---|
| 56 | 187: 'F#,0',
|
---|
| 57 | 61: 'F#,0',
|
---|
| 58 |
|
---|
| 59 | /* Q */
|
---|
| 60 | 81: 'C,-1',
|
---|
| 61 |
|
---|
| 62 | /* W */
|
---|
| 63 | 87: 'D,-1',
|
---|
| 64 |
|
---|
| 65 | /* E */
|
---|
| 66 | 69: 'E,-1',
|
---|
| 67 |
|
---|
| 68 | /* R */
|
---|
| 69 | 82: 'F,-1',
|
---|
| 70 |
|
---|
| 71 | /* T */
|
---|
| 72 | 84: 'G,-1',
|
---|
| 73 |
|
---|
| 74 | /* Y */
|
---|
| 75 | 89: 'A,-1',
|
---|
| 76 |
|
---|
| 77 | /* U */
|
---|
| 78 | 85: 'B,-1',
|
---|
| 79 |
|
---|
| 80 | /* I */
|
---|
| 81 | 73: 'C,0',
|
---|
| 82 |
|
---|
| 83 | /* O */
|
---|
| 84 | 79: 'D,0',
|
---|
| 85 |
|
---|
| 86 | /* P */
|
---|
| 87 | 80: 'E,0',
|
---|
| 88 |
|
---|
| 89 | /* [ */
|
---|
| 90 | 219: 'F,0',
|
---|
| 91 |
|
---|
| 92 | /* ] */
|
---|
| 93 | 221: 'G,0',
|
---|
| 94 |
|
---|
| 95 | /* A */
|
---|
| 96 | 65: 'G#,0',
|
---|
| 97 |
|
---|
| 98 | /* S */
|
---|
| 99 | 83: 'A#,0',
|
---|
| 100 |
|
---|
| 101 | /* F */
|
---|
| 102 | 70: 'C#,1',
|
---|
| 103 |
|
---|
| 104 | /* G */
|
---|
| 105 | 71: 'D#,1',
|
---|
| 106 |
|
---|
| 107 | /* J */
|
---|
| 108 | 74: 'F#,1',
|
---|
| 109 |
|
---|
| 110 | /* K */
|
---|
| 111 | 75: 'G#,1',
|
---|
| 112 |
|
---|
| 113 | /* L */
|
---|
| 114 | 76: 'A#,1',
|
---|
| 115 |
|
---|
| 116 | /* Z */
|
---|
| 117 | 90: 'A,0',
|
---|
| 118 |
|
---|
| 119 | /* X */
|
---|
| 120 | 88: 'B,0',
|
---|
| 121 |
|
---|
| 122 | /* C */
|
---|
| 123 | 67: 'C,1',
|
---|
| 124 |
|
---|
| 125 | /* V */
|
---|
| 126 | 86: 'D,1',
|
---|
| 127 |
|
---|
| 128 | /* B */
|
---|
| 129 | 66: 'E,1',
|
---|
| 130 |
|
---|
| 131 | /* N */
|
---|
| 132 | 78: 'F,1',
|
---|
| 133 |
|
---|
| 134 | /* M */
|
---|
| 135 | 77: 'G,1',
|
---|
| 136 |
|
---|
| 137 | /* , */
|
---|
| 138 | 188: 'A,1',
|
---|
| 139 |
|
---|
| 140 | /* . */
|
---|
| 141 | 190: 'B,1'
|
---|
| 142 |
|
---|
| 143 | };
|
---|
| 144 |
|
---|
| 145 | var reverseLookupText = {};
|
---|
| 146 | var reverseLookup = {};
|
---|
| 147 |
|
---|
| 148 | // Create a reverse lookup table.
|
---|
| 149 | for(var i in keyboard) {
|
---|
| 150 |
|
---|
| 151 | var val;
|
---|
| 152 |
|
---|
| 153 | switch(i|0) {
|
---|
| 154 |
|
---|
| 155 | case 187:
|
---|
| 156 | val = 61;
|
---|
| 157 | break;
|
---|
| 158 |
|
---|
| 159 | case 219:
|
---|
| 160 | val = 91;
|
---|
| 161 | break;
|
---|
| 162 |
|
---|
| 163 | case 221:
|
---|
| 164 | val = 93;
|
---|
| 165 | break;
|
---|
| 166 |
|
---|
| 167 | case 188:
|
---|
| 168 | val = 44;
|
---|
| 169 | break;
|
---|
| 170 |
|
---|
| 171 | case 190:
|
---|
| 172 | val = 46;
|
---|
| 173 | break;
|
---|
| 174 |
|
---|
| 175 | default:
|
---|
| 176 | val = i;
|
---|
| 177 | break;
|
---|
| 178 |
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | reverseLookupText[keyboard[i]] = val;
|
---|
| 182 | reverseLookup[keyboard[i]] = i;
|
---|
| 183 |
|
---|
| 184 | }
|
---|
| 185 |
|
---|
| 186 | // Keys you have pressed down.
|
---|
| 187 | var keysPressed = [];
|
---|
| 188 | var visualKeyboard = null;
|
---|
| 189 | var selectSound = null;
|
---|
| 190 |
|
---|
| 191 | var fnCreateKeyboard = function(keyboardElement) {
|
---|
| 192 | // Generate keyboard
|
---|
| 193 | // This is our main keyboard element! It's populated dynamically based on what you've set above.
|
---|
| 194 | visualKeyboard = document.getElementById('keyboard');
|
---|
| 195 | selectSound = document.getElementById('sound');
|
---|
| 196 |
|
---|
| 197 | var iKeys = 0;
|
---|
| 198 | var iWhite = 0;
|
---|
| 199 | var notes = __audioSynth._notes;
|
---|
| 200 |
|
---|
| 201 | for(var i=-1;i<=1;i++) {
|
---|
| 202 | for(var n in notes) {
|
---|
| 203 | if(n[2]!='b') {
|
---|
| 204 | var thisKey = document.createElement('div');
|
---|
| 205 | if(n.length>1) {
|
---|
| 206 | thisKey.className = 'black key';
|
---|
| 207 | thisKey.style.width = '30px';
|
---|
| 208 | thisKey.style.height = '120px';
|
---|
| 209 | thisKey.style.left = (40 * (iWhite - 1)) + 25 + 'px';
|
---|
| 210 | } else {
|
---|
| 211 | thisKey.className = 'white key';
|
---|
| 212 | thisKey.style.width = '40px';
|
---|
| 213 | thisKey.style.height = '200px';
|
---|
| 214 | thisKey.style.left = 40 * iWhite + 'px';
|
---|
| 215 | iWhite++;
|
---|
| 216 | }
|
---|
| 217 | var label = document.createElement('div');
|
---|
| 218 | label.className = 'label';
|
---|
| 219 | label.innerHTML = '<b>' + String.fromCharCode(reverseLookupText[n + ',' + i]) + '</b>' + '<br /><br />' + n.substr(0,1) +
|
---|
| 220 | '<span name="OCTAVE_LABEL" value="' + i + '">' + (__octave + parseInt(i)) + '</span>' + (n.substr(1,1)?n.substr(1,1):'');
|
---|
| 221 | thisKey.appendChild(label);
|
---|
| 222 | thisKey.setAttribute('ID', 'KEY_' + n + ',' + i);
|
---|
[29888] | 223 | thisKey.addEventListener(evtListener[0], (function(_temp) { return function() {
|
---|
| 224 | console.log("**** bespoke evtListener for mousedown, away to call fnPlayKeyboard()");
|
---|
| 225 | fnPlayKeyboard({keyCode:_temp}); } })(reverseLookup[n + ',' + i]));
|
---|
| 226 |
|
---|
[29863] | 227 | visualKeyboard[n + ',' + i] = thisKey;
|
---|
| 228 | visualKeyboard.appendChild(thisKey);
|
---|
| 229 | iKeys++;
|
---|
| 230 | }
|
---|
| 231 | }
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 | visualKeyboard.style.width = iWhite * 40 + 'px';
|
---|
| 235 |
|
---|
| 236 | window.addEventListener(evtListener[1], function() { n = keysPressed.length; while(n--) { fnRemoveKeyBinding({keyCode:keysPressed[n]}); } });
|
---|
| 237 |
|
---|
| 238 | };
|
---|
| 239 |
|
---|
| 240 | var midiMiddleC = 60;
|
---|
| 241 |
|
---|
| 242 | //var freqOctaveMap = {'C':261.63,'C#':277.18,'D':293.66,'D#':311.13,'E':329.63,'F':346.23,'F#':369.99,'G':392.00,'G#':415.30,'A':440.00,'A#':466.16,'B':493.88});
|
---|
| 243 |
|
---|
| 244 | var midiOctaveMap = {'C':0,'C#':1,'D':2,'D#':3,'E':4,'F':5,'F#':6,'G':7,'G#':8,'A':9,'A#':10,'B':11};
|
---|
| 245 |
|
---|
| 246 | var playedNotePitch;
|
---|
| 247 | var playedMidiPitch;
|
---|
[29883] | 248 |
|
---|
[29863] | 249 | var playedNoteStartTime;
|
---|
[29883] | 250 | var playedNoteStartCurrentTime;
|
---|
| 251 |
|
---|
[29863] | 252 | var playedDuration;
|
---|
| 253 |
|
---|
[29883] | 254 |
|
---|
[29863] | 255 | // Creates our audio player
|
---|
| 256 | var fnPlayNote = function(note, octave) {
|
---|
| 257 |
|
---|
| 258 | //console.log("**** Note started: " + Date.now()/1000.0)
|
---|
| 259 |
|
---|
| 260 | playedNoteStartTime = Date.now();
|
---|
[29883] | 261 | playedNoteStartCurrentTime = mediaPlayer.currentTime;
|
---|
| 262 |
|
---|
[29863] | 263 | playedNotePitch = "note = " + note + ", octave = " + octave;
|
---|
| 264 | playedMidiPitch = midiMiddleC + (12 * (octave-4)) + midiOctaveMap[note];
|
---|
| 265 |
|
---|
| 266 | inTheGroove();
|
---|
| 267 | MIDI.noteOn(0, playedMidiPitch, 50);
|
---|
| 268 |
|
---|
| 269 | //src = __audioSynth.generate(selectSound.value, note, octave, 2);
|
---|
| 270 | //container = new Audio(src);
|
---|
| 271 | //container.addEventListener('ended', function() {
|
---|
| 272 | // container = null;
|
---|
| 273 | //});
|
---|
| 274 | //container.addEventListener('loadeddata', function(e) { e.target.play(); });
|
---|
| 275 | //container.autoplay = false;
|
---|
| 276 | //container.setAttribute('type', 'audio/wav');
|
---|
| 277 | /*document.body.appendChild(container);*/
|
---|
| 278 | //container.load();
|
---|
| 279 | //return container;
|
---|
| 280 | return true;
|
---|
| 281 |
|
---|
| 282 | };
|
---|
| 283 |
|
---|
| 284 | // Detect keypresses, play notes.
|
---|
| 285 |
|
---|
| 286 | var fnPlayKeyboard = function(e) {
|
---|
[29888] | 287 | console.log("***### fnPlayKeyboard() e=" + e); //JSON.stringify(e));
|
---|
[29863] | 288 |
|
---|
[29888] | 289 | // check to see if any modal dialogs are open
|
---|
| 290 | var active_modal_dialogs = $('.ui-widget-overlay:visible');
|
---|
| 291 | if (active_modal_dialogs.length>0) {
|
---|
| 292 | return false;
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 |
|
---|
[29863] | 296 | if (e.ctrlKey) {
|
---|
| 297 | // avoid playing a note if some kind of control-key
|
---|
| 298 | // combination (such a web page reload) is pressed
|
---|
[29867] | 299 | return false;
|
---|
[29863] | 300 | }
|
---|
[29867] | 301 |
|
---|
[29888] | 302 | console.log("**** testing keyboard event key: '" + e.key + "' keycode = " + e.keyCode);
|
---|
| 303 |
|
---|
| 304 | if (e.keyCode == 32) { // <space-bar>
|
---|
[29883] | 305 | togglePlayPause();
|
---|
[29888] | 306 | //e.preventDefault();
|
---|
[29883] | 307 | return false;
|
---|
| 308 | }
|
---|
| 309 |
|
---|
[29867] | 310 | if (e.shiftKey) {
|
---|
| 311 | return fnDrumKeyboard(e);
|
---|
| 312 | }
|
---|
[29863] | 313 |
|
---|
| 314 |
|
---|
| 315 | var i = keysPressed.length;
|
---|
| 316 | while(i--) {
|
---|
| 317 | if(keysPressed[i]==e.keyCode) {
|
---|
| 318 | return false;
|
---|
| 319 | }
|
---|
| 320 | }
|
---|
| 321 | keysPressed.push(e.keyCode);
|
---|
| 322 |
|
---|
| 323 | switch(e.keyCode) {
|
---|
| 324 |
|
---|
| 325 | // left
|
---|
| 326 | case 37:
|
---|
| 327 | fnChangeOctave(-1);
|
---|
| 328 | break;
|
---|
| 329 |
|
---|
| 330 | // right
|
---|
| 331 | case 39:
|
---|
| 332 | fnChangeOctave(1);
|
---|
| 333 | break;
|
---|
| 334 |
|
---|
| 335 | // space
|
---|
| 336 | case 16:
|
---|
| 337 | break;
|
---|
| 338 | fnPlaySong([
|
---|
| 339 | ['E,0', 8],
|
---|
| 340 | ['D,0', 8],
|
---|
| 341 | ['C,0', 2],
|
---|
| 342 | ['C,0', 8],
|
---|
| 343 | ['D,0', 8],
|
---|
| 344 | ['C,0', 8],
|
---|
| 345 | ['E,0', 8],
|
---|
| 346 | ['D,0', 1],
|
---|
| 347 | ['C,0', 8],
|
---|
| 348 | ['D,0', 8],
|
---|
| 349 | ['E,0', 2],
|
---|
| 350 | ['A,0', 8],
|
---|
| 351 | ['G,0', 8],
|
---|
| 352 | ['E,0', 8],
|
---|
| 353 | ['C,0', 8],
|
---|
| 354 | ['D,0', 1],
|
---|
| 355 | ['A,0', 8],
|
---|
| 356 | ['B,0', 8],
|
---|
| 357 | ['C,1', 2],
|
---|
| 358 | ['B,0', 8],
|
---|
| 359 | ['C,1', 8],
|
---|
| 360 | ['D,1', 8],
|
---|
| 361 | ['C,1', 8],
|
---|
| 362 | ['A,0', 1],
|
---|
| 363 | ['G,0', 8],
|
---|
| 364 | ['A,0', 8],
|
---|
| 365 | ['B,0', 2],
|
---|
| 366 | ['C,1', 8],
|
---|
| 367 | ['B,0', 8],
|
---|
| 368 | ['A,0', 8],
|
---|
| 369 | ['G,0', 8],
|
---|
| 370 | ['A,0', 1]
|
---|
| 371 | ]);
|
---|
| 372 | break;
|
---|
| 373 |
|
---|
| 374 | }
|
---|
| 375 |
|
---|
| 376 | if(keyboard[e.keyCode]) {
|
---|
| 377 | if(visualKeyboard[keyboard[e.keyCode]]) {
|
---|
| 378 | visualKeyboard[keyboard[e.keyCode]].style.backgroundColor = '#ff0000';
|
---|
| 379 | visualKeyboard[keyboard[e.keyCode]].style.marginTop = '5px';
|
---|
| 380 | visualKeyboard[keyboard[e.keyCode]].style.boxShadow = 'none';
|
---|
| 381 | }
|
---|
| 382 | var arrPlayNote = keyboard[e.keyCode].split(',');
|
---|
| 383 | var note = arrPlayNote[0];
|
---|
| 384 | var octaveModifier = arrPlayNote[1]|0;
|
---|
| 385 | fnPlayNote(note, __octave + octaveModifier);
|
---|
| 386 | } else {
|
---|
| 387 | return false;
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | }
|
---|
| 391 |
|
---|
| 392 | // Remove key bindings once note is done.
|
---|
| 393 |
|
---|
| 394 | function calcMidiNoteInfo() {
|
---|
| 395 | if (mediaStartPlayTime != null) {
|
---|
| 396 | var playedNoteEndTime = Date.now();
|
---|
| 397 | var relativePlayedNoteStartTime = playedNoteStartTime - mediaStartPlayTime;
|
---|
| 398 | var relativePlayedNoteEndTime = playedNoteEndTime - mediaStartPlayTime;
|
---|
| 399 | playedDuration = (relativePlayedNoteEndTime - relativePlayedNoteStartTime);
|
---|
| 400 |
|
---|
| 401 |
|
---|
| 402 | // console.log("**** " + playedNotePitch + " (midi pitch = " + playedMidiPitch+ ") startTime = ", relativePlayStartTime + ", duration = " + playedDuration);
|
---|
| 403 |
|
---|
| 404 | mediaPlayedNotes[String(mediaStartPlayTime)].push(
|
---|
[29885] | 405 | { 'midiPitch' : playedMidiPitch,
|
---|
| 406 | 'midiNoteOn' : relativePlayedNoteStartTime,
|
---|
| 407 | 'midiNoteOff' : relativePlayedNoteEndTime,
|
---|
[29883] | 408 | 'startCurrentTime' : playedNoteStartCurrentTime,
|
---|
[29885] | 409 | 'duration' : playedDuration,
|
---|
| 410 | 'startPercTime': playedNoteStartCurrentTime/mediaPlayer.duration,
|
---|
| 411 | 'humanReadble' : playedNotePitch }
|
---|
[29863] | 412 | );
|
---|
| 413 |
|
---|
| 414 | }
|
---|
| 415 | }
|
---|
| 416 |
|
---|
| 417 | var fnRemoveKeyBinding = function(e) {
|
---|
| 418 |
|
---|
| 419 | //console.log("**** key up at: " + Date.now())
|
---|
| 420 | // console.log("*** event e = " + JSON.stringify(e));
|
---|
| 421 |
|
---|
| 422 |
|
---|
| 423 | var i = keysPressed.length;
|
---|
| 424 | while(i--) {
|
---|
| 425 | if(keysPressed[i]==e.keyCode) {
|
---|
| 426 | if(visualKeyboard[keyboard[e.keyCode]]) {
|
---|
| 427 |
|
---|
| 428 | delayedMissingTheGroove(500);
|
---|
| 429 |
|
---|
| 430 | MIDI.noteOff(0, playedMidiPitch, 0);
|
---|
[29877] | 431 | if (mediaPlaybackMode == "record") {
|
---|
| 432 | calcMidiNoteInfo();
|
---|
| 433 | }
|
---|
[29863] | 434 |
|
---|
| 435 | visualKeyboard[keyboard[e.keyCode]].style.backgroundColor = '';
|
---|
| 436 | visualKeyboard[keyboard[e.keyCode]].style.marginTop = '';
|
---|
| 437 | visualKeyboard[keyboard[e.keyCode]].style.boxShadow = '';
|
---|
| 438 | }
|
---|
| 439 | keysPressed.splice(i, 1);
|
---|
| 440 | }
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | var fnPlaySong = function(arr) {
|
---|
| 446 |
|
---|
| 447 | if(arr.length>0) {
|
---|
| 448 |
|
---|
| 449 | var noteLen = 1000*(1/parseInt(arr[0][1]));
|
---|
| 450 | if(!(arr[0][0] instanceof Array)) {
|
---|
| 451 | arr[0][0] = [arr[0][0]];
|
---|
| 452 | }
|
---|
| 453 | var i = arr[0][0].length;
|
---|
| 454 | var keys = [];
|
---|
| 455 | while(i--) {
|
---|
| 456 | keys.unshift(reverseLookup[arr[0][0][i]]);
|
---|
[29888] | 457 | console.log("**** In fnPlaySong(), away to call fnPlayKeyboard()");
|
---|
[29863] | 458 | fnPlayKeyboard({keyCode:keys[0]});
|
---|
| 459 | }
|
---|
| 460 | arr.shift();
|
---|
| 461 | setTimeout(function(array, val){ return function() { var i = val.length; while(i--) { fnRemoveKeyBinding({keyCode:val[i]}); } fnPlaySong(array); } }(arr, keys), noteLen);
|
---|
| 462 |
|
---|
| 463 | }
|
---|
| 464 |
|
---|
| 465 | };
|
---|
| 466 |
|
---|
[29867] | 467 | var fnDrumKeyboard = function(e) {
|
---|
| 468 | //console.log("*** drum pressed: " + e.key);
|
---|
| 469 | if (e.key == "C") {
|
---|
| 470 | $('#drum1').trigger("mousedown");
|
---|
| 471 | }
|
---|
[29883] | 472 | else if (e.key == "V") {
|
---|
[29867] | 473 | $('#drum2').trigger("mousedown");
|
---|
| 474 | }
|
---|
[29883] | 475 | else if (e.key == "B") {
|
---|
[29867] | 476 | $('#drum3').trigger("mousedown");
|
---|
| 477 | }
|
---|
[29883] | 478 | else if (e.key == "N") {
|
---|
[29867] | 479 | $('#drum4').trigger("mousedown");
|
---|
| 480 | }
|
---|
[29883] | 481 | else if (e.key == "M") {
|
---|
[29867] | 482 | $('#drum5').trigger("mousedown");
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | e.preventDefault();
|
---|
| 486 | return false;
|
---|
| 487 | }
|
---|
| 488 |
|
---|
| 489 |
|
---|
[29863] | 490 | // Set up global event listeners
|
---|
| 491 |
|
---|
| 492 | window.addEventListener('keydown', fnPlayKeyboard);
|
---|
| 493 | window.addEventListener('keyup', fnRemoveKeyBinding);
|
---|
| 494 | document.getElementById('-_OCTAVE').addEventListener('click', function() { fnChangeOctave(-1); });
|
---|
| 495 | document.getElementById('+_OCTAVE').addEventListener('click', function() { fnChangeOctave(1); });
|
---|
| 496 |
|
---|
| 497 | Object.defineProperty(this, 'draw', {
|
---|
| 498 | value: fnCreateKeyboard
|
---|
| 499 | });
|
---|
| 500 |
|
---|
| 501 | }
|
---|