summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2017-11-05 11:05:22 +0200
committerJustin Worthe <justin@worthe-it.co.za>2017-11-05 11:05:22 +0200
commitdc5081b6a44b576f530955050dd59d6b1bba331f (patch)
tree61829f8aceaec015ff0e8b7f9a3f5f972dbdc942 /web
parent1e37661ea154815fe4e0fa421d5be33d29e0a36d (diff)
Set up web interface to mimic GTK interface
Diffstat (limited to 'web')
-rw-r--r--web/index.html18
-rw-r--r--web/main.js133
-rw-r--r--web/style.css38
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;
+}