From e3780f6aea71f55749ce1169b523e8bfb877df53 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Sat, 19 Nov 2022 14:34:47 -0500 Subject: [PATCH] Adding all current customizations to the original forked code. --- csdr/chain/clientaudio.py | 31 +++++-- htdocs/gfx/svg-defs.svg | 2 + htdocs/index.html | 6 ++ htdocs/lib/Demodulator.js | 6 ++ htdocs/map.js | 42 ++++++++- htdocs/openwebrx.js | 127 +++++++++++++++++++++------ owrx/config/defaults.py | 13 +++ owrx/connection.py | 2 + owrx/controllers/settings/general.py | 7 ++ owrx/dsp.py | 20 ++++- owrx/property/validators.py | 1 + owrx/source/__init__.py | 17 ++-- owrx/source/sdrplay.py | 30 +++++-- 13 files changed, 255 insertions(+), 49 deletions(-) diff --git a/csdr/chain/clientaudio.py b/csdr/chain/clientaudio.py index febfd15..a33301a 100644 --- a/csdr/chain/clientaudio.py +++ b/csdr/chain/clientaudio.py @@ -1,15 +1,18 @@ from csdr.chain import Chain -from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, Limit +from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, Limit, NoiseFilter from pycsdr.types import Format class Converter(Chain): - def __init__(self, format: Format, inputRate: int, clientRate: int): + def __init__(self, format: Format, inputRate: int, clientRate: int, nrEnabled: bool, nrThreshold: int): workers = [] + # we only have an audio resampler and noise filter for float ATM, + # so if we need to resample or remove noise, we need to convert + if (inputRate != clientRate or nrEnabled) and format != Format.FLOAT: + workers += [Convert(format, Format.FLOAT)] + if nrEnabled: + workers += [NoiseFilter(nrThreshold)] if inputRate != clientRate: - # we only have an audio resampler for float ATM so if we need to resample, we need to convert - if format != Format.FLOAT: - workers += [Convert(format, Format.FLOAT)] workers += [AudioResampler(inputRate, clientRate), Limit(), Convert(Format.FLOAT, Format.SHORT)] elif format != Format.SHORT: workers += [Convert(format, Format.SHORT)] @@ -17,10 +20,12 @@ class Converter(Chain): class ClientAudioChain(Chain): - def __init__(self, format: Format, inputRate: int, clientRate: int, compression: str): + def __init__(self, format: Format, inputRate: int, clientRate: int, compression: str, nrEnabled: bool, nrThreshold: int): self.format = format self.inputRate = inputRate self.clientRate = clientRate + self.nrEnabled = nrEnabled + self.nrThreshold = nrThreshold workers = [] converter = self._buildConverter() if not converter.empty(): @@ -30,7 +35,7 @@ class ClientAudioChain(Chain): super().__init__(workers) def _buildConverter(self): - return Converter(self.format, self.inputRate, self.clientRate) + return Converter(self.format, self.inputRate, self.clientRate, self.nrEnabled, self.nrThreshold) def _updateConverter(self): converter = self._buildConverter() @@ -70,3 +75,15 @@ class ClientAudioChain(Chain): else: if index >= 0: self.remove(index) + + def setNrEnabled(self, nrEnabled: bool) -> None: + if nrEnabled == self.nrEnabled: + return + self.nrEnabled = nrEnabled + self._updateConverter() + + def setNrThreshold(self, nrThreshold: int) -> None: + if nrThreshold == self.nrThreshold: + return + self.nrThreshold = nrThreshold + self._updateConverter() diff --git a/htdocs/gfx/svg-defs.svg b/htdocs/gfx/svg-defs.svg index 251b051..38336d2 100644 --- a/htdocs/gfx/svg-defs.svg +++ b/htdocs/gfx/svg-defs.svg @@ -24,5 +24,7 @@ + + \ No newline at end of file diff --git a/htdocs/index.html b/htdocs/index.html index 6646783..8e121c5 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -201,6 +201,12 @@ +
+
+ +
+ +
diff --git a/htdocs/lib/Demodulator.js b/htdocs/lib/Demodulator.js index b43adce..79282b6 100644 --- a/htdocs/lib/Demodulator.js +++ b/htdocs/lib/Demodulator.js @@ -81,6 +81,12 @@ Envelope.prototype.draw = function(visible_range){ scale_ctx.fill(); scale_ctx.globalAlpha = 1; scale_ctx.stroke(); + scale_ctx.lineWidth = 1; + scale_ctx.textAlign = "left"; + scale_ctx.fillText(this.demodulator.high_cut.toString(), to_px + env_att_w, env_h2); + scale_ctx.textAlign = "right"; + scale_ctx.fillText(this.demodulator.low_cut.toString(), from_px - env_att_w, env_h2); + scale_ctx.lineWidth = 3; } if (typeof line !== "undefined") // out of screen? { diff --git a/htdocs/map.js b/htdocs/map.js index af879d0..8d72b30 100644 --- a/htdocs/map.js +++ b/htdocs/map.js @@ -37,6 +37,7 @@ $(function(){ var retention_time = 2 * 60 * 60 * 1000; var strokeOpacity = 0.8; var fillOpacity = 0.35; + var callsign_url = null; var colorKeys = {}; var colorScale = chroma.scale(['red', 'blue', 'green']).mode('hsl'); @@ -286,6 +287,9 @@ $(function(){ if ('map_position_retention_time' in config) { retention_time = config.map_position_retention_time * 1000; } + if ('callsign_url' in config) { + callsign_url = config['callsign_url']; + } break; case "update": processUpdates(json.value); @@ -340,6 +344,32 @@ $(function(){ return infowindow; } + var linkifyCallsign = function(callsign) { + if ((callsign_url == null) || (callsign_url == '')) + return callsign; + else + return '' + callsign + ''; + }; + + var distanceKm = function(p1, p2) { + // Earth radius in km + var R = 6371.0; + // Convert degrees to radians + var rlat1 = p1.lat() * (Math.PI/180); + var rlat2 = p2.lat() * (Math.PI/180); + // Compute difference in radians + var difflat = rlat2-rlat1; + var difflon = (p2.lng()-p1.lng()) * (Math.PI/180); + // Compute distance + d = 2 * R * Math.asin(Math.sqrt( + Math.sin(difflat/2) * Math.sin(difflat/2) + + Math.cos(rlat1) * Math.cos(rlat2) * Math.sin(difflon/2) * Math.sin(difflon/2) + )); + return Math.round(d); + } + var infowindow; var showLocatorInfoWindow = function(locator, pos) { var infowindow = getInfoWindow(); @@ -351,13 +381,15 @@ $(function(){ }).sort(function(a, b){ return b.lastseen - a.lastseen; }); + var distance = receiverMarker? + " at " + distanceKm(receiverMarker.position, pos) + " km" : ""; infowindow.setContent( - '

Locator: ' + locator + '

' + + '

Locator: ' + locator + distance + '

' + '
Active Callsigns:
' + '