summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--Makefile11
-rw-r--r--src/emscripten_api.rs26
-rw-r--r--src/lib.rs12
-rw-r--r--src/main.rs6
-rw-r--r--web/index.html75
-rw-r--r--web/main.js72
7 files changed, 139 insertions, 65 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f448215..680a811 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["Justin Worthe <justin.worthe@gmail.com>"]
[dependencies]
bencher = "0.1.2"
-[target.'cfg(not(target_os = "emscripten"))'.dependencies]
+[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
portaudio = "0.7.0"
gtk = "0.3.0"
cairo-rs = "0.3.0"
diff --git a/Makefile b/Makefile
index 0f0d7e2..229494b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,17 @@
all: build
build-web:
- cargo build --target=wasm32-unknown-emscripten --release
+ cargo +nightly build --target=wasm32-unknown-unknown --release
mkdir -p target/site
- cp target/wasm32-unknown-emscripten/release/rusty_microphone.js target/site/
- cp target/wasm32-unknown-emscripten/release/deps/*.wasm target/site/
+ cp target/wasm32-unknown-unknown/release/*.wasm target/site/
cp web/* target/site/
build-web-debug:
- cargo build --target=wasm32-unknown-emscripten
+ cargo +nightly build --target=wasm32-unknown-unknown
mkdir -p target/site
- cp target/wasm32-unknown-emscripten/debug/rusty_microphone.js target/site/
- cp target/wasm32-unknown-emscripten/debug/deps/*.wasm target/site/
+ cp target/wasm32-unknown-unknown/debug/*.wasm target/site/
cp web/* target/site/
-
build-desktop:
cargo build --release
diff --git a/src/emscripten_api.rs b/src/emscripten_api.rs
index e296818..c7f980f 100644
--- a/src/emscripten_api.rs
+++ b/src/emscripten_api.rs
@@ -3,11 +3,37 @@ use signal::Signal;
use pitch::Pitch;
use std::os::raw::c_char;
+use std::os::raw::c_void;
+use std::mem;
use std::ffi::CString;
use std::slice;
use std::f32;
#[no_mangle]
+pub extern "C" fn malloc(size: usize) -> *mut c_void {
+ let mut buf = Vec::with_capacity(size);
+ let ptr = buf.as_mut_ptr();
+ mem::forget(buf);
+ return ptr as *mut c_void;
+}
+
+#[no_mangle]
+pub extern "C" fn free(ptr: *mut c_void, cap: usize) {
+ unsafe {
+ // after it's in scope, it can go out of scope in the normal
+ // RAII cleanup.
+ let _buf = Vec::from_raw_parts(ptr, 0, cap);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn free_str(ptr: *mut c_char) {
+ unsafe {
+ let _ = CString::from_raw(ptr);
+ }
+}
+
+#[no_mangle]
pub extern "C" fn find_fundamental_frequency(signal_ptr: *const f32, signal_length: isize, sample_rate: f32) -> f32 {
let signal_slice = unsafe {
&slice::from_raw_parts(signal_ptr, signal_length as usize)
diff --git a/src/lib.rs b/src/lib.rs
index c2b73d1..f778f3b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,18 +3,18 @@ pub mod signal;
pub mod correlation;
pub mod pitch;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
extern crate gtk;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
extern crate cairo;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
pub mod gui;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
extern crate portaudio;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
pub mod audio;
-#[cfg(target_os = "emscripten")]
+#[cfg(target_arch = "wasm32")]
pub mod emscripten_api;
diff --git a/src/main.rs b/src/main.rs
index cfc5629..a05c2f7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
extern crate rusty_microphone;
-#[cfg(not(target_os = "emscripten"))]
+#[cfg(not(target_arch = "wasm32"))]
fn main() {
use rusty_microphone::*;
@@ -11,7 +11,7 @@ fn main() {
}
}
-#[cfg(target_os = "emscripten")]
+#[cfg(target_arch = "wasm32")]
fn main() {
- println!("Hello Emscripten");
+ println!("Hello Wasm");
}
diff --git a/web/index.html b/web/index.html
index d3f6a4b..2d957cc 100644
--- a/web/index.html
+++ b/web/index.html
@@ -1,47 +1,48 @@
+<!DOCTYPE html>
<html>
<head>
+ <meta charset="utf-8" />
<link rel="stylesheet" href="style.css">
- </head>
- <body>
- <h1>Rusty Microphone</h1>
- <div id="loading">
- Loading...
- </div>
- <div id="browser-support-error" class="error" style="display:none;">
- <p>
- It looks like something has gone wrong while loading. The
- most likely reason for this is that this app doesn't support
- your web browser.
- </p>
+ </head>
+ <body>
+ <h1>Rusty Microphone</h1>
+ <div id="loading">
+ Loading...
+ </div>
+ <div id="browser-support-error" class="error" style="display:none;">
+ <p>
+ It looks like something has gone wrong while loading. The
+ most likely reason for this is that this app doesn't support
+ your web browser.
+ </p>
- <p>
- I test with the latest version of Firefox, but it should
- also work with recent versions of Chrome, Microsoft Edge,
- Safari and Opera. If you're running one of these browsers,
- please make sure you've updated to the latest version.
- </p>
+ <p>
+ I test with the latest version of Firefox, but it should
+ also work with recent versions of Chrome, Microsoft Edge,
+ Safari and Opera. If you're running one of these browsers,
+ please make sure you've updated to the latest version.
+ </p>
+ </div>
+ <div id="unexpected-error" class="error" style="display:none;">
+ <p>
+ An unexpected error has occurred. Please try again later.
+ </p>
+ </div>
+ <div id="rusty-microphone" style="display:none;">
+ <p>The current note being played is <span id="pitch-label">unknown</span></p>
+ <div id="pitch-indicator-bar-container">
+ <div id="pitch-indicator-bar"></div>
</div>
- <div id="unexpected-error" class="error" style="display:none;">
- <p>
- An unexpected error has occurred. Please try again later.
- </p>
+ <div id="pitch-indicator-colours">
+ <div id="flat-indicator"></div>
+ <div id="sharp-indicator"></div>
</div>
- <div id="rusty-microphone" style="display:none;">
- <p>The current note being played is <span id="pitch-label">unknown</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="320" height="300"></canvas>
+ <canvas id="oscilloscope" width="320" height="300"></canvas>
- <p>The current framerate is <span id="frame-rate">0</span>FPS</p>
- </div>
+ <p>The current framerate is <span id="frame-rate">0</span>FPS</p>
+ </div>
- <script src="main.js"></script>
- <script src="rusty_microphone.js"></script>
- </body>
+ <script src="main.js"></script>
+ </body>
</html>
diff --git a/web/main.js b/web/main.js
index 02e94fc..8d7fa33 100644
--- a/web/main.js
+++ b/web/main.js
@@ -5,7 +5,30 @@ var Module = {
onRuntimeInitialized: main,
onAbort: onAbort
};
-checkBrowserSupport();
+
+var env = {
+ log2f: Math.log2,
+ roundf: Math.round
+};
+checkBrowserSupport(function() {
+ fetch('rusty_microphone.wasm')
+ .then(response => response.arrayBuffer())
+ .then(bytes => WebAssembly.instantiate(bytes, { env:env }))
+ .then(results => {
+ var mod = results.instance;
+ Module._find_fundamental_frequency = mod.exports.find_fundamental_frequency;
+ Module._hz_to_pitch = mod.exports.hz_to_pitch;
+ Module._hz_to_cents_error = mod.exports.hz_to_cents_error;
+ Module._correlation = mod.exports.correlation;
+
+ Module.memory = mod.exports.memory;
+ Module._malloc = mod.exports.malloc;
+ Module._free = mod.exports.free;
+ Module._free_str = mod.exports.free_str;
+
+ Module.onRuntimeInitialized();
+ });
+});
function onAbort(reason) {
document.getElementById('loading').setAttribute('style', 'display:none');
@@ -24,11 +47,14 @@ function supportsUserMedia() {
typeof AudioContext === "function";
}
-function checkBrowserSupport() {
+function checkBrowserSupport(supportedCallback) {
if (!supportsWasm() || !supportsUserMedia()) {
document.getElementById('loading').setAttribute('style', 'display:none');
document.getElementById('browser-support-error').removeAttribute('style');
- }
+ }
+ else {
+ supportedCallback();
+ }
}
/**
@@ -49,7 +75,7 @@ function jsArrayToF32ArrayPtr(jsArray, callback) {
var nDataBytes = data.length * data.BYTES_PER_ELEMENT;
var dataPtr = Module._malloc(nDataBytes);
- var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, nDataBytes);
+ var dataHeap = new Uint8Array(Module.memory.buffer, dataPtr, nDataBytes);
dataHeap.set(new Uint8Array(data.buffer));
var result = callback(dataPtr, jsArray.length);
@@ -79,12 +105,12 @@ function jsArrayToF32ArrayPtrMutateInPlace(jsArray, mutate) {
var nDataBytes = data.length * data.BYTES_PER_ELEMENT;
var dataPtr = Module._malloc(nDataBytes);
- var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, nDataBytes);
+ var dataHeap = new Uint8Array(Module.memory.buffer, dataPtr, nDataBytes);
dataHeap.set(new Uint8Array(data.buffer));
mutate(dataPtr, jsArray.length);
- var mutatedData = new Float32Array(Module.HEAPU8.buffer, dataPtr, jsArray.length);
+ var mutatedData = new Float32Array(Module.memory.buffer, dataPtr, jsArray.length);
var result = Array.prototype.slice.call(mutatedData);
Module._free(dataPtr);
@@ -112,21 +138,45 @@ function findFundamentalFrequencyNoFree(data, samplingRate) {
if (!dataPtr) {
nDataBytes = data.length * data.BYTES_PER_ELEMENT;
dataPtr = Module._malloc(nDataBytes);
- dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, nDataBytes);
+ dataHeap = new Uint8Array(Module.memory.buffer, dataPtr, nDataBytes);
}
dataHeap.set(new Uint8Array(data.buffer, data.buffer.byteLength - nDataBytes));
return Module._find_fundamental_frequency(dataPtr, data.length, samplingRate);
}
+/**
+ * Takes a pointer to a C-style string (ends in a 0), and interprets it as UTF-8.
+ */
+function copyCStr(ptr) {
+ var iter = ptr;
+
+ // ye olde 0 terminated string
+ function* collectCString() {
+ var memory = new Uint8Array(Module.memory.buffer);
+ while (memory[iter] !== 0) {
+ if (memory[iter] === undefined) {
+ throw new Error("Tried to read undef mem");
+ }
+ yield memory[iter];
+ iter += 1;
+ }
+ };
+
+ var buffer_as_u8 = new Uint8Array(collectCString());
+ var utf8Decoder = new TextDecoder("UTF-8");
+ var buffer_as_utf8 = utf8Decoder.decode(buffer_as_u8);
+ Module._free_str(ptr);
+ return buffer_as_utf8;
+}
+
function hzToCentsError(hz) {
return Module._hz_to_cents_error(hz);
}
-var hzToPitch = function(hz) {
- var wrapped = Module.cwrap('hz_to_pitch', 'string', ['number']);
- hzToPitch = wrapped;
- return wrapped(hz);
+function hzToPitch(hz) {
+ var strPtr = Module._hz_to_pitch(hz);
+ return copyCStr(strPtr);
};
function correlation(data, samplingRate) {