JSFiddle - React, Tailwind, and code Playground
HTML
<button id="coin">?</button>
<span>coin: </count><span id="counter">0</span></span>
<canvas id="canvas"></canvas>
CSS
@import url('https://fonts.googleapis.com/css?family=Press+Start+2P');
#coin {
width: 64px;
height: 64px;
background: #fc9838;
color: #c84c0c;
font-family: 'Press Start 2P', cursive;
font-size: 36px;
font-weight: bold;
text-shadow: 2px 2px 0px #000000;
border-width: 2px;
border-color: #c84c0c #000000 #000000 #c84c0c;
animation: blink 0.9s linear infinite;
}
@keyframes blink {
0% { background: #fc9838 }
49% { background: #fc9838 }
50% { background: #c84c0c }
65% { background: #c84c0c }
66% { background: #7c0800 }
82% { background: #7c0800 }
83% { background: #c84c0c }
100% { background: #c84c0c }
}
#canvas {
display: block;
margin: 10px;
width: 360px;
height: 240px;
background: #333;
}
JavaScript
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext();
var analyser = audioContext.createAnalyser();
function coin(destination, playbackTime) {
var t0 = playbackTime;
var t1 = t0 + tdur(180, 16);
var t2 = t0 + tdur(180, 4) * 3;
var si = mtof(83);
var mi = mtof(88);
var audioContext = destination.context;
var oscillator = audioContext.createOscillator();
var gain = audioContext.createGain();
oscillator.type = "square";
oscillator.frequency.setValueAtTime(si, t0);
oscillator.frequency.setValueAtTime(mi, t1);
oscillator.start(t0);
oscillator.stop(t2);
oscillator.connect(gain);
gain.gain.setValueAtTime(0.5, t0);
gain.gain.setValueAtTime(0.5, t1);
gain.gain.linearRampToValueAtTime(0, t2);
gain.connect(destination);
}
function mtof(midi) {
return 440 * Math.pow(2, (midi - 69) / 12);
}
function tdur(tempo, length) {
return (60 / tempo) * (4 / length);
}
function oneup(destination, playbackTime) {
var t0 = playbackTime;
var ti = tdur(200, 8);
var t2 = t0 + ti * 6;
var freqs = [ 88, 91, 100, 96, 98, 103 ].map(mtof);
var oscillator = audioContext.createOscillator();
var gain = audioContext.createGain();
oscillator.type = "square";
freqs.forEach(function(freq, index) {
oscillator.frequency.setValueAtTime(freq, t0 + ti * index);
});
oscillator.start(t0);
oscillator.stop(t2);
oscillator.connect(gain);
gain.gain.value = 0.5;
gain.connect(destination);
}
// user interface
var counter = 0;
document.getElementById("coin").addEventListener("click", function () {
var destination = analyser;
var playbackTime = audioContext.currentTime;
counter += 5;
if (counter === 10) {
oneup(destination, playbackTime);
counter = 0;
} else {
coin(destination, playbackTime);
}
document.getElementById("counter").textContent = counter;
});
// visualization
(function(analyser) {
var canvas = document.getElementById("canvas");
...