diff --git a/Panels/FrequencyGraphPanel.js b/Panels/FrequencyGraphPanel.js index cb6f220..4d4ef16 100644 --- a/Panels/FrequencyGraphPanel.js +++ b/Panels/FrequencyGraphPanel.js @@ -9,6 +9,7 @@ class FrequencyGraphPanel extends BasePanel { this.signalStart = performance.now(); this.signalEnd = this.signalStart; this.samples = []; + this.samplesPerGroup = 1; this.duration = 200; this.amplitudeThreshold = 0; this.addButton('toggle', 'Start', 'toggle'); @@ -26,8 +27,14 @@ class FrequencyGraphPanel extends BasePanel { setSignalEnd = milliseconds => { this.signalEnd = milliseconds; } - setSamplingPeriod = (milliseconds) => this.samplingPeriod = milliseconds; - + setSamplingPeriod = (milliseconds) => { + this.samplingPeriod = milliseconds; + if(!this.isRunning()) this.draw(); + } + setSamplePeriodsPerGroup = count => { + this.samplesPerGroup = count; + if(!this.isRunning()) this.draw(); + } setAmplitudeThreshold = value => { this.amplitudeThreshold = value; if(!this.isRunning()) this.draw(); @@ -150,7 +157,6 @@ class FrequencyGraphPanel extends BasePanel { if(!now) now = performance.now(); let lastPeriodStart = now - ((now - this.signalStart) % this.samplingPeriod); let lastTextX = -1000; - ctx.lineWidth = 1; this.lastCountX = -1000; for(let time = lastPeriodStart; time > now - this.duration; time -= this.samplingPeriod) { const end = time + this.samplingPeriod; @@ -161,6 +167,7 @@ class FrequencyGraphPanel extends BasePanel { ctx.moveTo(rightX, 0); ctx.lineTo(rightX, height); ctx.strokeStyle = 'hsla(120, 100%, 100%, 50%)'; + ctx.lineWidth = 1; ctx.stroke(); let samplePeriodWidth = rightX - leftX; @@ -170,7 +177,19 @@ class FrequencyGraphPanel extends BasePanel { if(time >= this.signalStart && (this.signalEnd < this.signalStart || time < this.signalEnd)) { const signalIndex = Math.floor((time - this.signalStart) / this.samplingPeriod); - let text = signalIndex.toLocaleString(); + + const indexInGroup = signalIndex % this.samplesPerGroup; + if(indexInGroup === 0) { + // Line for when group started + ctx.beginPath(); + ctx.moveTo(rightX, 0); + ctx.lineTo(rightX, height); + ctx.strokeStyle = 'hsla(180, 100%, 50%, 50%)'; + ctx.lineWidth = 2; + ctx.stroke(); + } + + let text = indexInGroup.toLocaleString(); let size = ctx.measureText(text); let textX = leftX + (samplePeriodWidth / 2) - (size.width / 2); // far enough from prior text? diff --git a/Panels/SignalPanel.js b/Panels/SignalPanel.js index ff3222e..9cbb18e 100644 --- a/Panels/SignalPanel.js +++ b/Panels/SignalPanel.js @@ -5,8 +5,8 @@ const clamp = (value, min, max) => Math.max(min, Math.min(value, max)); class SignalPanel extends BasePanel { constructor() { super('Signal'); - this.openField('Segment Duration'); - this.addInputNumber('segment-duration', 100, {min: 0, max: 1000, eventName: 'segmentDurationChange'}); + this.openField('Sampling Period'); + this.addInputNumber('segment-duration', 100, {min: 3, max: 1000, eventName: 'segmentDurationChange'}); this.addText('ms'); this.closeField(); @@ -44,13 +44,13 @@ class SignalPanel extends BasePanel { getWaveform = () => this.getValueById('wave-form'); setWaveform = (value) => this.setValueById('wave-form', value); - getSegmentDuration = () => parseInt(this.getValueById('segment-duration')); - setSegmentDuration = value => this.setValueById('segment-duration', value); + getSegmentDurationMilliseconds = () => this.getNumberById('segment-duration'); + setSegmentDurationMilliseconds = value => this.setValueById('segment-duration', value); - getAmplitudeThreshold = () => parseInt(this.getValueById('amplitude-threshold')) / 100; + getAmplitudeThreshold = () => this.getNumberById('amplitude-threshold') / 100; setAmplitudeThreshold = value => this.setValueById('amplitude-threshold', clamp(value * 100, 0, 100)); - getSmoothingTimeConstant = () => parseInt(this.getValueById('smoothing-time-constant')) / 100; + getSmoothingTimeConstant = () => this.getNumberById('smoothing-time-constant') / 100; setSmoothingTimeConstant = value => this.setValueById('smoothing-time-constant', clamp(value * 100, 0, 100)); } diff --git a/index.js b/index.js index 9d387ef..25dac9d 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,7 @@ function handleWindowLoad() { frequencyPanel.setMultiFskPadding(1); signalPanel.setWaveform('triangle'); - signalPanel.setSegmentDuration(30); + signalPanel.setSegmentDurationMilliseconds(30); signalPanel.setAmplitudeThreshold(0.78); signalPanel.setSmoothingTimeConstant(0); signalPanel.setTimeoutMilliseconds(60); @@ -101,7 +101,7 @@ function handleWindowLoad() { availableFskPairsPanel.setFskPairs(frequencyPanel.getFskPairs()); - graphConfigurationPanel.setDurationMilliseconds(signalPanel.getSegmentDuration() * 20); + graphConfigurationPanel.setDurationMilliseconds(signalPanel.getSegmentDurationMilliseconds() * 20); graphConfigurationPanel.setPauseAfterEnd(true); frequencyGraphPanel.setFskPairs(availableFskPairsPanel.getSelectedFskPairs()); @@ -132,8 +132,8 @@ function handleWindowLoad() { }); signalPanel.addEventListener('waveformChange', updateAudioSender); - signalPanel.addEventListener('segmentDurationChange', (event) => { - frequencyGraphPanel.setSamplingPeriod(event.value); + signalPanel.addEventListener('segmentDurationChange', () => { + frequencyGraphPanel.setSamplingPeriod(signalPanel.getSegmentDurationMilliseconds()); configurationChanged(); }); signalPanel.addEventListener('amplitudeThresholdChange', ({value}) => { @@ -244,7 +244,7 @@ function updateAudioReceiver() { fskSets: availableFskPairsPanel.getSelectedFskPairs(), amplitudeThreshold: Math.floor(signalPanel.getAmplitudeThreshold() * 255), analyser: getAnalyser(), - signalIntervalMs: signalPanel.getSegmentDuration(), + signalIntervalMs: signalPanel.getSegmentDurationMilliseconds(), sampleRate: getAudioContext().sampleRate }); } @@ -274,7 +274,7 @@ function updatePacketUtils() { ); const bitsPerSegment = availableFskPairsPanel.getSelectedFskPairs().length; PacketUtils.changeConfiguration({ - segmentDurationMilliseconds: signalPanel.getSegmentDuration(), + segmentDurationMilliseconds: signalPanel.getSegmentDurationMilliseconds(), packetSizeBitCount: packetizationPanel.getSizePower(), dataSizeBitCount: MAXIMUM_PACKETIZATION_SIZE_BITS, dataSizeCrcBitCount: CRC_BIT_COUNT, @@ -323,6 +323,7 @@ function updatePacketStats() { document.getElementById('segment-transfer-duration').innerText = Humanize.durationMilliseconds(PacketUtils.getSegmentDurationMilliseconds()); document.getElementById('data-transfer-duration').innerText = Humanize.durationMilliseconds(PacketUtils.getDataTransferDurationMilliseconds(bitCount)); document.getElementById('segments-per-packet').innerText = PacketUtils.getPacketSegmentCount().toLocaleString(); + frequencyGraphPanel.setSamplePeriodsPerGroup(PacketUtils.getPacketSegmentCount()); document.getElementById('total-segments').innerText = getTotalSegmentCount(bitCount).toLocaleString(); } @@ -929,7 +930,7 @@ function drawChannelData() { // Loop through visible segments const latestSegmentEnded = Math.min(latest, lastStreamEnded); - for(let time = latestSegmentEnded; time > graphEarliest; time -= signalPanel.getSegmentDuration()) { + for(let time = latestSegmentEnded; time > graphEarliest; time -= signalPanel.getSegmentDurationMilliseconds()) { // too far back? if(time < RECEIVED_STREAM_START_MS) break; @@ -1016,7 +1017,7 @@ function drawSegmentBackground( width, height ) { - const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDuration()); + const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDurationMilliseconds()); const hue = 120; let luminance = segmentIndex % 2 === 0 ? 30 : 25; @@ -1037,7 +1038,7 @@ function drawChannelSegmentForeground( expectedBit ) { const channelHeight = height / channelCount; - const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDuration()); + const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDurationMilliseconds()); let fontHeight = Math.min(24, channelHeight, segmentWidth); let top = channelHeight * channelIndex; ctx.font = `${fontHeight}px Arial`; @@ -1077,7 +1078,7 @@ function drawChannelSegmentBackground( if(isSelectedOrOver) luminance += 15; const channelHeight = height / channelCount; - const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDuration()); + const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDurationMilliseconds()); let top = channelHeight * channelIndex; ctx.fillStyle = `hsl(${hue}, 100%, ${luminance}%)`; ctx.fillRect(endX, top, segmentWidth, channelHeight); @@ -1114,7 +1115,7 @@ function drawChannelNumbers(ctx, channelCount, width, height) { const offset = 0; const channels = availableFskPairsPanel.getSelectedFskPairs(); const channelHeight = height / channelCount; - const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDuration()); + const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDurationMilliseconds()); let fontHeight = Math.min(24, channelHeight, segmentWidth); ctx.font = `${fontHeight}px Arial`; ctx.textBaseline = 'middle'; @@ -1317,11 +1318,11 @@ function getChannelAndSegment(e) { }; } - const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDuration()); + const segmentWidth = width / (graphConfigurationPanel.getDurationMilliseconds() / signalPanel.getSegmentDurationMilliseconds()); const latestSegmentEnded = Math.min(latest, lastStreamEnded); - for(let time = latestSegmentEnded; time > graphEarliest; time -= signalPanel.getSegmentDuration()) { + for(let time = latestSegmentEnded; time > graphEarliest; time -= signalPanel.getSegmentDurationMilliseconds()) { // too far back? if(time < RECEIVED_STREAM_START_MS) { return { @@ -1331,11 +1332,11 @@ function getChannelAndSegment(e) { }; // which segment are we looking at? - const segmentIndex = Math.floor(((time - RECEIVED_STREAM_START_MS) / signalPanel.getSegmentDuration())); + const segmentIndex = Math.floor(((time - RECEIVED_STREAM_START_MS) / signalPanel.getSegmentDurationMilliseconds())); // when did the segment begin/end - const segmentStart = RECEIVED_STREAM_START_MS + (segmentIndex * signalPanel.getSegmentDuration()); - const segmentEnd = segmentStart + signalPanel.getSegmentDuration(); + const segmentStart = RECEIVED_STREAM_START_MS + (segmentIndex * signalPanel.getSegmentDurationMilliseconds()); + const segmentEnd = segmentStart + signalPanel.getSegmentDurationMilliseconds(); // where is the segments left x coordinate? const leftX = ((latest - segmentEnd) / graphDuration) * width;