move sample interleaving to audio sender/receiver

This commit is contained in:
Lewis Moten
2024-05-14 03:09:41 -04:00
parent 398eea69b2
commit 522a925009
4 changed files with 57 additions and 32 deletions

View File

@@ -1,6 +1,11 @@
import Dispatcher from "./Dispatcher"; import Dispatcher from "./Dispatcher";
const dispatcher = new Dispatcher('AudioReceiver', ['begin', 'end', 'receive']); const dispatcher = new Dispatcher('AudioReceiver', ['begin', 'end', 'receive']);
const noEncoding = bits => bits;
let SAMPLE_ENCODING = {
encode: noEncoding,
decode: noEncoding
};
let sampleIntervalIds = []; let sampleIntervalIds = [];
let SAMPLE_LAST_COLLECTED = 0; let SAMPLE_LAST_COLLECTED = 0;
@@ -26,6 +31,11 @@ const setTimeoutMilliseconds = (milliseconds) => {
signalTimeoutId = window.setTimeout(handleSignalLost, SIGNAL_TIMEOUT_MS, LAST_SIGNAL_BEFORE_TIMEOUT); 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 = ({ const changeConfiguration = ({
fskSets, fskSets,
signalIntervalMs, signalIntervalMs,
@@ -154,7 +164,8 @@ function processSample({ signalStart, index }) {
const samples = SAMPLES.filter(isSegment); const samples = SAMPLES.filter(isSegment);
if(samples.length === 0) return; if(samples.length === 0) return;
let bits = evaluateBits(samples); let bits = SAMPLE_ENCODING.decode(evaluateBits(samples));
const { start, end } = samples[0]; const { start, end } = samples[0];
dispatcher.emit('receive', { dispatcher.emit('receive', {
signalStart, signalStart,

View File

@@ -1,6 +1,11 @@
import Dispatcher from "./Dispatcher"; import Dispatcher from "./Dispatcher";
const dispatcher = new Dispatcher('AudioSender', ['begin', 'end', 'send']); const dispatcher = new Dispatcher('AudioSender', ['begin', 'end', 'send']);
const noEncoding = bits => bits;
let SAMPLE_ENCODING = {
encode: noEncoding,
decode: noEncoding
};
let audioContext; let audioContext;
let CHANNELS = []; let CHANNELS = [];
@@ -15,6 +20,11 @@ let stopOscillatorsTimeoutId;
export const addEventListener = dispatcher.addListener; export const addEventListener = dispatcher.addListener;
export const removeEventListener = dispatcher.removeListener; export const removeEventListener = dispatcher.removeListener;
export const setSampleEncoding = ({ encode, decode } = {}) => {
SAMPLE_ENCODING.encode = encode ?? noEncoding;
SAMPLE_ENCODING.decode = decode ?? noEncoding;
}
export const changeConfiguration = ({ export const changeConfiguration = ({
channels, channels,
destination, destination,
@@ -65,9 +75,17 @@ function getOscillators() {
return CHANNEL_OSCILLATORS; return CHANNEL_OSCILLATORS;
} }
export function send(bits, startSeconds) { 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 oscillators = getOscillators();
const sentBits = []; const sentBits = [];
getChannels().forEach((channel, i) => { fskPairs.forEach((fsk, i) => {
// send missing bits as zero // send missing bits as zero
const isHigh = bits[i] ?? 0; const isHigh = bits[i] ?? 0;
sentBits.push(isHigh); sentBits.push(isHigh);
@@ -75,7 +93,7 @@ export function send(bits, startSeconds) {
// already at correct frequency // already at correct frequency
if(oscillator.on === isHigh) return; if(oscillator.on === isHigh) return;
oscillator.on = isHigh; oscillator.on = isHigh;
const hz = channel[isHigh ? 1 : 0]; const hz = fsk[isHigh ? 1 : 0];
oscillator.frequency.setValueAtTime(hz, startSeconds); oscillator.frequency.setValueAtTime(hz, startSeconds);
}); });

View File

@@ -20,10 +20,6 @@ let BITS_PER_PACKET = 0;
let SEGMENTS_PER_PACKET = 0; let SEGMENTS_PER_PACKET = 0;
let BITS_PER_SEGMENT = 0; let BITS_PER_SEGMENT = 0;
let STREAM_HEADERS = []; let STREAM_HEADERS = [];
let SEGMENT_ENCODING = {
encode: bits => bits,
decode: bits => bits
};
let PACKET_ENCODING = { let PACKET_ENCODING = {
encode: bits => bits, encode: bits => bits,
decode: bits => bits decode: bits => bits
@@ -111,10 +107,6 @@ export const changeConfiguration = ({
STREAM_HEADERS = streamHeaders; STREAM_HEADERS = streamHeaders;
} }
const noEncoding = bits => bits; const noEncoding = bits => bits;
export const setSegmentEncoding = ({ encode, decode } = {}) => {
SEGMENT_ENCODING.encode = encode ?? noEncoding;
SEGMENT_ENCODING.decode = decode ?? noEncoding;
}
export const setPacketEncoding = ({ encode, decode } = {}) => { export const setPacketEncoding = ({ encode, decode } = {}) => {
PACKET_ENCODING.encode = encode ?? noEncoding; PACKET_ENCODING.encode = encode ?? noEncoding;
PACKET_ENCODING.decode = decode ?? noEncoding; PACKET_ENCODING.decode = decode ?? noEncoding;
@@ -171,7 +163,6 @@ export const getPacketBits = (packetIndex, defaultBit = 0) => {
const packet = BITS[packetIndex] ?? []; const packet = BITS[packetIndex] ?? [];
for(let segmentIndex = 0; segmentIndex < SEGMENTS_PER_PACKET; segmentIndex++) { for(let segmentIndex = 0; segmentIndex < SEGMENTS_PER_PACKET; segmentIndex++) {
let segment = packet[segmentIndex] ?? []; let segment = packet[segmentIndex] ?? [];
segment = SEGMENT_ENCODING.decode(segment);
for(let bitIndex = 0; bitIndex < BITS_PER_SEGMENT; bitIndex++) { for(let bitIndex = 0; bitIndex < BITS_PER_SEGMENT; bitIndex++) {
const bit = segment[bitIndex]; const bit = segment[bitIndex];
bits.push(bit ?? defaultBit); bits.push(bit ?? defaultBit);

View File

@@ -145,8 +145,6 @@ function handleWindowLoad() {
speedPanel.setPacketizationBitsPerSecond(0); speedPanel.setPacketizationBitsPerSecond(0);
speedPanel.setTransferDurationMilliseconds(0); speedPanel.setTransferDurationMilliseconds(0);
AudioReceiver.setTimeoutMilliseconds(signalPanel.getTimeoutMilliseconds());
// Events // Events
communicationsPanel.addEventListener('sendSpeakersChange', handleChangeSendSpeakers); communicationsPanel.addEventListener('sendSpeakersChange', handleChangeSendSpeakers);
@@ -184,9 +182,9 @@ function handleWindowLoad() {
packetizationPanel.addEventListener('sizePowerChange', configurationChanged); packetizationPanel.addEventListener('sizePowerChange', configurationChanged);
packetizationPanel.addEventListener('interleavingChange', () => { packetizationPanel.addEventListener('interleavingChange', () => {
StreamManager.setSegmentEncoding( const encoding = packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined;
packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined AudioReceiver.setSampleEncoding(encoding);
); AudioSender.setSampleEncoding(encoding)
configurationChanged(); configurationChanged();
}); });
packetizationPanel.addEventListener('errorCorrectionChange', configurationChanged); packetizationPanel.addEventListener('errorCorrectionChange', configurationChanged);
@@ -196,6 +194,11 @@ function handleWindowLoad() {
packetizationPanel.addEventListener('packetCrcChange', configurationChanged); packetizationPanel.addEventListener('packetCrcChange', configurationChanged);
packetizationPanel.addEventListener('sequenceNumberPowerChange', 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) => { availableFskPairsPanel.addEventListener('change', (event) => {
frequencyGraphPanel.setFskPairs(event.selected); frequencyGraphPanel.setFskPairs(event.selected);
configurationChanged(); configurationChanged();
@@ -477,21 +480,23 @@ function sendBytes(bytes) {
const packer = PacketUtils.pack(bits); const packer = PacketUtils.pack(bits);
try {
AudioSender.beginAt(startSeconds); AudioSender.beginAt(startSeconds);
// send all packets // send all packets
for(let i = 0; i < packetCount; i++) { for(let i = 0; i < packetCount; i++) {
let packet = packer.getBits(i); let packet = packer.getBits(i);
SENT_ENCODED_BITS.push(...packet);
if(packet.length > packetBitCount) { if(packet.length > packetBitCount) {
console.error('Too many bits in the packet. tried to send %s, limited to %s', packet.length, packetBitCount); throw new Error(`Too many bits in the packet. tried to send ${packet.length}, limited to ${packetBitCount}`);
AudioSender.stop();
return;
} }
packet = padArray(packet, packetBitCount, 0); packet.push(...new Array(packetBitCount - packet.length).fill(0));
sendPacket(packet, startSeconds + (i * packetDurationSeconds)); sendPacket(packet, startSeconds + (i * packetDurationSeconds));
} }
AudioSender.stopAt(startSeconds + totalDurationSeconds); AudioSender.stopAt(startSeconds + totalDurationSeconds);
} catch (e) {
console.error(e);
AudioSender.stop();
return;
}
showSentBits(); showSentBits();
// start the graph moving again // start the graph moving again
@@ -531,8 +536,8 @@ function sendPacket(bits, packetStartSeconds) {
const segmentDurationSeconds = PacketUtils.getSegmentDurationSeconds(); const segmentDurationSeconds = PacketUtils.getSegmentDurationSeconds();
for(let i = 0; i < bitCount; i += channelCount) { for(let i = 0; i < bitCount; i += channelCount) {
let segmentBits = bits.slice(i, i + channelCount); let segmentBits = bits.slice(i, i + channelCount);
if(packetizationPanel.getInterleaving()) { if(segmentBits.length !== channelCount) {
segmentBits = InterleaverEncoding.encode(segmentBits); segmentBits.push(...new Array(channelCount - segmentBits.length).fill(0))
} }
const segmentIndex = Math.floor(i / channelCount); const segmentIndex = Math.floor(i / channelCount);
var offsetSeconds = segmentIndex * segmentDurationSeconds; var offsetSeconds = segmentIndex * segmentDurationSeconds;