diff options
author | Justin Worthe <justin@worthe-it.co.za> | 2017-11-05 11:05:22 +0200 |
---|---|---|
committer | Justin Worthe <justin@worthe-it.co.za> | 2017-11-05 11:05:22 +0200 |
commit | dc5081b6a44b576f530955050dd59d6b1bba331f (patch) | |
tree | 61829f8aceaec015ff0e8b7f9a3f5f972dbdc942 /web | |
parent | 1e37661ea154815fe4e0fa421d5be33d29e0a36d (diff) |
Set up web interface to mimic GTK interface
Diffstat (limited to 'web')
-rw-r--r-- | web/index.html | 18 | ||||
-rw-r--r-- | web/main.js | 133 | ||||
-rw-r--r-- | web/style.css | 38 |
3 files changed, 139 insertions, 50 deletions
diff --git a/web/index.html b/web/index.html index 7f18a7c..05857a0 100644 --- a/web/index.html +++ b/web/index.html @@ -2,12 +2,22 @@ <head> <script src="main.js"></script> <script src="rusty_microphone.js"></script> + <link rel="stylesheet" href="style.css"> </head> <body> - <p>The current note being played is <span id="pitch-label"></span></p> - <p>It is <span id="pitch-error-direction"></span> by <span id="pitch-error"></span> cents</p> - <p>The current framerate is <span id="frame-rate"></span></p> + <div id="rusty-microphone"> + <p>The current note being played is <span id="pitch-label"></span></p> + <div id="pitch-indicator-bar-container"> + <div id="pitch-indicator-bar"></div> + </div> + <div id="pitch-indicator-colours"> + <div id="flat-indicator"></div> + <div id="sharp-indicator"></div> + </div> - <canvas id="oscilloscope" width="300" height="300" /> + <canvas id="oscilloscope" width="320" height="300" /> + + <p>The current framerate is <span id="frame-rate"></span>Hz</p> + </div> </body> </html> diff --git a/web/main.js b/web/main.js index 6962493..56aec33 100644 --- a/web/main.js +++ b/web/main.js @@ -76,58 +76,110 @@ function correlation(data) { }); } -function update(signal, sampleRate) { +function update(view, signal, sampleRate, timestamp) { var fundamental = findFundamentalFrequencyNoFree(signal, sampleRate); var pitch = hzToPitch(fundamental); var error = hzToCentsError(fundamental); - document.getElementById('pitch-label').innerHTML = pitch; - if (error > 0) { - document.getElementById('pitch-error-direction').innerHTML = 'sharp'; - document.getElementById('pitch-error').innerHTML = error; - } else { - document.getElementById('pitch-error-direction').innerHTML = 'flat'; - document.getElementById('pitch-error').innerHTML = -error; - } + view.draw(signal, timestamp, pitch, error); } -function draw(dataArray, canvas, canvasCtx) { - // This draw example is currently heavily based on an example - // from MDN: - // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode - var bufferLength = Math.min(dataArray.length, 512); +function initView() { + var canvas = document.getElementById("oscilloscope"); + var canvasCtx = canvas.getContext("2d"); - canvasCtx.fillStyle = 'rgb(200, 200, 200)'; - canvasCtx.fillRect(0, 0, canvas.width, canvas.height); + var frameRateLabel = document.getElementById('frame-rate'); - canvasCtx.lineWidth = 2; - canvasCtx.strokeStyle = 'rgb(0, 0, 0)'; + var pitchLabel = document.getElementById('pitch-label'); - canvasCtx.beginPath(); + var pitchIndicatorBar = document.getElementById('pitch-indicator-bar'); + var flatIndicator = document.getElementById('flat-indicator'); + var sharpIndicator = document.getElementById('sharp-indicator'); + + var lastTimestamp = 0; + var timestampMod = 0; - var sliceWidth = canvas.width * 1.0 / bufferLength; - var x = 0; + function draw(signal, timestamp, pitch, error) { + updateFramerate(timestamp); + updatePitchIndicators(pitch, error); + drawDebugGraph(signal); + } + + function updateFramerate(timestamp) { + timestampMod += 1; + if (timestampMod === 100) { + timestampMod = 0; + var dt = timestamp - lastTimestamp; + lastTimestamp = timestamp; + var framerate = 100000/dt; + frameRateLabel.innerText = framerate.toFixed(2); + } + } - for (var i = 0; i < bufferLength; i++) { - var y = (dataArray[i] * canvas.height / 2) + canvas.height / 2; + function updatePitchIndicators(pitch, error) { + pitchLabel.innerText = pitch; - if (i === 0) { - canvasCtx.moveTo(x, y); + if (isNaN(error)) { + pitchIndicatorBar.setAttribute('style', 'visibility: hidden'); } else { - canvasCtx.lineTo(x, y); - } + var sharpColour; + var flatColour; + + if (error > 0) { + sharpColour = Math.floor(256*error/50); + flatColour = 0; + } else { + sharpColour = 0; + flatColour = Math.floor(-256*error/50); + } + flatIndicator.setAttribute('style', 'background: rgb(0,0,'+flatColour+')'); + sharpIndicator.setAttribute('style', 'background: rgb('+sharpColour+',0,0)'); - x += sliceWidth; + var errorIndicatorPercentage = error+50; + pitchIndicatorBar.setAttribute('style', 'left: ' + errorIndicatorPercentage.toFixed(2) + '%'); + } } + + function drawDebugGraph(signal) { + // This draw example is currently heavily based on an example + // from MDN: + // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode + var bufferLength = Math.min(signal.length, 512); + + canvasCtx.fillStyle = 'rgb(200, 200, 200)'; + canvasCtx.fillRect(0, 0, canvas.width, canvas.height); + + canvasCtx.lineWidth = 2; + canvasCtx.strokeStyle = 'rgb(0, 0, 0)'; + + canvasCtx.beginPath(); + + var sliceWidth = canvas.width * 1.0 / bufferLength; + var x = 0; + + for (var i = 0; i < bufferLength; i++) { + var y = (signal[i] * canvas.height / 2) + canvas.height / 2; + + if (i === 0) { + canvasCtx.moveTo(x, y); + } else { + canvasCtx.lineTo(x, y); + } + + x += sliceWidth; + } + + canvasCtx.stroke(); + }; + + return { + draw: draw + }; +} - canvasCtx.stroke(); -}; function main() { - var canvas = document.getElementById("oscilloscope"); - var canvasCtx = canvas.getContext("2d"); - navigator.mediaDevices.getUserMedia({ audio: true }) .then(function(stream) { var context = new window.AudioContext(); @@ -135,23 +187,12 @@ function main() { var analyser = context.createAnalyser(); input.connect(analyser); - var lastTimestamp = 0; - var timestampMod = 0; + var view = initView(); function analyserNodeCallback(timestamp) { - timestampMod += 1; - if (timestampMod === 100) { - timestampMod = 0; - var dt = timestamp - lastTimestamp; - lastTimestamp = timestamp; - var framerate = 100000/dt; - document.getElementById('frame-rate').innerHTML = framerate.toFixed(2) + 'Hz'; - } - var dataArray = new Float32Array(analyser.fftSize); analyser.getFloatTimeDomainData(dataArray); - update(dataArray, context.sampleRate); - draw(dataArray, canvas, canvasCtx); + update(view, dataArray, context.sampleRate, timestamp); window.requestAnimationFrame(analyserNodeCallback); } diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..77034e9 --- /dev/null +++ b/web/style.css @@ -0,0 +1,38 @@ +* { + box-sizing: border-box; +} + +#rusty-microphone { + max-width: 320px; +} +#pitch-indicator-bar-container { + width: calc(100% - 2px); + height: 30px; + position: relative; +} +#pitch-indicator-bar { + height: 100%; + border: 1px solid black; + width: 0; + position: absolute; + left: 50%; +} + +#pitch-indicator-colours { + width: 100%; + height: 50px; +} + +#flat-indicator { + width: 50%; + height: 100%; + background: blue; + float: left; +} + +#sharp-indicator { + width: 50%; + height: 100%; + background: red; + float: left; +} |