display segment index and sample count for each segment

This commit is contained in:
Lewis Moten
2024-05-05 02:26:39 -04:00
parent 94245049de
commit d69a7aea1a

101
index.js
View File

@@ -15,7 +15,8 @@ var pauseTimeoutId;
var sampleIntervalId;
var TEXT_TO_SEND = "U";
var MAX_BITS_DISPLAYED_ON_GRAPH = 115;
var RANDOM_COUNT = 64;
var MAX_BITS_DISPLAYED_ON_GRAPH = 58;
var SEGMENT_DURATION = 30;
var AMPLITUDE_THRESHOLD_PERCENT = .75;
var AMPLITUDE_THRESHOLD = 160;
@@ -27,6 +28,7 @@ var FREQUENCY_RESOLUTION_MULTIPLIER = 2;
var SMOOTHING_TIME_CONSTANT = 0;
var HAMMING_ERROR_CORRECTION = true;
var LAST_STREAM_STARTED;
var SAMPLE_DELAY_MS = 1;
var frequencyOverTime = [];
var bitStart = [];
@@ -46,7 +48,7 @@ let packetDataByteCount = -1;
function handleWindowLoad() {
const printable = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`-=~!@#$%^&*()_+[]\\{}|;':\",./<>?";
TEXT_TO_SEND = new Array(128).fill(0).map(() => printable[Math.floor(Math.random() * printable.length)]).join('');
TEXT_TO_SEND = new Array(RANDOM_COUNT).fill(0).map(() => printable[Math.floor(Math.random() * printable.length)]).join('');
// grab dom elements
sendButton = document.getElementById('send-button');
@@ -209,7 +211,7 @@ function drawChannels() {
const nyquistFrequency = audioContext.sampleRate / 2;
const frequencySegments = Math.floor(nyquistFrequency / frequencyResolution);
for(let i = 0; i < channelCount; i++) {//xxx
for(let i = 0; i < channelCount; i++) {
const [low, high] = channels[i];
let top = channelHeight * i;
ctx.fillStyle = 'black';
@@ -365,10 +367,15 @@ function sendBits(bits) {
const channel = i % channelCount;
const segment = Math.floor(i / channelCount);
var offset = ((segment * SEGMENT_DURATION)/1000);
var offset2 = (((segment+1) * SEGMENT_DURATION)/1000) - (1/100000);
oscillators[channel].frequency.setValueAtTime(
channels[channel][isHigh ? 1 : 0],
currentTime + offset
);
oscillators[channel].frequency.setValueAtTime(
channels[channel][isHigh ? 1 : 0],
currentTime + offset2
);
}
// start sending our signal
@@ -379,6 +386,7 @@ function sendBits(bits) {
const channel = i % channelCount;
const segment = Math.floor(i / channelCount);
const offset = ((segment * SEGMENT_DURATION) / 1000);
oscillators[channel].frequency.setValueAtTime(0, currentTime + offset);
oscillators[channel].stop(currentTime + offset);
}
@@ -467,6 +475,7 @@ function collectSample() {
} else {
// new bit stream
data.streamStarted = time;
LAST_STREAM_STARTED = time;
// clear last packet
packetReceivedBits.length = 0;
packetDataByteCount = 0;
@@ -554,9 +563,6 @@ function processSegmentReceived(streamStarted, segmentIndex) {
if((sampleDuration / SEGMENT_DURATION) < LAST_SEGMENT_PERCENT) return;
const bitValues = GET_SEGMENT_BITS(streamStarted, segmentIndex);
console.log("%s Received: %s from %s samples", segmentIndex, bitValues.join(''), samples.length);
packetReceivedBits.push(...bitValues);
const encodingRatio = HAMMING_ERROR_CORRECTION ? 7/4 : 1;
@@ -660,14 +666,21 @@ const textExpectorReducer = expected => (all, bit, i, bits) => {
const char = String.fromCharCode(ascii);
const charIndex = Math.floor((i - PACKET_SIZE_BITS) / 8);
if(char !== expected[charIndex]) {
all += '<span class="bit-wrong">' + char + '</span>';
all += '<span class="bit-wrong">' + htmlEncode(printable(char)) + '</span>';
} else {
all += char;
all += htmlEncode(printable(char));
}
}
return all;
}
function printable(text) {
return text.replace(/[\x00-\x1f\x7f-\x9f]/g, '.');
}
function htmlEncode(text) {
const element = document.createElement('div');
element.textContent = text;
return element.innerHTML;
}
function resetGraphData() {
frequencyOverTime.length = 0;
bitStart.length = 0;
@@ -786,6 +799,75 @@ function avgLabel(array) {
if(values.length === 0) return 'N/A';
return (values.reduce((t, v) => t + v, 0) / values.length).toFixed(2)
}
function drawSegmentIndexes(ctx) {
if(!LAST_STREAM_STARTED) return;
const { width, height } = receivedGraph;
const fot = frequencyOverTime.find(fot => fot.streamStarted === LAST_STREAM_STARTED);
const newest = frequencyOverTime[0].time;
const channelCount = frequencyOverTime[0].pairs.length;
let {
streamStarted,
streamEnded = newest
} = fot ?? {
streamStarted: LAST_STREAM_STARTED,
streamEnded: newest
};
if(streamEnded === -1) streamEnded = newest;
let segmentIndex = 0;
ctx.fontSize = 24;
// determine max segments to prevent infinite loop later
let maxBits = ((1 << PACKET_SIZE_BITS) * 8) + PACKET_SIZE_BITS;
if(HAMMING_ERROR_CORRECTION) maxBits *= 7/4;
let maxSegments = Math.ceil(maxBits / channelCount);
// loop through each index
while(true) {
let segmentStart = streamStarted + (segmentIndex * SEGMENT_DURATION);
// if(segmentStart > streamEnded) break; // stream ended
let segmentEnd = segmentStart + SEGMENT_DURATION;
// find where the index is on the graph
const rightX = getTimeX(segmentStart, newest);
const leftX = getTimeX(segmentEnd, newest);
const segmentWidth = rightX - leftX;
if(leftX > width) continue; // too far in past
if(rightX < 0) break; // in the future
// Draw segment index
let text = segmentIndex.toString();
let size = ctx.measureText(text);
let textX = leftX + (segmentWidth / 2) - (size.width / 2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.textBaseline = 'bottom';
ctx.strokeText(text, textX, height);
ctx.fillStyle = segmentStart > streamEnded ? 'grey' : 'white';
ctx.fillText(text, textX, height);
// draw sample count
const sampleCount = frequencyOverTime
.filter(fot =>
fot.streamStarted === streamStarted &&
fot.segmentIndex === segmentIndex
)
.length;
text = sampleCount.toString();
size = ctx.measureText(text);
textX = leftX + (segmentWidth / 2) - (size.width / 2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.textBaseline = 'top';
ctx.strokeText(text, textX, 5);
ctx.fillStyle = 'white';
ctx.fillText(text, textX, 5);
segmentIndex++;
// break out of potential infinite loop
if(segmentIndex >= maxSegments) break;
}
}
function drawBitDurationLines(ctx, color) {
const { width, height } = receivedGraph;
const newest = frequencyOverTime[0].time;
@@ -1048,6 +1130,7 @@ function drawFrequencyData() {
drawFrequencyLineGraph(ctx, high, `hsl(${hue}, 100%, 50%)`, 2, false);
drawFrequencyLineGraph(ctx, low, `hsl(${hue}, 100%, 25%)`, 1, true);
});
drawSegmentIndexes(ctx);
requestAnimationFrame(drawFrequencyData);
}