I am trying to write an app that allows a user to write a melody on a virtual keyboard, save the melody and use the rules of counterpoint to generate a bassline using JavaScript. Eventually what I would like to do is allow the user to export their generated melody with midi since it is now available in Google Chrome(http://webaudio.github.io/web-midi-api/).
But for now I am using this code for a virtual piano that I found on Github until I can wrap my mind around how to do this all with midi in the browser...(just getting a working model of how I want the counterpoint to eventually work)
First, I created a dropdown list that lets the user call their selected scale from an XML file which has a list of all the notes in the scale they select. What I want to do next is take those intervals and limit the playable notes on the keyboard to just those notes, and limit the amount of notes playable to 16.
How do I limit the keyboard notes to just the user selected array/post those values selected to the javascript file?
this is what I have so far:
define(["PianoNote"], function(PianoNote){ return function(diretorioSons) { // List notes that the piano has this.notas = ["C3", "C3s", "D3", "D3s", "E3", "F3", "F3s", "G3", "G3s", "A3", "A3s", "B3", "C4", "C4s", "D4", "D4s", "E4", "F4", "F4s", "G4", "G4s", "A4", "A4s", "B4", "C5"]; // Object that will hold objects of type PianoNote this.sons = {}; // Runs through the list of notes adding to this.sons attribute objects PianoNote for (var i = 0; i < this.notas.length; i++) { // This.sons has the following format : // { // Note : PianoNote object , // Note : PianoNote object , // ... // Note : PianoNote object // } this.sons[this.notas[i]] = new PianoNote(diretorioSons + this.notas[i]); } // Piano play function takes the note being played and calls the play function of PianoNote object of the corresponding note this.play = function(nota) { this.sons[nota].play(); }; // Piano stop function this.stop = function(nota) { this.sons[nota].stop(); }; }; }); var mapa = {'Z': "C3", 'S': "C3s", 'X': "D3", 'D': "D3s", 'C': "E3", 'V': "F3", 'G': "F3s", 'B': "G3", 'H': "G3s", 'N': "A3", 'J': "A3s", 'M': "B3", 'Q': "C4", '2': "C4s", 'W': "D4", '3': "D4s", 'E': "E4", 'R': "F4", '5': "F4s", 'T': "G4", '6': "G4s", 'Y': "A4", '7': "A4s", 'U': "B4", 'I': "C5" }; // the var notas stores the notes in the array var notas = []; // add notes to the notes array for (var i in mapa) { notas.push(mapa[i]); } // variable that will receive the Piano object var piano; // function that plays or pauses a note while changing the key color in the Piano // receives as parameters the noa being played / stopped, gone down or released and the element on the piano that will change color function tocarNota(nota, press) { var tecla = document.getElementById(nota); // Check if the key was pressed if (press) { // Checks the type of pressed key if (tecla.className == "key") { // tecla branca tecla.className = "keyPressed"; } else if (tecla.className == "blackKey") { // Black key tecla.className = "blackKeyPressed"; } // Reproduce the note piano.play(nota); } // If the key is released, it returns to original color else { // Checks the type of pressed key if (tecla.className == "keyPressed") { // tecla branca tecla.className = "key"; } else if (tecla.className == "blackKeyPressed") { // tecla preta tecla.className = "blackKey"; } // interrompe a nota piano.stop(nota); } } // Variables and functions are outside the above require in order to be accessed after running the require require(["Piano"], function(Piano){ // Creates a new object type Piano piano = new Piano("sons/"); var tecla; // Runs through the array notes and add the mouse events to the corresponding elements for (var i = 0; i < notas.length; i++) { tecla = document.getElementById(notas[i]); // When the button is pressed with the mouse tecla.addEventListener("mousedown", function(e) { // Before holding the note, it is checked whether the element that triggered the event is the same element that was clicked . // This check is required because the black key is an element in a white key , // So the click the black button would trigger the event the white button if there was no check. // 'This' reference to own tag to which the event is added // ' E.target ' references the element that was clicked if (e.target == this) { tocarNota(this.id, true); } },false); // When the key is released with the mouse tecla.addEventListener("mouseup", function(e) { if (e.target == this) { tocarNota(this.id, false); } },false); // When the mouse is removed from above the element tecla.addEventListener("mouseout", function(e) { if (e.target == this) { tocarNota(this.id, false); } },false); } // Add keyboard events to the entire document // When the button is pressed document.addEventListener("keydown", function(e) { // The pressed key is identified var tecla = String.fromCharCode(e.keyCode).toUpperCase(); var nota; // Check the existence of the key on the map and has not been pressed in combination with alt , ctrl and shift if ((nota = mapa[tecla]) && (!e.altKey) && (!e.ctrlKey) && (!e.shiftKey)) { // There is the execution of the note // While the note is running, ie the keyboard key is pressed, the note will not run again if (!piano.sons[nota].executando) { // Note is executed tocarNota(nota, true); } } }, false); // When the button is released document.addEventListener("keyup", function(e) { // The pressed key is identified var tecla = String.fromCharCode(e.keyCode).toUpperCase(); var nota; // Check the existence of the note on the map and has not been pressed in combination with alt , ctrl and shift if ((nota = mapa[tecla]) && (!e.altKey) && (!e.ctrlKey) && (!e.shiftKey)) { // Note is stopped tocarNota(nota, false); } }, false); }); <!DOCTYPE html > <html lang="en" > <head> <title> counterpoint </title> <meta charset="utf-8" /> <link rel='stylesheet' type='text/css' href='counterpoint.css' /> <link rel="stylesheet" type="text/css" href="style.css" /> <!-- This is where your link tag goes when linking to an external style sheet. --> <script data-main="main.js" src="require.js"></script> <script> function showKEY(str) { if (str=="") { document.getElementById("txtHint0").innerHTML=""; return; } if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else { // code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("txtHint0").innerHTML=xmlhttp.responseText; } } xmlhttp.open("GET","getKEY.php?q="+str,true); xmlhttp.send(); } window.onload = function() { document.getElementById("piano").style.display = "block"; document.getElementById("loader").style.display = "none"; }; </script> <header> </header> </head> <body class="center"></script> <header> <h1>COUNTERPOINT</h1> <form> Select a key: <select name="scale" onchange="showKEY(this.value)" > <option value="">Select a key:</option> <option value="C3">C</option> <option value="D3">D</option> <option value="E3">E</option> <option value="F3">F</option> <option value="G3">G</option> <option value="A3">A</option> <option value="B3">B</option> </select> </form> <div id="txtHint0"><b>Key intervals will be listed here...</b></div> </header> </head> <body class="center"> <div id="loader"> <img src="preloader.gif"> </div> <div id="piano"> <h1 id="brand"></h1> <div id="keyboard"> <div id="C3" class="key"> <div id="C3s" class="blackKey"> </div> </div> <div id="D3" class="key"> <div id="D3s" class="blackKey"> </div> </div> <div id="E3" class="key"> <div class="invisible"> </div> </div> <div id="F3" class="key"> <div id="F3s" class="blackKey"> </div> </div> <div id="G3" class="key"> <div id="G3s" class="blackKey"> </div> </div> <div id="A3" class="key"> <div id="A3s" class="blackKey"> </div> </div> <div id="B3" class="key"> <div class="invisible"> </div> </div> <div id="C4" class="key"> <div id="C4s" class="blackKey"> </div> </div> <div id="D4" class="key"> <div id="D4s" class="blackKey"> </div> </div> <div id="E4" class="key"> <div class="invisible"> </div> </div> <div id="F4" class="key"> <div id="F4s" class="blackKey"> </div> </div> <div id="G4" class="key"> <div id="G4s" class="blackKey"> </div> </div> <div id="A4" class="key"> <div id="A4s" class="blackKey"> </div> </div> <div id="B4" class="key"> <div class="invisible"> </div> </div> <div id="C5" class="key"> <div class="invisible"> </div> </div> </div> </div> <p class="hint">Use your qwerty keyboard to interact with the virtual piano</p> <?php ?> </body> </html> <?php $q=$_GET["q"]; $xmlDoc = new DOMDocument(); $xmlDoc->load("scale.xml"); $x=$xmlDoc->getElementsByTagName('root'); for ($i=0; $i<=$x->length-1; $i++) { //Process only element nodes if ($x->item($i)->nodeType==1) { if ($x->item($i)->childNodes->item(0)->nodeValue == $q) { $y=($x->item($i)->parentNode); } } } $scale=($y->childNodes); for ($i=0;$i<$scale->length;$i++) { //Process only element nodes if ($scale->item($i)->nodeType==1) { echo("<b>" . $scale->item($i)->nodeName . ":</b> "); echo($scale->item($i)->childNodes->item(0)->nodeValue); echo("<br>"); } } echo "<br>Now, lets make your cantus firmus using the intervals from your selection"; echo $scale; ?>
No comments:
Post a Comment