Ultrasonic Modem
Uses Web Audio API to emit a FM ultrasonic signal, and demodulates it using a pair of Goertzel filters.
HTML
<p>Microphone permission is required for this demo.</p>
<p>Open your browser's console (ctrl+shift+J for Chrome, ctrl+shift+K for Firefox), and click on the "Pulse" button. It will output an ultrasonic sound through your speakers, which will captured by your microphone, decoded to binary using JavaScript, and logged to the console.</p>
CSS
body {
background-color: #333;
color: #eee;
font-family: Verdana, sans-serif;
}
JavaScript
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
function createGoertzelFilter(context, freq) {
if (typeof freq !== "number") throw new Error("Need frequency!");
var
w = 2*Math.PI * freq / context.sampleRate,
wr = Math.cos(w),
wi = Math.sin(w),
coeff = 2 * wr,
g = context.createScriptProcessor(256, 1, 1);
g.wr = wr;
g.wi = wi;
g.coeff = coeff;
g.onaudioprocess = function(e) {
var
inp = e.inputBuffer.getChannelData(0),
N = inp.length,
coeff = this.coeff,
s1 = 0,
s2 = 0;
for (var n = 0; n < N; n+=2) {
s2 = inp[n] + coeff * s1 - s2;
s1 = inp[n+1] + coeff * s2 - s1;
}
var
XKr = s1 * this.wr - s2,
XKi = s1 * this.wi,
res = (XKr*XKr + XKi*XKi) / N;
this.res = res;
};
return g;
}
var fCutoff = 10000;
var fLow = 11000;
var fHigh =11375;
var dtms = 50;
var context = new AudioContext;
var filter = context.createBiquadFilter();
var gLow = createGoertzelFilter(context, fLow);
var gHigh = createGoertzelFilter(context, fHigh);
filter.type = "highpass";
filter.frequency.value = fCutoff;
navigator.getUserMedia({audio: true, video: false},
function(stream) {
var mic = context.createMediaStreamSource(stream);
mic.connect(filter);
},
(console.warn || console.log).bind(console)
);
filter.connect(gLow);
filter.connect(gHigh);
gLow.connect(context.destination);
gHigh.connect(context.destination);
var osc = context.createOscillator();
osc.frequency.value = 0;
osc.start(0);
osc.connect(context.destination);
function demodValue() {
var val = -1;
var thresh = 3.e-6;
if (gLow.res > thresh || gHigh.res > thresh) {
val = gHigh.res > gLow.res ? 1 : 0;
console.log(val);
...