Hour of Code Piano Sample

In this example below you will see how to do a Hour of Code Piano Sample with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by Lathomas42, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright Lathomas42 ©
  • HTML
  • CSS
  • JavaScript
    <!-- ALl we need are a bunch of "button" classes. the CSS script will deal with what they look like-->
<div id="content">
	<div class="button" data-key="e" data-freq="261.6">
		<h3>Q</h3>
    <h5>C4</h5>
	</div>
	<div class="button" data-key="r" data-freq="293.7">
		<h3>W</h3>
    <h5>D4</h5>
	</div>
	<div class="button" data-key="q" data-freq="329.6">
		<h3>E</h3>
    <h5>E4</h5>
	</div>
	<div class="button" data-key="w" data-freq="349.2">
		<h3>R</h3>
    <h5>F4</h5>
	</div>
	<div class="button" data-key="t" data-freq="392">
		<h3>T</h3>
    <h5>G4</h5>
	</div>
  <div class="button" data-key="t" data-freq="440">
		<h3>Y</h3>
    <h5>A4</h5>
	</div>
  <div class="button" data-key="t" data-freq="493.9">
		<h3>U</h3>
    <h5>B4</h5>
	</div>
  <div class="button" data-key="t" data-freq="523.3">
		<h3>I</h3>
    <h5>C5</h5>
	</div>
  <div class="button" data-key="t" data-freq="587.3">
		<h3>O</h3>
    <h5>D5</h5>
	</div>
  <div class="button" data-key="t" data-freq="659.3">
		<h3>P</h3>
    <h5>E5</h5>
	</div>
  <div class="button" data-key="t" data-freq="698.5">
		<h3>&#123</h3>
    <h5>F5</h5>
	</div>
  <div class="button" data-key="t" data-freq="784.0">
		<h3>&#125</h3>
    <h5>G5</h5>
	</div>
  <div class="button" data-key="t" data-freq="880.0">
		<h3>&#124</h3>
    <h5>A5</h5>
	</div>
</div>
<div>
  <center>
  <canvas id='scope' width=400 height=200></canvas>
  </center>
<br>

/*Downloaded from https://www.codeseek.co/Lathomas42/hour-of-code-piano-sample-eBKoGb */
    /* this controls what all of the button classes look like 
Mess around with some of these and see what happens!
*/
.button {
    display: inline-block;
    width: 50px;
    height: 100px;
    background-color: grey;
    border-radius: 5px;
    opacity: 1;
    transition: all 0.2s;
}
/* if the button is also an "active" class 
This code controls what it looks like when it becomes active
*/
.button.active {
    background-color: orange;
    border-radius: 100px;
}


/* This stuff just controls the text position and makes the buttons centered */
#content, #device_info {
    max-width: 1500px;
    margin: 0 auto;
    padding: 10px 0;
}
#content, #key_data {
    margin-top: 0px;
    text-align: center;
}




/*Downloaded from https://www.codeseek.co/Lathomas42/hour-of-code-piano-sample-eBKoGb */
    // this will just allow us to write stuff out to the console later
var log = console.log.bind(console);

// These next two lines create the context, 
// or connection to our speakers / microphone
var AudioContext = AudioContext || webkitAudioContext; // for ios/safari
var context = new AudioContext();
var analyser = context.createAnalyser();

// This will be an array of all the things in the HTML
// Document with the class "button"
var btn = document.getElementsByClassName('button');


//-------------------AUDIO CODE-----------------------
// prepare audio keys
for (var i = 0; i < btn.length; i++) {
    addAudioProperties(btn[i]);
}
// add AudioProperties adds the properties to the button object
function addAudioProperties(object) {
    object.name = object.id;
    object.playing = false;
    object.freq = object.dataset.freq;
    // this adds the play function to the button so that we can call it
    // to play the audio file
    object.play = function() {
            if( !object.playing ){
              // add active to the css class list
              object.classList.add('active');
              object.playing = true;
              // a buffer source delivers us buffers of audio from
              // the computer to fill with audio
              // start playing the audio
              if( object.osc )
                object.osc.stop();
              var osc = context.createOscillator();
              var gainNode = context.createGain();
              // do any editing of the audio here
              osc.frequency.value = object.freq;
              // this osc.type can be:
              //sine square sawtooth triangle
              osc.type = "triangle";
              
              osc.connect(gainNode);
              // connect the sound to the speakers
              gainNode.connect(context.destination);
              gainNode.connect(analyser);
              object.gainNode = gainNode;
              object.osc = osc;
              osc.start();
              // FADE in the audio so we dont get clicks
              object.gainNode.gain.setValueAtTime(.0001, context.currentTime); 
              object.gainNode.gain.exponentialRampToValueAtTime(1.0, context.currentTime + 0.03);
            }
        }
        // add a stop function to the button so we can call it if we need to 
    object.stop = function() {
      // remove active from the css class list
        object.classList.remove('active');
        object.playing = false;
        // Fade out the audio so we dont get clicks
        object.gainNode.gain.setValueAtTime(object.gainNode.gain.value, context.currentTime); 
        object.gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.03);
      // stop this guy later so the fade out can take place
        object.osc.stop( context.currentTime + 0.5);
    }
}
//-----------------END AUDIO CODE---------------------------------

