summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2017-11-03 20:35:43 +0200
committerJustin Worthe <justin@worthe-it.co.za>2017-11-03 20:35:43 +0200
commit604f56e2e433d9b941e3054612b5c286120f558a (patch)
tree47f90a0b1f8680905ecaa3129ff8b46f02a06ade /web
parent669987f0ebd01963d0eb52849fd4f16640350232 (diff)
Added a connection to the microphone through the web, calling into Rust
Diffstat (limited to 'web')
-rw-r--r--web/index.html7
-rw-r--r--web/main.js116
2 files changed, 110 insertions, 13 deletions
diff --git a/web/index.html b/web/index.html
index f70f24b..faf637b 100644
--- a/web/index.html
+++ b/web/index.html
@@ -3,5 +3,10 @@
<script src="main.js"></script>
<script src="rusty_microphone.js"></script>
</head>
- <body></body>
+ <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>
+
+ <canvas id="oscilloscope" width="300" height="300" />
+ </body>
</html>
diff --git a/web/main.js b/web/main.js
index ace739f..c7ba24b 100644
--- a/web/main.js
+++ b/web/main.js
@@ -6,7 +6,7 @@ var Module = {
};
function jsArrayToF32ArrayPtr(jsArray, callback) {
- var data = new Float32Array(jsArray);
+ var data = (jsArray instanceof Float32Array) ? jsArray : new Float32Array(jsArray);
var nDataBytes = data.length * data.BYTES_PER_ELEMENT;
var dataPtr = Module._malloc(nDataBytes);
@@ -44,14 +44,29 @@ function findFundamentalFrequency(data, samplingRate) {
});
}
+var dataPtr = null;
+var dataHeap = null;
+function findFundamentalFrequencyNoFree(data, samplingRate) {
+ //assume data is already a Float32Array and its length won't change from call to call
+ if (!dataPtr) {
+ var nDataBytes = data.length * data.BYTES_PER_ELEMENT;
+ dataPtr = Module._malloc(nDataBytes);
+ dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, nDataBytes);
+ }
+ dataHeap.set(new Uint8Array(data.buffer));
+ return Module._find_fundamental_frequency(dataPtr, data.length, samplingRate);
+}
+
+
function hzToCentsError(hz) {
return Module._hz_to_cents_error(hz);
}
-function hzToPitch(hz) {
+var hzToPitch = function(hz) {
var wrapped = Module.cwrap('hz_to_pitch', 'string', ['number']);
+ hzToPitch = wrapped;
return wrapped(hz);
-}
+};
function correlation(data) {
return jsArrayToF32ArrayPtrMutateInPlace(data, function(dataPtr, dataLength) {
@@ -59,15 +74,92 @@ function correlation(data) {
});
}
-function main() {
- var data = [1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0];
- var fundamental = findFundamentalFrequency(data, 44100.0);
- var correlated = correlation(data);
+function update(signal, sampleRate) {
+ 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;
+ }
+}
+
+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 = dataArray.length;
+
+ canvasCtx.fillStyle = 'rgb(200, 200, 200)';
+ canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
- var error = hzToCentsError(450.0);
- var pitch = hzToPitch(450.0);
+ 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 v = dataArray[i] / 128.0;
+ var y = v * canvas.height / 2;
+
+ if (i === 0) {
+ canvasCtx.moveTo(x, y);
+ } else {
+ canvasCtx.lineTo(x, y);
+ }
+
+ x += sliceWidth;
+ }
+
+ canvasCtx.lineTo(canvas.width, canvas.height / 2);
+ canvasCtx.stroke();
+};
+
+function main() {
+ var canvas = document.getElementById("oscilloscope");
+ var canvasCtx = canvas.getContext("2d");
- console.log("Javascript here. Our fundamental frequency according to Rust is " + fundamental + "Hz");
- console.log("The other math shows a pitch of " + pitch + ", and an error of " + error);
- console.log("Correlation of the array is " + correlated);
+ navigator.mediaDevices.getUserMedia({ audio: true })
+ .then(function(stream) {
+ var context = new window.AudioContext();
+ var input = context.createMediaStreamSource(stream);
+ var analyser = context.createAnalyser();
+ input.connect(analyser);
+
+ var lastTimestamp = 0;
+ var timestampMod = 0;
+
+ function analyserNodeCallback(timestamp) {
+ timestampMod += 1;
+ if (timestampMod === 100) {
+ timestampMod = 0;
+ var dt = timestamp - lastTimestamp;
+ lastTimestamp = timestamp;
+ var framerate = 100000/dt;
+ console.log("Framerate is", framerate);
+ }
+
+ var dataArray = new Float32Array(analyser.fftSize);
+ analyser.getFloatTimeDomainData(dataArray);
+ update(dataArray, context.sampleRate);
+ draw(dataArray, canvas, canvasCtx);
+ window.requestAnimationFrame(analyserNodeCallback);
+ }
+
+ window.requestAnimationFrame(analyserNodeCallback);
+ })
+ .catch(function(err) {
+ console.err('Could not get the microphone');
+ console.err(err);
+ });
}