pause on end of data, resume on send
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
Last Bit Percent: <input id="last-bit-percent" type="number" min="0" max="100" value="90">%<br>
|
Last Bit Percent: <input id="last-bit-percent" type="number" min="0" max="100" value="90">%<br>
|
||||||
FFT Size: 2^<input id="fft-size-power-text" type="number" min="5" max="15" value="90"><br>
|
FFT Size: 2^<input id="fft-size-power-text" type="number" min="5" max="15" value="90"><br>
|
||||||
Smoothing Time Constant: <input id="smoothing-time-constant-text" type="number" min="0.00" max="1.00" step="0.01" value="0.00"><br>
|
Smoothing Time Constant: <input id="smoothing-time-constant-text" type="number" min="0.00" max="1.00" step="0.01" value="0.00"><br>
|
||||||
|
Max Samples on Graph: <input id="max-samples-on-graph" type="number" min="100" max="2000"><br>
|
||||||
<input type="text" id="text-to-send">
|
<input type="text" id="text-to-send">
|
||||||
<button id="send-button">Send</button>
|
<button id="send-button">Send</button>
|
||||||
<h2>Sent</h2>
|
<h2>Sent</h2>
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
<h2>Received</h2>
|
<h2>Received</h2>
|
||||||
<textarea id="received-data" rows="10" cols="40"></textarea><br />
|
<textarea id="received-data" rows="10" cols="40"></textarea><br />
|
||||||
Samples Per Bit: <span id="samples-per-bit">0</span><br>
|
Samples Per Bit: <span id="samples-per-bit">0</span><br>
|
||||||
|
Sample Rate: <span id="audio-context-sample-rate">N/A</span> per second.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="received-graph" width="800" height="100"></canvas>
|
<canvas id="received-graph" width="800" height="100"></canvas>
|
||||||
|
|||||||
45
index.js
45
index.js
@@ -10,14 +10,15 @@ var receivedDataTextarea;
|
|||||||
var sentDataTextArea;
|
var sentDataTextArea;
|
||||||
var receivedGraph;
|
var receivedGraph;
|
||||||
var receivedData = [];
|
var receivedData = [];
|
||||||
var MAX_DATA_POINTS = 200;
|
var MAX_DATA_POINTS = 300;
|
||||||
var MAX_DATA = 0;
|
var MAX_DATA = 0;
|
||||||
|
var pauseTimeoutId;
|
||||||
|
|
||||||
// 20 to 20,000 - human
|
// 20 to 20,000 - human
|
||||||
var FREQUENCY_TONE = 18000;
|
var FREQUENCY_TONE = 18000;
|
||||||
var FREQUENCY_HIGH = 400;
|
var FREQUENCY_HIGH = 400;
|
||||||
var FREQUENCY_LOW = 500;
|
var FREQUENCY_LOW = 500;
|
||||||
var FREQUENCY_DURATION = 200;
|
var FREQUENCY_DURATION = 100;
|
||||||
var FREQUENCY_THRESHOLD = 200;
|
var FREQUENCY_THRESHOLD = 200;
|
||||||
var FFT_POWER = 10;
|
var FFT_POWER = 10;
|
||||||
var LAST_BIT_PERCENT = 0.8;
|
var LAST_BIT_PERCENT = 0.8;
|
||||||
@@ -26,6 +27,7 @@ var frequencyOverTime = [];
|
|||||||
var bitStart = [];
|
var bitStart = [];
|
||||||
var samplesPerBit = [];
|
var samplesPerBit = [];
|
||||||
var bitSampleCount = 0;
|
var bitSampleCount = 0;
|
||||||
|
var PAUSE = false;
|
||||||
|
|
||||||
function handleWindowLoad() {
|
function handleWindowLoad() {
|
||||||
// grab dom elements
|
// grab dom elements
|
||||||
@@ -41,6 +43,11 @@ function handleWindowLoad() {
|
|||||||
bitSampleCount = 0;
|
bitSampleCount = 0;
|
||||||
samplesPerBit.length = 0;
|
samplesPerBit.length = 0;
|
||||||
});
|
});
|
||||||
|
document.getElementById('max-samples-on-graph').value= MAX_DATA_POINTS;
|
||||||
|
document.getElementById('max-samples-on-graph').addEventListener('input', (event) => {
|
||||||
|
MAX_DATA_POINTS = parseInt(event.target.value);
|
||||||
|
})
|
||||||
|
document.getElementById('bit-duration-text').value = FREQUENCY_DURATION;
|
||||||
document.getElementById('amplitude-threshold-text').value = FREQUENCY_THRESHOLD;
|
document.getElementById('amplitude-threshold-text').value = FREQUENCY_THRESHOLD;
|
||||||
document.getElementById('frequency-high-text').value = FREQUENCY_HIGH;
|
document.getElementById('frequency-high-text').value = FREQUENCY_HIGH;
|
||||||
document.getElementById('frequency-low-text').value = FREQUENCY_LOW;
|
document.getElementById('frequency-low-text').value = FREQUENCY_LOW;
|
||||||
@@ -69,7 +76,7 @@ function handleWindowLoad() {
|
|||||||
SMOOTHING_TIME_CONSTANT = parseFloat(event.target.value);
|
SMOOTHING_TIME_CONSTANT = parseFloat(event.target.value);
|
||||||
if(analyser) analyser.smoothingTimeConstant = SMOOTHING_TIME_CONSTANT;
|
if(analyser) analyser.smoothingTimeConstant = SMOOTHING_TIME_CONSTANT;
|
||||||
});
|
});
|
||||||
|
document.getElementById('audio-context-sample-rate').innerText = getAudioContext().sampleRate.toLocaleString();
|
||||||
// wire up events
|
// wire up events
|
||||||
sendButton.addEventListener('click', handleSendButtonClick);
|
sendButton.addEventListener('click', handleSendButtonClick);
|
||||||
isListeningCheckbox.addEventListener('click', handleListeningCheckbox);
|
isListeningCheckbox.addEventListener('click', handleListeningCheckbox);
|
||||||
@@ -101,6 +108,11 @@ function sendBits(bits) {
|
|||||||
audioContext.currentTime + offset
|
audioContext.currentTime + offset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
console.log('removing pause');
|
||||||
|
if(PAUSE && isListeningCheckbox.checked) {
|
||||||
|
PAUSE = false;
|
||||||
|
requestAnimationFrame(analyzeAudio);
|
||||||
|
}
|
||||||
oscillator.connect(audioContext.destination);
|
oscillator.connect(audioContext.destination);
|
||||||
oscillator.start();
|
oscillator.start();
|
||||||
window.setTimeout(function() { oscillator.stop(); }, duration);
|
window.setTimeout(function() { oscillator.stop(); }, duration);
|
||||||
@@ -177,7 +189,9 @@ function received(value) {
|
|||||||
let bitStarted;
|
let bitStarted;
|
||||||
let bitHighStrength = [];
|
let bitHighStrength = [];
|
||||||
let bitLowStrength = [];
|
let bitLowStrength = [];
|
||||||
|
let lastBitIndex = 0;
|
||||||
function analyzeAudio() {
|
function analyzeAudio() {
|
||||||
|
if(PAUSE) return;
|
||||||
if(!analyser) return;
|
if(!analyser) return;
|
||||||
if(!microphoneNode) return;
|
if(!microphoneNode) return;
|
||||||
var audioContext = getAudioContext();
|
var audioContext = getAudioContext();
|
||||||
@@ -204,6 +218,7 @@ function analyzeAudio() {
|
|||||||
return frequencyData[i];
|
return frequencyData[i];
|
||||||
}
|
}
|
||||||
const sum = (total, value) => total + value;
|
const sum = (total, value) => total + value;
|
||||||
|
|
||||||
function evaluateBit(highBits, lowBits) {
|
function evaluateBit(highBits, lowBits) {
|
||||||
let highCount = highBits.reduce(
|
let highCount = highBits.reduce(
|
||||||
(count, highAmplitude, i) =>
|
(count, highAmplitude, i) =>
|
||||||
@@ -218,18 +233,22 @@ function evaluateBit(highBits, lowBits) {
|
|||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
if(high || low) {
|
if(high || low) {
|
||||||
if(bitStarted) {
|
if(bitStarted) {
|
||||||
if(now - bitStarted >= FREQUENCY_DURATION) {
|
var totalDuration = now - bitStarted;
|
||||||
|
var bitIndex = Math.floor(totalDuration / FREQUENCY_DURATION)
|
||||||
|
// next bit?
|
||||||
|
if(lastBitIndex !== bitIndex) {
|
||||||
|
lastBitIndex = bitIndex;
|
||||||
samplesPerBit.unshift(bitSampleCount)
|
samplesPerBit.unshift(bitSampleCount)
|
||||||
received(evaluateBit(bitHighStrength, bitLowStrength));
|
received(evaluateBit(bitHighStrength, bitLowStrength));
|
||||||
bitHighStrength.length = 0;
|
bitHighStrength.length = 0;
|
||||||
bitLowStrength.length = 0;
|
bitLowStrength.length = 0;
|
||||||
bitStarted = now;
|
|
||||||
bitStart[0] = true;
|
bitStart[0] = true;
|
||||||
bitSampleCount = 1;
|
bitSampleCount = 1;
|
||||||
} else {
|
} else {
|
||||||
bitSampleCount++;
|
bitSampleCount++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
lastBitIndex = 0;
|
||||||
bitSampleCount = 1;
|
bitSampleCount = 1;
|
||||||
bitStarted = now;
|
bitStarted = now;
|
||||||
bitStart[0] = true;
|
bitStart[0] = true;
|
||||||
@@ -240,15 +259,23 @@ function evaluateBit(highBits, lowBits) {
|
|||||||
bitLowStrength.push(amplitude(FREQUENCY_LOW));
|
bitLowStrength.push(amplitude(FREQUENCY_LOW));
|
||||||
} else {
|
} else {
|
||||||
if(bitStarted) {
|
if(bitStarted) {
|
||||||
// was bit long enough?
|
var bitIndex = Math.floor((bitStarted - now) / FREQUENCY_DURATION);
|
||||||
const duration = now - bitStarted;
|
var startTime = bitStarted + (FREQUENCY_DURATION * bitIndex);
|
||||||
|
var duration = now - startTime;
|
||||||
if(duration >= FREQUENCY_DURATION * LAST_BIT_PERCENT) {
|
if(duration >= FREQUENCY_DURATION * LAST_BIT_PERCENT) {
|
||||||
samplesPerBit.unshift(bitSampleCount)
|
samplesPerBit.unshift(bitSampleCount)
|
||||||
received(evaluateBit(bitHighStrength, bitLowStrength));
|
received(evaluateBit(bitHighStrength, bitLowStrength));
|
||||||
}
|
}
|
||||||
|
lastBitIndex = 0;
|
||||||
bitStarted = undefined;
|
bitStarted = undefined;
|
||||||
bitStart[0] = true;
|
bitStart[0] = true;
|
||||||
received('\n');
|
received('\n');
|
||||||
|
if(!pauseTimeoutId) {
|
||||||
|
pauseTimeoutId = window.setTimeout(() => {
|
||||||
|
PAUSE = true;
|
||||||
|
pauseTimeoutId = undefined;
|
||||||
|
}, FREQUENCY_DURATION * 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(samplesPerBit.length > MAX_DATA_POINTS) {
|
if(samplesPerBit.length > MAX_DATA_POINTS) {
|
||||||
@@ -299,16 +326,16 @@ function drawFrequency(ctx, hz, color) {
|
|||||||
function drawFrequencyData() {
|
function drawFrequencyData() {
|
||||||
const ctx = receivedGraph.getContext('2d');
|
const ctx = receivedGraph.getContext('2d');
|
||||||
const { width, height } = receivedGraph;
|
const { width, height } = receivedGraph;
|
||||||
ctx.clearRect(0, 0, width, height);
|
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.fillRect(0, 0, width, height);
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
const thresholdY = (1 - (FREQUENCY_THRESHOLD/MAX_DATA)) * height;
|
const thresholdY = (1 - (FREQUENCY_THRESHOLD/MAX_DATA)) * height;
|
||||||
ctx.strokeStyle = 'grey';
|
ctx.strokeStyle = 'grey';
|
||||||
|
ctx.beginPath();
|
||||||
ctx.moveTo(0, thresholdY);
|
ctx.moveTo(0, thresholdY);
|
||||||
ctx.lineTo(width, thresholdY);
|
ctx.lineTo(width, thresholdY);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
drawBitStart(ctx, 'grey');
|
drawBitStart(ctx, 'green');
|
||||||
drawFrequency(ctx, FREQUENCY_HIGH, 'red');
|
drawFrequency(ctx, FREQUENCY_HIGH, 'red');
|
||||||
drawFrequency(ctx, FREQUENCY_LOW, 'blue');
|
drawFrequency(ctx, FREQUENCY_LOW, 'blue');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user