//-----------------Keyboard and Command Hanlding----------------
// add event listener to the document for keydown and keyup so that we can
// intercept Q,W,E,R,T calls
document.addEventListener('keydown', keyController);
document.addEventListener('keyup', keyController);
// qwerty keyboard controls. [q,w,e,r,t]
function keyController(e) {
    if (e.type == "keydown") {
        switch (e.keyCode) {
            case 81: //Q
                // play the audio associated with the button
                btn[0].play();
                break;
            case 87: //W
                // play the audio assosciated with the button
                btn[1].play();
                break;
            case 69: //E
                // play the audio associated with the button
                btn[2].play();
                break;
            case 82: //R
                // play the audio associated with the button
                btn[3].play();
                break;
            case 84: //T
                // play the audio associated with the button
                btn[4].play();
                break;
            case 89: //Y
                // play the audio associated with the button
                btn[5].play();
                break;
            case 85: //U
                // play the audio associated with the button
                btn[6].play();
                break;
            case 73: //I
                // play the audio associated with the button
                btn[7].play();
                break;
            case 79: //O
                // play the audio associated with the button
                btn[8].play();
                break;
            case 80: //P
                // play the audio associated with the button
                btn[9].play();
                break;
            case 219: //curly bracket left
                // play the audio associated with the button
                btn[10].play();
                break;
            case 221: //curly bracket right
                // play the audio associated with the button
                btn[11].play();
                break;
            case 220: //|
                // play the audio associated with the button
                btn[12].play();
                break;
            default:
                //console.log(e.keycode);
        }
    } else if (e.type == "keyup") {
        switch (e.keyCode) {
            case 81: //Q
                btn[0].stop();
                break;
            case 87: //W
                btn[1].stop()
                break;
            case 69: //E
                btn[2].stop();
                break;
            case 82: //R
                btn[3].stop();
                break;
            case 84: //T
                btn[4].stop();
                break;
            case 89: //Y
                // play the audio associated with the button
                btn[5].stop();
                break;
            case 85: //U
                // play the audio associated with the button
                btn[6].stop();
                break;
            case 73: //I
                // play the audio associated with the button
                btn[7].stop();
                break;
            case 79: //O
                // play the audio associated with the button
                btn[8].stop();
                break;
            case 80: //P
                // play the audio associated with the button
                btn[9].stop();
                break;
            case 219: //curly bracket left
                // play the audio associated with the button
                btn[10].stop();
                break;
            case 221: //curly bracket right
                // play the audio associated with the button
                btn[11].stop();
                break;
            case 220: //|
                // play the audio associated with the button
                btn[12].stop();
                break;
            default:
                //console.log(e.keycode);
        }
    }
}
// add mousedown listeners to the buttons
for (var i = 0; i < btn.length; i++) {
    btn[i].addEventListener('mousedown', clickPlayOn);
    btn[i].addEventListener('mouseup', clickPlayOff);
}
// user interaction, mouse click
function clickPlayOn(e) {
    // add active to the css class list
    e.target.classList.add('active');
    e.target.play();
}

function clickPlayOff(e) {
    e.target.stop();
}
//----------------------End of Command and Keyboard handling ----------


//-----------------Begin Oscilloscope code -------------------
analyser.fftSize = 4096;

var scopeCtx = document.getElementById('scope').getContext('2d');
draw();
function draw() {
  
  drawScope(analyser, scopeCtx);
  requestAnimationFrame(draw);
}
function drawScope(analyser, ctx) {
  var width = ctx.canvas.width;
  
  var height = ctx.canvas.height;

  var timeData = new Uint8Array(analyser.frequencyBinCount);
  var scaling = height / 256;
  var risingEdge = 0;
  var edgeThreshold = 5;

  analyser.getByteTimeDomainData(timeData);

  ctx.fillStyle = 'rgba(0, 20, 0, 0.1)';
  ctx.fillRect(0, 0, width, height);

  ctx.lineWidth = 2;
  ctx.strokeStyle = 'rgb(0, 200, 0)';
  ctx.beginPath();

  // No buffer overrun protection
  while (timeData[risingEdge++] - 128 > 0 && risingEdge <= width);
  if (risingEdge >= width) risingEdge = 0;

  while (timeData[risingEdge++] - 128 < edgeThreshold && risingEdge <= width);
  if (risingEdge >= width) risingEdge = 0;
  
  for (var x = risingEdge; x < timeData.length && x - risingEdge < width; x++)
    ctx.lineTo(x - risingEdge, height - timeData[x] * scaling);

  ctx.stroke();
  
}
//-----------------------End Oscilloscope code

// utility functions
function randomRange(min, max) {
    return Math.random() * (max + min) + min;
}

Comments