From 522a92500961bda02431ce824c8def2fe09c65f5 Mon Sep 17 00:00:00 2001 From: Lewis Moten Date: Tue, 14 May 2024 03:09:41 -0400 Subject: [PATCH] move sample interleaving to audio sender/receiver --- AudioReceiver.js | 13 ++++++++++++- AudioSender.js | 22 ++++++++++++++++++++-- StreamManager.js | 9 --------- index.js | 45 +++++++++++++++++++++++++-------------------- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/AudioReceiver.js b/AudioReceiver.js index 13fc39f..ad9d505 100644 --- a/AudioReceiver.js +++ b/AudioReceiver.js @@ -1,6 +1,11 @@ import Dispatcher from "./Dispatcher"; const dispatcher = new Dispatcher('AudioReceiver', ['begin', 'end', 'receive']); +const noEncoding = bits => bits; +let SAMPLE_ENCODING = { + encode: noEncoding, + decode: noEncoding +}; let sampleIntervalIds = []; let SAMPLE_LAST_COLLECTED = 0; @@ -26,6 +31,11 @@ const setTimeoutMilliseconds = (milliseconds) => { signalTimeoutId = window.setTimeout(handleSignalLost, SIGNAL_TIMEOUT_MS, LAST_SIGNAL_BEFORE_TIMEOUT); } } +export const setSampleEncoding = ({ encode, decode } = {}) => { + SAMPLE_ENCODING.encode = encode ?? noEncoding; + SAMPLE_ENCODING.decode = decode ?? noEncoding; +} + const changeConfiguration = ({ fskSets, signalIntervalMs, @@ -154,7 +164,8 @@ function processSample({ signalStart, index }) { const samples = SAMPLES.filter(isSegment); if(samples.length === 0) return; - let bits = evaluateBits(samples); + let bits = SAMPLE_ENCODING.decode(evaluateBits(samples)); + const { start, end } = samples[0]; dispatcher.emit('receive', { signalStart, diff --git a/AudioSender.js b/AudioSender.js index 6c202a8..6cdbdf1 100644 --- a/AudioSender.js +++ b/AudioSender.js @@ -1,6 +1,11 @@ import Dispatcher from "./Dispatcher"; const dispatcher = new Dispatcher('AudioSender', ['begin', 'end', 'send']); +const noEncoding = bits => bits; +let SAMPLE_ENCODING = { + encode: noEncoding, + decode: noEncoding +}; let audioContext; let CHANNELS = []; @@ -15,6 +20,11 @@ let stopOscillatorsTimeoutId; export const addEventListener = dispatcher.addListener; export const removeEventListener = dispatcher.removeListener; +export const setSampleEncoding = ({ encode, decode } = {}) => { + SAMPLE_ENCODING.encode = encode ?? noEncoding; + SAMPLE_ENCODING.decode = decode ?? noEncoding; +} + export const changeConfiguration = ({ channels, destination, @@ -65,9 +75,17 @@ function getOscillators() { return CHANNEL_OSCILLATORS; } export function send(bits, startSeconds) { + const fskPairs = getChannels(); + if(bits.length < fskPairs.length) { + throw new Error(`Expected ${fskPairs.length} bits. Received ${bits.length}.`) + bits.push(...new Array(fskPairs.length - bits.length).fill(0)); + } else if(bits.length > fskPairs.length) { + throw new Error(`Invalid bit length. Expected ${fskPairs.length}, but got ${bits.lengt}`); + } + bits = SAMPLE_ENCODING.encode(bits); const oscillators = getOscillators(); const sentBits = []; - getChannels().forEach((channel, i) => { + fskPairs.forEach((fsk, i) => { // send missing bits as zero const isHigh = bits[i] ?? 0; sentBits.push(isHigh); @@ -75,7 +93,7 @@ export function send(bits, startSeconds) { // already at correct frequency if(oscillator.on === isHigh) return; oscillator.on = isHigh; - const hz = channel[isHigh ? 1 : 0]; + const hz = fsk[isHigh ? 1 : 0]; oscillator.frequency.setValueAtTime(hz, startSeconds); }); diff --git a/StreamManager.js b/StreamManager.js index a5e018e..29d1b78 100644 --- a/StreamManager.js +++ b/StreamManager.js @@ -20,10 +20,6 @@ let BITS_PER_PACKET = 0; let SEGMENTS_PER_PACKET = 0; let BITS_PER_SEGMENT = 0; let STREAM_HEADERS = []; -let SEGMENT_ENCODING = { - encode: bits => bits, - decode: bits => bits -}; let PACKET_ENCODING = { encode: bits => bits, decode: bits => bits @@ -111,10 +107,6 @@ export const changeConfiguration = ({ STREAM_HEADERS = streamHeaders; } const noEncoding = bits => bits; -export const setSegmentEncoding = ({ encode, decode } = {}) => { - SEGMENT_ENCODING.encode = encode ?? noEncoding; - SEGMENT_ENCODING.decode = decode ?? noEncoding; -} export const setPacketEncoding = ({ encode, decode } = {}) => { PACKET_ENCODING.encode = encode ?? noEncoding; PACKET_ENCODING.decode = decode ?? noEncoding; @@ -171,7 +163,6 @@ export const getPacketBits = (packetIndex, defaultBit = 0) => { const packet = BITS[packetIndex] ?? []; for(let segmentIndex = 0; segmentIndex < SEGMENTS_PER_PACKET; segmentIndex++) { let segment = packet[segmentIndex] ?? []; - segment = SEGMENT_ENCODING.decode(segment); for(let bitIndex = 0; bitIndex < BITS_PER_SEGMENT; bitIndex++) { const bit = segment[bitIndex]; bits.push(bit ?? defaultBit); diff --git a/index.js b/index.js index 0f2d6a8..cbebb57 100644 --- a/index.js +++ b/index.js @@ -145,8 +145,6 @@ function handleWindowLoad() { speedPanel.setPacketizationBitsPerSecond(0); speedPanel.setTransferDurationMilliseconds(0); - AudioReceiver.setTimeoutMilliseconds(signalPanel.getTimeoutMilliseconds()); - // Events communicationsPanel.addEventListener('sendSpeakersChange', handleChangeSendSpeakers); @@ -184,9 +182,9 @@ function handleWindowLoad() { packetizationPanel.addEventListener('sizePowerChange', configurationChanged); packetizationPanel.addEventListener('interleavingChange', () => { - StreamManager.setSegmentEncoding( - packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined - ); + const encoding = packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined; + AudioReceiver.setSampleEncoding(encoding); + AudioSender.setSampleEncoding(encoding) configurationChanged(); }); packetizationPanel.addEventListener('errorCorrectionChange', configurationChanged); @@ -196,6 +194,11 @@ function handleWindowLoad() { packetizationPanel.addEventListener('packetCrcChange', configurationChanged); packetizationPanel.addEventListener('sequenceNumberPowerChange', configurationChanged); + AudioReceiver.setTimeoutMilliseconds(signalPanel.getTimeoutMilliseconds()); + const encoding = packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined; + AudioReceiver.setSampleEncoding(encoding); + AudioSender.setSampleEncoding(encoding) + availableFskPairsPanel.addEventListener('change', (event) => { frequencyGraphPanel.setFskPairs(event.selected); configurationChanged(); @@ -477,21 +480,23 @@ function sendBytes(bytes) { const packer = PacketUtils.pack(bits); - AudioSender.beginAt(startSeconds); - // send all packets - for(let i = 0; i < packetCount; i++) { - let packet = packer.getBits(i); - SENT_ENCODED_BITS.push(...packet); - if(packet.length > packetBitCount) { - console.error('Too many bits in the packet. tried to send %s, limited to %s', packet.length, packetBitCount); - AudioSender.stop(); - return; + try { + AudioSender.beginAt(startSeconds); + // send all packets + for(let i = 0; i < packetCount; i++) { + let packet = packer.getBits(i); + if(packet.length > packetBitCount) { + throw new Error(`Too many bits in the packet. tried to send ${packet.length}, limited to ${packetBitCount}`); + } + packet.push(...new Array(packetBitCount - packet.length).fill(0)); + sendPacket(packet, startSeconds + (i * packetDurationSeconds)); } - packet = padArray(packet, packetBitCount, 0); - sendPacket(packet, startSeconds + (i * packetDurationSeconds)); + AudioSender.stopAt(startSeconds + totalDurationSeconds); + } catch (e) { + console.error(e); + AudioSender.stop(); + return; } - AudioSender.stopAt(startSeconds + totalDurationSeconds); - showSentBits(); // start the graph moving again @@ -531,8 +536,8 @@ function sendPacket(bits, packetStartSeconds) { const segmentDurationSeconds = PacketUtils.getSegmentDurationSeconds(); for(let i = 0; i < bitCount; i += channelCount) { let segmentBits = bits.slice(i, i + channelCount); - if(packetizationPanel.getInterleaving()) { - segmentBits = InterleaverEncoding.encode(segmentBits); + if(segmentBits.length !== channelCount) { + segmentBits.push(...new Array(channelCount - segmentBits.length).fill(0)) } const segmentIndex = Math.floor(i / channelCount); var offsetSeconds = segmentIndex * segmentDurationSeconds;