Compare commits
7 Commits
release-1.
...
opus
Author | SHA1 | Date | |
---|---|---|---|
58c7f8a132 | |||
a779d5d02a | |||
a6f2b6b31a | |||
26440d4e24 | |||
08188527ce | |||
8532d9048e | |||
1771fd55e1 |
@ -1,6 +1,4 @@
|
|||||||
**1.2.1**
|
**unreleased**
|
||||||
- FifiSDR support fixed (pipeline formats now line up correctly)
|
|
||||||
- Added "Device" input for FifiSDR devices for sound card selection
|
|
||||||
|
|
||||||
**1.2.0**
|
**1.2.0**
|
||||||
- Major rewrite of all demodulation components to make use of the new csdr/pycsdr and digiham/pydigiham demodulator
|
- Major rewrite of all demodulation components to make use of the new csdr/pycsdr and digiham/pydigiham demodulator
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from csdr.chain import Chain
|
from csdr.chain import Chain
|
||||||
from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, Limit
|
from pycsdr.modules import AudioResampler, Convert, AdpcmEncoder, OpusEncoder, Limit
|
||||||
from pycsdr.types import Format
|
from pycsdr.types import Format
|
||||||
|
|
||||||
|
|
||||||
@ -27,10 +27,12 @@ class ClientAudioChain(Chain):
|
|||||||
workers += [converter]
|
workers += [converter]
|
||||||
if compression == "adpcm":
|
if compression == "adpcm":
|
||||||
workers += [AdpcmEncoder(sync=True)]
|
workers += [AdpcmEncoder(sync=True)]
|
||||||
|
elif compression == "opus":
|
||||||
|
workers += [OpusEncoder()]
|
||||||
super().__init__(workers)
|
super().__init__(workers)
|
||||||
|
|
||||||
def _buildConverter(self):
|
def _buildConverter(self):
|
||||||
return Converter(self.format, self.inputRate, self.clientRate)
|
return Converter(self.format, self.inputRate, 12000)
|
||||||
|
|
||||||
def _updateConverter(self):
|
def _updateConverter(self):
|
||||||
converter = self._buildConverter()
|
converter = self._buildConverter()
|
||||||
@ -63,10 +65,18 @@ class ClientAudioChain(Chain):
|
|||||||
self._updateConverter()
|
self._updateConverter()
|
||||||
|
|
||||||
def setAudioCompression(self, compression: str) -> None:
|
def setAudioCompression(self, compression: str) -> None:
|
||||||
index = self.indexOf(lambda x: isinstance(x, AdpcmEncoder))
|
index = self.indexOf(lambda x: isinstance(x, AdpcmEncoder) or isinstance(x, OpusEncoder))
|
||||||
|
newEncoder = None
|
||||||
if compression == "adpcm":
|
if compression == "adpcm":
|
||||||
|
newEncoder = AdpcmEncoder(sync=True)
|
||||||
|
elif compression == "opus":
|
||||||
|
newEncoder = OpusEncoder()
|
||||||
|
|
||||||
|
if newEncoder:
|
||||||
if index < 0:
|
if index < 0:
|
||||||
self.append(AdpcmEncoder(sync=True))
|
self.append(newEncoder)
|
||||||
|
else:
|
||||||
|
self.replace(index, newEncoder)
|
||||||
else:
|
else:
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
self.remove(index)
|
self.remove(index)
|
||||||
|
7
debian/changelog
vendored
7
debian/changelog
vendored
@ -1,9 +1,6 @@
|
|||||||
openwebrx (1.2.1) bullseye jammy; urgency=low
|
openwebrx (1.3.0) UNRELEASED; urgency=low
|
||||||
|
|
||||||
* FifiSDR support fixed (pipeline formats now line up correctly)
|
-- Jakob Ketterl <jakob.ketterl@gmx.de> Thu, 16 Jun 2022 21:47:00 +0000
|
||||||
* Added "Device" input for FifiSDR devices for sound card selection
|
|
||||||
|
|
||||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Tue, 20 Sep 2022 16:01:00 +0000
|
|
||||||
|
|
||||||
openwebrx (1.2.0) bullseye jammy; urgency=low
|
openwebrx (1.2.0) bullseye jammy; urgency=low
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ tar xfz $PACKAGE
|
|||||||
|
|
||||||
git clone https://github.com/jancona/hpsdrconnector.git
|
git clone https://github.com/jancona/hpsdrconnector.git
|
||||||
pushd hpsdrconnector
|
pushd hpsdrconnector
|
||||||
git checkout v0.6.1
|
git checkout v0.6.0
|
||||||
/tmp/go/bin/go build
|
/tmp/go/bin/go build
|
||||||
install -m 0755 hpsdrconnector /usr/local/bin
|
install -m 0755 hpsdrconnector /usr/local/bin
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ popd
|
|||||||
rm -rf js8py
|
rm -rf js8py
|
||||||
|
|
||||||
git clone https://github.com/jketterl/csdr.git
|
git clone https://github.com/jketterl/csdr.git
|
||||||
cmakebuild csdr 0.18.1
|
cmakebuild csdr 0.18.0
|
||||||
|
|
||||||
git clone https://github.com/jketterl/pycsdr.git
|
git clone https://github.com/jketterl/pycsdr.git
|
||||||
cd pycsdr
|
cd pycsdr
|
||||||
git checkout 0.18.1
|
git checkout 0.18.0
|
||||||
./setup.py install install_headers
|
./setup.py install install_headers
|
||||||
cd ..
|
cd ..
|
||||||
rm -rf pycsdr
|
rm -rf pycsdr
|
||||||
|
@ -55,6 +55,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="openwebrx-panels-container">
|
<div id="openwebrx-panels-container">
|
||||||
<div id="openwebrx-panels-container-left">
|
<div id="openwebrx-panels-container-left">
|
||||||
|
<div class="openwebrx-panel" data-panel-name="client-under-devel" style="width: 245px; background-color: Red;">
|
||||||
|
<span style="font-size: 15pt; font-weight: bold;">Under construction</span>
|
||||||
|
<br />We're working on the code right now, so the application might fail.
|
||||||
|
</div>
|
||||||
<div class="openwebrx-panel" id="openwebrx-panel-digimodes" style="display: none; width: 619px;" data-panel-name="digimodes">
|
<div class="openwebrx-panel" id="openwebrx-panel-digimodes" style="display: none; width: 619px;" data-panel-name="digimodes">
|
||||||
<div id="openwebrx-digimode-canvas-container">
|
<div id="openwebrx-digimode-canvas-container">
|
||||||
<div id="openwebrx-digimode-select-channel"></div>
|
<div id="openwebrx-digimode-select-channel"></div>
|
||||||
|
@ -21,7 +21,15 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
|||||||
me._start();
|
me._start();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.audioCodec = new ImaAdpcmCodec();
|
var onAudio = function(audioData) {
|
||||||
|
me.playbackAudio(audioData);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.audioCodecs = {
|
||||||
|
"adpcm": new ImaAdpcmCodec(onAudio),
|
||||||
|
"opus": new OpusCodec(onAudio)
|
||||||
|
};
|
||||||
|
|
||||||
this.compression = 'none';
|
this.compression = 'none';
|
||||||
|
|
||||||
this.setupResampling();
|
this.setupResampling();
|
||||||
@ -279,24 +287,26 @@ AudioEngine.prototype.getSampleRate = function() {
|
|||||||
AudioEngine.prototype.processAudio = function(data, resampler) {
|
AudioEngine.prototype.processAudio = function(data, resampler) {
|
||||||
if (!this.audioNode) return;
|
if (!this.audioNode) return;
|
||||||
this.audioBytes.add(data.byteLength);
|
this.audioBytes.add(data.byteLength);
|
||||||
var buffer;
|
|
||||||
if (this.compression === "adpcm") {
|
if (this.compression !== "none") {
|
||||||
//resampling & ADPCM
|
this.audioCodecs[this.compression].decodeAsync(new Uint8Array(data));
|
||||||
buffer = this.audioCodec.decodeWithSync(new Uint8Array(data));
|
|
||||||
} else {
|
} else {
|
||||||
buffer = new Int16Array(data);
|
this.playbackAudio(new Int16Array(data));
|
||||||
}
|
}
|
||||||
buffer = resampler.process(buffer);
|
}
|
||||||
|
|
||||||
|
AudioEngine.prototype.playbackAudio = function(audioData) {
|
||||||
|
//var buffer = this.resampler.process(audioData);
|
||||||
if (this.audioNode.port) {
|
if (this.audioNode.port) {
|
||||||
// AudioWorklets supported
|
// AudioWorklets supported
|
||||||
this.audioNode.port.postMessage(buffer);
|
this.audioNode.port.postMessage(audioData);
|
||||||
} else {
|
} else {
|
||||||
// silently drop excess samples
|
// silently drop excess samples
|
||||||
if (this.getBuffersize() + buffer.length <= this.maxBufferSize) {
|
if (this.getBuffersize() + buffer.length <= this.maxBufferSize) {
|
||||||
this.audioBuffers.push(buffer);
|
this.audioBuffers.push(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
AudioEngine.prototype.pushAudio = function(data) {
|
AudioEngine.prototype.pushAudio = function(data) {
|
||||||
this.processAudio(data, this.resampler);
|
this.processAudio(data, this.resampler);
|
||||||
@ -320,8 +330,9 @@ AudioEngine.prototype.getBuffersize = function() {
|
|||||||
return this.audioBuffers.map(function(b){ return b.length; }).reduce(function(a, b){ return a + b; }, 0);
|
return this.audioBuffers.map(function(b){ return b.length; }).reduce(function(a, b){ return a + b; }, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
function ImaAdpcmCodec() {
|
function ImaAdpcmCodec(callback) {
|
||||||
this.reset();
|
this.reset();
|
||||||
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImaAdpcmCodec.prototype.reset = function() {
|
ImaAdpcmCodec.prototype.reset = function() {
|
||||||
@ -357,7 +368,7 @@ ImaAdpcmCodec.prototype.decode = function(data) {
|
|||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
ImaAdpcmCodec.prototype.decodeAsync = function(data, callback) {
|
||||||
var output = new Int16Array(data.length * 2);
|
var output = new Int16Array(data.length * 2);
|
||||||
var index = this.skip;
|
var index = this.skip;
|
||||||
var oi = 0;
|
var oi = 0;
|
||||||
@ -391,7 +402,7 @@ ImaAdpcmCodec.prototype.decodeWithSync = function(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.skip = index - data.length;
|
this.skip = index - data.length;
|
||||||
return output.slice(0, oi);
|
this.callback(output.slice(0, oi));
|
||||||
};
|
};
|
||||||
|
|
||||||
ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
||||||
@ -412,6 +423,39 @@ ImaAdpcmCodec.prototype.decodeNibble = function(nibble) {
|
|||||||
return this.predictor;
|
return this.predictor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function OpusCodec(callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
this.resetDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpusCodec.prototype.resetDecoder = function() {
|
||||||
|
var me = this;
|
||||||
|
me.decoder = new AudioDecoder({
|
||||||
|
output: function(audioData) {
|
||||||
|
var buffer = new Float32Array(audioData.numberOfFrames * audioData.numberOfChannels);
|
||||||
|
audioData.copyTo(buffer, {planeIndex: 0});
|
||||||
|
me.callback(buffer);
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
console.error(e);
|
||||||
|
me.resetDecoder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
me.decoder.configure({
|
||||||
|
codec: "opus",
|
||||||
|
sampleRate: 12000,
|
||||||
|
numberOfChannels: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
OpusCodec.prototype.decodeAsync = function(data) {
|
||||||
|
this.decoder.decode(new EncodedAudioChunk({
|
||||||
|
type: "key",
|
||||||
|
data: data,
|
||||||
|
timestamp: 0
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
function Interpolator(factor) {
|
function Interpolator(factor) {
|
||||||
this.factor = factor;
|
this.factor = factor;
|
||||||
this.lowpass = new Lowpass(factor)
|
this.lowpass = new Lowpass(factor)
|
||||||
|
@ -98,8 +98,13 @@ TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
|||||||
if (index < 0) return;
|
if (index < 0) return;
|
||||||
|
|
||||||
var delta = 10 ** (Math.floor(Math.max(me.exponent, Math.log10(me.frequency))) - index);
|
var delta = 10 ** (Math.floor(Math.max(me.exponent, Math.log10(me.frequency))) - index);
|
||||||
|
var newFrequency;
|
||||||
|
if ('deltaMode' in e.originalEvent && e.originalEvent.deltaMode === 0) {
|
||||||
|
newFrequency = me.frequency - delta * (e.originalEvent.deltaY / 50);
|
||||||
|
} else {
|
||||||
if (e.originalEvent.deltaY > 0) delta *= -1;
|
if (e.originalEvent.deltaY > 0) delta *= -1;
|
||||||
var newFrequency = me.frequency + delta;
|
newFrequency = me.frequency + delta;
|
||||||
|
}
|
||||||
|
|
||||||
me.element.trigger('frequencychange', newFrequency);
|
me.element.trigger('frequencychange', newFrequency);
|
||||||
});
|
});
|
||||||
|
@ -60,7 +60,7 @@ function zoomOutOneStep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function zoomInTotal() {
|
function zoomInTotal() {
|
||||||
zoom_set(zoom_levels.length - 1);
|
zoom_set(zoom_levels_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoomOutTotal() {
|
function zoomOutTotal() {
|
||||||
@ -317,7 +317,7 @@ function scale_px_from_freq(f, range) {
|
|||||||
function get_visible_freq_range() {
|
function get_visible_freq_range() {
|
||||||
if (!bandwidth) return false;
|
if (!bandwidth) return false;
|
||||||
var fcalc = function (x) {
|
var fcalc = function (x) {
|
||||||
var canvasWidth = waterfallWidth() * zoom_levels[zoom_level];
|
var canvasWidth = waterfallWidth() * get_zoom(zoom_level);
|
||||||
return Math.round(((-zoom_offset_px + x) / canvasWidth) * bandwidth) + (center_freq - bandwidth / 2);
|
return Math.round(((-zoom_offset_px + x) / canvasWidth) * bandwidth) + (center_freq - bandwidth / 2);
|
||||||
};
|
};
|
||||||
var out = {
|
var out = {
|
||||||
@ -565,7 +565,7 @@ function canvas_mousemove(evt) {
|
|||||||
) {
|
) {
|
||||||
zoom_center_rel += dpx;
|
zoom_center_rel += dpx;
|
||||||
}
|
}
|
||||||
resize_canvases(false);
|
resize_canvases();
|
||||||
canvas_drag_last_x = evt.pageX;
|
canvas_drag_last_x = evt.pageX;
|
||||||
canvas_drag_last_y = evt.pageY;
|
canvas_drag_last_y = evt.pageY;
|
||||||
mkscale();
|
mkscale();
|
||||||
@ -616,9 +616,14 @@ function get_relative_x(evt) {
|
|||||||
|
|
||||||
function canvas_mousewheel(evt) {
|
function canvas_mousewheel(evt) {
|
||||||
if (!waterfall_setup_done) return;
|
if (!waterfall_setup_done) return;
|
||||||
|
|
||||||
|
var delta = -evt.deltaY;
|
||||||
|
// deltaMode 0 means pixels instead of lines
|
||||||
|
if ('deltaMode' in evt && evt.deltaMode === 0) {
|
||||||
|
delta /= 50;
|
||||||
|
}
|
||||||
var relativeX = get_relative_x(evt);
|
var relativeX = get_relative_x(evt);
|
||||||
var dir = (evt.deltaY / Math.abs(evt.deltaY)) > 0;
|
zoom_step(delta, relativeX, zoom_center_where_calc(evt.pageX));
|
||||||
zoom_step(dir, relativeX, zoom_center_where_calc(evt.pageX));
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +636,6 @@ function get_zoom_coeff_from_hps(hps) {
|
|||||||
return bandwidth / shown_bw;
|
return bandwidth / shown_bw;
|
||||||
}
|
}
|
||||||
|
|
||||||
var zoom_levels = [1];
|
|
||||||
var zoom_level = 0;
|
var zoom_level = 0;
|
||||||
var zoom_offset_px = 0;
|
var zoom_offset_px = 0;
|
||||||
var zoom_center_rel = 0;
|
var zoom_center_rel = 0;
|
||||||
@ -639,45 +643,48 @@ var zoom_center_where = 0;
|
|||||||
|
|
||||||
var smeter_level = 0;
|
var smeter_level = 0;
|
||||||
|
|
||||||
function mkzoomlevels() {
|
function get_zoom(level) {
|
||||||
zoom_levels = [1];
|
|
||||||
var maxc = get_zoom_coeff_from_hps(zoom_max_level_hps);
|
var maxc = get_zoom_coeff_from_hps(zoom_max_level_hps);
|
||||||
if (maxc < 1) return;
|
if (maxc < 1) return;
|
||||||
// logarithmic interpolation
|
// logarithmic interpolation
|
||||||
var zoom_ratio = Math.pow(maxc, 1 / zoom_levels_count);
|
var zoom_ratio = Math.pow(maxc, 1 / zoom_levels_count);
|
||||||
for (var i = 1; i < zoom_levels_count; i++)
|
return Math.pow(zoom_ratio, level);
|
||||||
zoom_levels.push(Math.pow(zoom_ratio, i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoom_step(out, where, onscreen) {
|
function zoom_step(delta, where, onscreen) {
|
||||||
if ((out && zoom_level === 0) || (!out && zoom_level >= zoom_levels_count - 1)) return;
|
zoom_level += delta;
|
||||||
if (out) --zoom_level;
|
if (zoom_level < 0) {
|
||||||
else ++zoom_level;
|
zoom_level = 0;
|
||||||
|
} else if (zoom_level > zoom_levels_count) {
|
||||||
|
zoom_level = zoom_levels_count;
|
||||||
|
}
|
||||||
|
|
||||||
zoom_center_rel = canvas_get_freq_offset(where);
|
zoom_center_rel = canvas_get_freq_offset(where);
|
||||||
//console.log("zoom_step || zlevel: "+zoom_level.toString()+" zlevel_val: "+zoom_levels[zoom_level].toString()+" zoom_center_rel: "+zoom_center_rel.toString());
|
|
||||||
zoom_center_where = onscreen;
|
zoom_center_where = onscreen;
|
||||||
//console.log(zoom_center_where, zoom_center_rel, where);
|
resize_canvases();
|
||||||
resize_canvases(true);
|
|
||||||
mkscale();
|
mkscale();
|
||||||
bookmarks.position();
|
bookmarks.position();
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoom_set(level) {
|
function zoom_set(level) {
|
||||||
if (!(level >= 0 && level <= zoom_levels.length - 1)) return;
|
if (level < 0) {
|
||||||
level = parseInt(level);
|
zoom_level = 0;
|
||||||
zoom_level = level;
|
} else if (level > zoom_levels_count) {
|
||||||
|
zoom_level = zoom_levels_count;
|
||||||
|
} else {
|
||||||
|
zoom_level = parseFloat(level);
|
||||||
|
}
|
||||||
//zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+waterfallWidth()/2); //zoom to screen center instead of demod envelope
|
//zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+waterfallWidth()/2); //zoom to screen center instead of demod envelope
|
||||||
zoom_center_rel = $('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator().get_offset_frequency();
|
zoom_center_rel = $('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator().get_offset_frequency();
|
||||||
zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack
|
zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack
|
||||||
resize_canvases(true);
|
resize_canvases();
|
||||||
mkscale();
|
mkscale();
|
||||||
bookmarks.position();
|
bookmarks.position();
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoom_calc() {
|
function zoom_calc() {
|
||||||
var winsize = waterfallWidth();
|
var winsize = waterfallWidth();
|
||||||
var canvases_new_width = winsize * zoom_levels[zoom_level];
|
var canvases_new_width = winsize * get_zoom(zoom_level);
|
||||||
zoom_offset_px = -((canvases_new_width * (0.5 + zoom_center_rel / bandwidth)) - (winsize * zoom_center_where));
|
zoom_offset_px = -((canvases_new_width * (0.5 + zoom_center_rel / bandwidth)) - (winsize * zoom_center_where));
|
||||||
if (zoom_offset_px > 0) zoom_offset_px = 0;
|
if (zoom_offset_px > 0) zoom_offset_px = 0;
|
||||||
if (zoom_offset_px < winsize - canvases_new_width)
|
if (zoom_offset_px < winsize - canvases_new_width)
|
||||||
@ -747,7 +754,7 @@ function on_ws_recv(evt) {
|
|||||||
if ('audio_compression' in config) {
|
if ('audio_compression' in config) {
|
||||||
var audio_compression = config['audio_compression'];
|
var audio_compression = config['audio_compression'];
|
||||||
audioEngine.setCompression(audio_compression);
|
audioEngine.setCompression(audio_compression);
|
||||||
divlog("Audio stream is " + ((audio_compression === "adpcm") ? "compressed" : "uncompressed") + ".");
|
divlog("Audio stream is " + ((audio_compression !== "none") ? "compressed" : "uncompressed") + ".");
|
||||||
}
|
}
|
||||||
if ('fft_compression' in config) {
|
if ('fft_compression' in config) {
|
||||||
fft_compression = config['fft_compression'];
|
fft_compression = config['fft_compression'];
|
||||||
@ -1122,12 +1129,10 @@ function shift_canvases() {
|
|||||||
canvas_maxshift++;
|
canvas_maxshift++;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resize_canvases(zoom) {
|
function resize_canvases() {
|
||||||
if (typeof zoom === "undefined") zoom = false;
|
|
||||||
if (!zoom) mkzoomlevels();
|
|
||||||
zoom_calc();
|
zoom_calc();
|
||||||
$('#webrx-canvas-container').css({
|
$('#webrx-canvas-container').css({
|
||||||
width: waterfallWidth() * zoom_levels[zoom_level] + 'px',
|
width: waterfallWidth() * get_zoom(zoom_level) + 'px',
|
||||||
left: zoom_offset_px + "px"
|
left: zoom_offset_px + "px"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1136,7 +1141,6 @@ function waterfall_init() {
|
|||||||
init_canvas_container();
|
init_canvas_container();
|
||||||
resize_canvases();
|
resize_canvases();
|
||||||
scale_setup();
|
scale_setup();
|
||||||
mkzoomlevels();
|
|
||||||
waterfall_setup_done = 1;
|
waterfall_setup_done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ class GeneralSettingsController(SettingsFormController):
|
|||||||
"Audio compression",
|
"Audio compression",
|
||||||
options=[
|
options=[
|
||||||
Option("adpcm", "ADPCM"),
|
Option("adpcm", "ADPCM"),
|
||||||
|
Option("opus", "OPUS"),
|
||||||
Option("none", "None"),
|
Option("none", "None"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -249,13 +249,10 @@ class SdrSource(ABC):
|
|||||||
def getPort(self):
|
def getPort(self):
|
||||||
return self.port
|
return self.port
|
||||||
|
|
||||||
def _getTcpSourceFormat(self):
|
|
||||||
return Format.COMPLEX_FLOAT
|
|
||||||
|
|
||||||
def _getTcpSource(self):
|
def _getTcpSource(self):
|
||||||
with self.modificationLock:
|
with self.modificationLock:
|
||||||
if self.tcpSource is None:
|
if self.tcpSource is None:
|
||||||
self.tcpSource = TcpSource(self.port, self._getTcpSourceFormat())
|
self.tcpSource = TcpSource(self.port, Format.COMPLEX_FLOAT)
|
||||||
return self.tcpSource
|
return self.tcpSource
|
||||||
|
|
||||||
def getBuffer(self):
|
def getBuffer(self):
|
||||||
|
@ -11,10 +11,6 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class DirectSource(SdrSource, metaclass=ABCMeta):
|
class DirectSource(SdrSource, metaclass=ABCMeta):
|
||||||
def __init__(self, id, props):
|
|
||||||
self._conversion = None
|
|
||||||
super().__init__(id, props)
|
|
||||||
|
|
||||||
def onPropertyChange(self, changes):
|
def onPropertyChange(self, changes):
|
||||||
logger.debug("restarting sdr source due to property changes: {0}".format(changes))
|
logger.debug("restarting sdr source due to property changes: {0}".format(changes))
|
||||||
self.stop()
|
self.stop()
|
||||||
@ -52,10 +48,6 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
|
|||||||
def getFormatConversion(self) -> Optional[Chain]:
|
def getFormatConversion(self) -> Optional[Chain]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _getTcpSourceFormat(self):
|
|
||||||
conversion = self.getFormatConversion()
|
|
||||||
return Format.COMPLEX_FLOAT if conversion is None else conversion.getInputFormat()
|
|
||||||
|
|
||||||
# override this in subclasses, if necessary
|
# override this in subclasses, if necessary
|
||||||
def sleepOnRestart(self):
|
def sleepOnRestart(self):
|
||||||
pass
|
pass
|
||||||
@ -65,12 +57,12 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
|
|||||||
source = self._getTcpSource()
|
source = self._getTcpSource()
|
||||||
buffer = Buffer(source.getOutputFormat())
|
buffer = Buffer(source.getOutputFormat())
|
||||||
source.setWriter(buffer)
|
source.setWriter(buffer)
|
||||||
self._conversion = self.getFormatConversion()
|
conversion = self.getFormatConversion()
|
||||||
if self._conversion is not None:
|
if conversion is not None:
|
||||||
self._conversion.setReader(buffer.getReader())
|
conversion.setReader(buffer.getReader())
|
||||||
# this one must be COMPLEX_FLOAT
|
# this one must be COMPLEX_FLOAT
|
||||||
buffer = Buffer(Format.COMPLEX_FLOAT)
|
buffer = Buffer(Format.COMPLEX_FLOAT)
|
||||||
self._conversion.setWriter(buffer)
|
conversion.setWriter(buffer)
|
||||||
self.buffer = buffer
|
self.buffer = buffer
|
||||||
return self.buffer
|
return self.buffer
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ from subprocess import Popen
|
|||||||
from csdr.chain import Chain
|
from csdr.chain import Chain
|
||||||
from pycsdr.modules import Convert, Gain
|
from pycsdr.modules import Convert, Gain
|
||||||
from pycsdr.types import Format
|
from pycsdr.types import Format
|
||||||
from typing import List
|
|
||||||
from owrx.form.input import Input, TextInput
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -51,15 +49,3 @@ class FifiSdrDeviceDescription(DirectSourceDeviceDescription):
|
|||||||
def supportsPpm(self):
|
def supportsPpm(self):
|
||||||
# not currently mapped, and it's unclear how this should be sent to the device
|
# not currently mapped, and it's unclear how this should be sent to the device
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getInputs(self) -> List[Input]:
|
|
||||||
return super().getInputs() + [
|
|
||||||
TextInput(
|
|
||||||
"device",
|
|
||||||
"Device identifier",
|
|
||||||
infotext="Alsa audio device identifier",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
def getDeviceOptionalKeys(self):
|
|
||||||
return super().getDeviceOptionalKeys() + ["device"]
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
_versionstring = "1.2.1"
|
_versionstring = "1.3.0-dev"
|
||||||
looseversion = LooseVersion(_versionstring)
|
looseversion = LooseVersion(_versionstring)
|
||||||
openwebrx_version = "v{0}".format(looseversion)
|
openwebrx_version = "v{0}".format(looseversion)
|
||||||
|
Reference in New Issue
Block a user