improve demodulator initalization, part 2: refactor js classes
This commit is contained in:
		| @@ -27,6 +27,7 @@ | ||||
|         <script src="static/openwebrx.js"></script> | ||||
|         <script src="static/lib/jquery-3.2.1.min.js"></script> | ||||
|         <script src="static/lib/jquery.nanoscroller.js"></script> | ||||
|         <script src="static/lib/Demodulator.js"></script> | ||||
|         <script src="static/lib/BookmarkBar.js"></script> | ||||
|         <script src="static/lib/AudioEngine.js"></script> | ||||
|         <script src="static/lib/ProgressBar.js"></script> | ||||
|   | ||||
							
								
								
									
										217
									
								
								htdocs/lib/Demodulator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								htdocs/lib/Demodulator.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| function Filter() { | ||||
|     this.min_passband = 100; | ||||
| } | ||||
|  | ||||
| Filter.prototype.getLimits = function() { | ||||
|     var max_bw; | ||||
|     if (secondary_demod === 'pocsag') { | ||||
|         max_bw = 12500; | ||||
|     } else { | ||||
|         max_bw = (audioEngine.getOutputRate() / 2) - 1; | ||||
|     } | ||||
|     return { | ||||
|         high: max_bw, | ||||
|         low: -max_bw | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| function Envelope(parent) { | ||||
|     this.parent = parent; | ||||
|     this.dragged_range = Demodulator.draggable_ranges.none; | ||||
| } | ||||
|  | ||||
| Envelope.prototype.draw = function(visible_range){ | ||||
|     this.visible_range = visible_range; | ||||
|     this.drag_ranges = demod_envelope_draw( | ||||
|         range, | ||||
|         center_freq + this.parent.offset_frequency + this.parent.low_cut, | ||||
|         center_freq + this.parent.offset_frequency + this.parent.high_cut, | ||||
|         this.color, center_freq + this.parent.offset_frequency | ||||
|     ); | ||||
| }; | ||||
|  | ||||
| Envelope.prototype.drag_start = function(x, key_modifiers){ | ||||
|     this.key_modifiers = key_modifiers; | ||||
|     this.dragged_range = demod_envelope_where_clicked(x, this.drag_ranges, key_modifiers); | ||||
|     this.drag_origin = { | ||||
|         x: x, | ||||
|         low_cut: this.parent.low_cut, | ||||
|         high_cut: this.parent.high_cut, | ||||
|         offset_frequency: this.parent.offset_frequency | ||||
|     }; | ||||
|     return this.dragged_range !== Demodulator.draggable_ranges.none; | ||||
| }; | ||||
|  | ||||
| Envelope.prototype.drag_move = function(x) { | ||||
|     var dr = Demodulator.draggable_ranges; | ||||
|     var new_value; | ||||
|     if (this.dragged_range === dr.none) return false; // we return if user is not dragging (us) at all | ||||
|     var freq_change = Math.round(this.visible_range.hps * (x - this.drag_origin.x)); | ||||
|  | ||||
|     //dragging the line in the middle of the filter envelope while holding Shift does emulate | ||||
|     //the BFO knob on radio equipment: moving offset frequency, while passband remains unchanged | ||||
|     //Filter passband moves in the opposite direction than dragged, hence the minus below. | ||||
|     var minus = (this.dragged_range === dr.bfo) ? -1 : 1; | ||||
|     //dragging any other parts of the filter envelope while holding Shift does emulate the PBS knob | ||||
|     //(PassBand Shift) on radio equipment: PBS does move the whole passband without moving the offset | ||||
|     //frequency. | ||||
|     if (this.dragged_range === dr.beginning || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) { | ||||
|         //we don't let low_cut go beyond its limits | ||||
|         if ((new_value = this.drag_origin.low_cut + minus * freq_change) < this.parent.filter.getLimits().low) return true; | ||||
|         //nor the filter passband be too small | ||||
|         if (this.parent.high_cut - new_value < this.parent.filter.min_passband) return true; | ||||
|         //sanity check to prevent GNU Radio "firdes check failed: fa <= fb" | ||||
|         if (new_value >= this.parent.high_cut) return true; | ||||
|         this.parent.low_cut = new_value; | ||||
|     } | ||||
|     if (this.dragged_range === dr.ending || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) { | ||||
|         //we don't let high_cut go beyond its limits | ||||
|         if ((new_value = this.drag_origin.high_cut + minus * freq_change) > this.parent.filter.getLimits().high) return true; | ||||
|         //nor the filter passband be too small | ||||
|         if (new_value - this.parent.low_cut < this.parent.filter.min_passband) return true; | ||||
|         //sanity check to prevent GNU Radio "firdes check failed: fa <= fb" | ||||
|         if (new_value <= this.parent.low_cut) return true; | ||||
|         this.parent.high_cut = new_value; | ||||
|     } | ||||
|     if (this.dragged_range === dr.anything_else || this.dragged_range === dr.bfo) { | ||||
|         //when any other part of the envelope is dragged, the offset frequency is changed (whole passband also moves with it) | ||||
|         new_value = this.drag_origin.offset_frequency + freq_change; | ||||
|         if (new_value > bandwidth / 2 || new_value < -bandwidth / 2) return true; //we don't allow tuning above Nyquist frequency :-) | ||||
|         this.parent.offset_frequency = new_value; | ||||
|     } | ||||
|     //now do the actual modifications: | ||||
|     mkenvelopes(this.visible_range); | ||||
|     this.parent.set(); | ||||
|     //will have to change this when changing to multi-demodulator mode: | ||||
|     tunedFrequencyDisplay.setFrequency(center_freq + this.parent.offset_frequency); | ||||
|     return true; | ||||
| }; | ||||
|  | ||||
| Envelope.prototype.drag_end = function(){ | ||||
|     demodulator_buttons_update(); | ||||
|     var to_return = this.dragged_range !== Demodulator.draggable_ranges.none; //this part is required for cliking anywhere on the scale to set offset | ||||
|     this.dragged_range = Demodulator.draggable_ranges.none; | ||||
|     return to_return; | ||||
| }; | ||||
|  | ||||
|  | ||||
| //******* class Demodulator_default_analog ******* | ||||
| // This can be used as a base for basic audio demodulators. | ||||
| // It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB | ||||
|  | ||||
| function Demodulator(offset_frequency, modulation) { | ||||
|     this.offset_frequency = offset_frequency; | ||||
|     this.envelope = new Envelope(this); | ||||
|     this.color = Demodulator.get_next_color(); | ||||
|     this.modulation = modulation; | ||||
|     this.filter = new Filter(); | ||||
|     this.squelch_level = -150; | ||||
|     this.dmr_filter = 3; | ||||
|     this.state = {}; | ||||
|     var mode = Modes.findByModulation(modulation); | ||||
|     if (mode) { | ||||
|         this.low_cut = mode.bandpass.low_cut; | ||||
|         this.high_cut = mode.bandpass.high_cut; | ||||
|     } | ||||
| } | ||||
|  | ||||
| //ranges on filter envelope that can be dragged: | ||||
| Demodulator.draggable_ranges = { | ||||
|     none: 0, | ||||
|     beginning: 1 /*from*/, | ||||
|     ending: 2 /*to*/, | ||||
|     anything_else: 3, | ||||
|     bfo: 4 /*line (while holding shift)*/, | ||||
|     pbs: 5 | ||||
| }; //to which parameter these correspond in demod_envelope_draw() | ||||
|  | ||||
| Demodulator.color_index = 0; | ||||
| Demodulator.colors = ["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"]; | ||||
|  | ||||
| Demodulator.get_next_color = function() { | ||||
|     if (this.color_index >= this.colors.length) this.color_index = 0; | ||||
|     return (this.colors[this.color_index++]); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| Demodulator.prototype.set_offset_frequency = function(to_what) { | ||||
|     if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return; | ||||
|     this.offset_frequency = Math.round(to_what); | ||||
|     this.set(); | ||||
|     mkenvelopes(get_visible_freq_range()); | ||||
|     tunedFrequencyDisplay.setFrequency(center_freq + to_what); | ||||
|     updateHash(); | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.get_offset_frequency = function() { | ||||
|     return this.offset_frequency; | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.get_modulation = function() { | ||||
|     return this.modulation; | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.start = function() { | ||||
|     this.set(); | ||||
|     ws.send(JSON.stringify({ | ||||
|         "type": "dspcontrol", | ||||
|         "action": "start" | ||||
|     })); | ||||
| }; | ||||
|  | ||||
| // TODO check if this is actually used | ||||
| Demodulator.prototype.stop = function() { | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.send = function(params) { | ||||
|     ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); | ||||
| } | ||||
|  | ||||
| Demodulator.prototype.set = function () {  //this function sends demodulator parameters to the server | ||||
|     var params = { | ||||
|         "low_cut": this.low_cut, | ||||
|         "high_cut": this.high_cut, | ||||
|         "offset_freq": this.offset_frequency, | ||||
|         "mod": this.modulation, | ||||
|         "dmr_filter": this.dmr_filter, | ||||
|         "squelch_level": this.squelch_level | ||||
|     }; | ||||
|     var to_send = {}; | ||||
|     for (var key in params) { | ||||
|         if (!(key in this.state) || params[key] !== this.state[key]) { | ||||
|             to_send[key] = params[key]; | ||||
|         } | ||||
|     } | ||||
|     if (Object.keys(to_send).length > 0) { | ||||
|         this.send(to_send); | ||||
|         for (var key in to_send) { | ||||
|             this.state[key] = to_send[key]; | ||||
|         } | ||||
|     } | ||||
|     mkenvelopes(get_visible_freq_range()); | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.setSquelch = function(squelch) { | ||||
|     this.squelch_level = squelch; | ||||
|     this.set(); | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.setDmrFilter = function(dmr_filter) { | ||||
|     this.dmr_filter = dmr_filter; | ||||
|     this.set(); | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.setBandpass = function(bandpass) { | ||||
|     this.bandpass = bandpass; | ||||
|     this.low_cut = bandpass.low_cut; | ||||
|     this.high_cut = bandpass.high_cut; | ||||
|     this.set(); | ||||
| }; | ||||
|  | ||||
| Demodulator.prototype.getBandpass = function() { | ||||
|     return { | ||||
|         low_cut: this.low_cut, | ||||
|         high_cut: this.high_cut | ||||
|     }; | ||||
| }; | ||||
| @@ -142,7 +142,7 @@ function setSquelchToAuto() { | ||||
|  | ||||
| function updateSquelch() { | ||||
|     var sliderValue = parseInt($("#openwebrx-panel-squelch").val()); | ||||
|     ws.send(JSON.stringify({"type": "dspcontrol", "params": {"squelch_level": sliderValue}})); | ||||
|     if (demodulators[0]) demodulators[0].setSquelch(sliderValue); | ||||
| } | ||||
|  | ||||
| var waterfall_min_level; | ||||
| @@ -238,14 +238,6 @@ function typeInAnimation(element, timeout, what, onFinish) { | ||||
|  | ||||
| demodulators = []; | ||||
|  | ||||
| var demodulator_color_index = 0; | ||||
| var demodulator_colors = ["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"]; | ||||
|  | ||||
| function demodulators_get_next_color() { | ||||
|     if (demodulator_color_index >= demodulator_colors.length) demodulator_color_index = 0; | ||||
|     return (demodulator_colors[demodulator_color_index++]); | ||||
| } | ||||
|  | ||||
| function demod_envelope_draw(range, from, to, color, line) {  //                                               ____ | ||||
|     // Draws a standard filter envelope like this: _/    \_ | ||||
|     // Parameters are given in offset frequency (Hz). | ||||
| @@ -331,166 +323,6 @@ function demod_envelope_where_clicked(x, drag_ranges, key_modifiers) {  // Check | ||||
|     return dr.none; //User doesn't drag the envelope for this demodulator | ||||
| } | ||||
|  | ||||
| //******* class Demodulator ******* | ||||
| // this can be used as a base class for ANY demodulator | ||||
| Demodulator = function (offset_frequency) { | ||||
|     this.offset_frequency = offset_frequency; | ||||
|     this.envelope = {}; | ||||
|     this.color = demodulators_get_next_color(); | ||||
|     this.stop = function () { | ||||
|     }; | ||||
| }; | ||||
| //ranges on filter envelope that can be dragged: | ||||
| Demodulator.draggable_ranges = { | ||||
|     none: 0, | ||||
|     beginning: 1 /*from*/, | ||||
|     ending: 2 /*to*/, | ||||
|     anything_else: 3, | ||||
|     bfo: 4 /*line (while holding shift)*/, | ||||
|     pbs: 5 | ||||
| }; //to which parameter these correspond in demod_envelope_draw() | ||||
|  | ||||
| //******* class Demodulator_default_analog ******* | ||||
| // This can be used as a base for basic audio demodulators. | ||||
| // It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB | ||||
|  | ||||
| demodulator_response_time = 50; | ||||
|  | ||||
| function Demodulator_default_analog(offset_frequency, subtype) { | ||||
|     Demodulator.call(this, offset_frequency); | ||||
|     this.subtype = subtype; | ||||
|     this.filter = { | ||||
|         min_passband: 100, | ||||
|         getLimits: function() { | ||||
|             var max_bw; | ||||
|             if (secondary_demod === 'pocsag') { | ||||
|                 max_bw = 12500; | ||||
|             } else { | ||||
|                 max_bw = (audioEngine.getOutputRate() / 2) - 1; | ||||
|             } | ||||
|             return { | ||||
|                 high: max_bw, | ||||
|                 low: -max_bw | ||||
|             }; | ||||
|         } | ||||
|     }; | ||||
|     var mode = Modes.findByModulation(subtype); | ||||
|     if (mode) { | ||||
|         this.low_cut = mode.bandpass.low_cut; | ||||
|         this.high_cut = mode.bandpass.high_cut; | ||||
|     } | ||||
|  | ||||
|     this.wait_for_timer = false; | ||||
|     this.set_after = false; | ||||
|     this.set = function () { //set() is a wrapper to call doset(), but it ensures that doset won't execute more frequently than demodulator_response_time. | ||||
|         if (!this.wait_for_timer) { | ||||
|             this.doset(false); | ||||
|             this.set_after = false; | ||||
|             this.wait_for_timer = true; | ||||
|             var timeout_this = this; //http://stackoverflow.com/a/2130411 | ||||
|             window.setTimeout(function () { | ||||
|                 timeout_this.wait_for_timer = false; | ||||
|                 if (timeout_this.set_after) timeout_this.set(); | ||||
|             }, demodulator_response_time); | ||||
|         } else { | ||||
|             this.set_after = true; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     this.doset = function (first_time) {  //this function sends demodulator parameters to the server | ||||
|         var params = { | ||||
|             "low_cut": this.low_cut, | ||||
|             "high_cut": this.high_cut, | ||||
|             "offset_freq": this.offset_frequency | ||||
|         }; | ||||
|         if (first_time) params.mod = this.subtype; | ||||
|         ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); | ||||
|         mkenvelopes(get_visible_freq_range()); | ||||
|     }; | ||||
|     this.doset(true); //we set parameters on object creation | ||||
|  | ||||
|     //******* envelope object ******* | ||||
|     // for drawing the filter envelope above scale | ||||
|     this.envelope.parent = this; | ||||
|  | ||||
|     this.envelope.draw = function (visible_range) { | ||||
|         this.visible_range = visible_range; | ||||
|         this.drag_ranges = demod_envelope_draw(range, | ||||
|             center_freq + this.parent.offset_frequency + this.parent.low_cut, | ||||
|             center_freq + this.parent.offset_frequency + this.parent.high_cut, | ||||
|             this.color, center_freq + this.parent.offset_frequency); | ||||
|     }; | ||||
|  | ||||
|     this.envelope.dragged_range = Demodulator.draggable_ranges.none; | ||||
|  | ||||
|     // event handlers | ||||
|     this.envelope.drag_start = function (x, key_modifiers) { | ||||
|         this.key_modifiers = key_modifiers; | ||||
|         this.dragged_range = demod_envelope_where_clicked(x, this.drag_ranges, key_modifiers); | ||||
|         this.drag_origin = { | ||||
|             x: x, | ||||
|             low_cut: this.parent.low_cut, | ||||
|             high_cut: this.parent.high_cut, | ||||
|             offset_frequency: this.parent.offset_frequency | ||||
|         }; | ||||
|         return this.dragged_range !== Demodulator.draggable_ranges.none; | ||||
|     }; | ||||
|  | ||||
|     this.envelope.drag_move = function (x) { | ||||
|         var dr = Demodulator.draggable_ranges; | ||||
|         var new_value; | ||||
|         if (this.dragged_range === dr.none) return false; // we return if user is not dragging (us) at all | ||||
|         var freq_change = Math.round(this.visible_range.hps * (x - this.drag_origin.x)); | ||||
|  | ||||
|         //dragging the line in the middle of the filter envelope while holding Shift does emulate | ||||
|         //the BFO knob on radio equipment: moving offset frequency, while passband remains unchanged | ||||
|         //Filter passband moves in the opposite direction than dragged, hence the minus below. | ||||
|         var minus = (this.dragged_range === dr.bfo) ? -1 : 1; | ||||
|         //dragging any other parts of the filter envelope while holding Shift does emulate the PBS knob | ||||
|         //(PassBand Shift) on radio equipment: PBS does move the whole passband without moving the offset | ||||
|         //frequency. | ||||
|         if (this.dragged_range === dr.beginning || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) { | ||||
|             //we don't let low_cut go beyond its limits | ||||
|             if ((new_value = this.drag_origin.low_cut + minus * freq_change) < this.parent.filter.getLimits().low) return true; | ||||
|             //nor the filter passband be too small | ||||
|             if (this.parent.high_cut - new_value < this.parent.filter.min_passband) return true; | ||||
|             //sanity check to prevent GNU Radio "firdes check failed: fa <= fb" | ||||
|             if (new_value >= this.parent.high_cut) return true; | ||||
|             this.parent.low_cut = new_value; | ||||
|         } | ||||
|         if (this.dragged_range === dr.ending || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) { | ||||
|             //we don't let high_cut go beyond its limits | ||||
|             if ((new_value = this.drag_origin.high_cut + minus * freq_change) > this.parent.filter.getLimits().high) return true; | ||||
|             //nor the filter passband be too small | ||||
|             if (new_value - this.parent.low_cut < this.parent.filter.min_passband) return true; | ||||
|             //sanity check to prevent GNU Radio "firdes check failed: fa <= fb" | ||||
|             if (new_value <= this.parent.low_cut) return true; | ||||
|             this.parent.high_cut = new_value; | ||||
|         } | ||||
|         if (this.dragged_range === dr.anything_else || this.dragged_range === dr.bfo) { | ||||
|             //when any other part of the envelope is dragged, the offset frequency is changed (whole passband also moves with it) | ||||
|             new_value = this.drag_origin.offset_frequency + freq_change; | ||||
|             if (new_value > bandwidth / 2 || new_value < -bandwidth / 2) return true; //we don't allow tuning above Nyquist frequency :-) | ||||
|             this.parent.offset_frequency = new_value; | ||||
|         } | ||||
|         //now do the actual modifications: | ||||
|         mkenvelopes(this.visible_range); | ||||
|         this.parent.set(); | ||||
|         //will have to change this when changing to multi-demodulator mode: | ||||
|         tunedFrequencyDisplay.setFrequency(center_freq + this.parent.offset_frequency); | ||||
|         return true; | ||||
|     }; | ||||
|  | ||||
|     this.envelope.drag_end = function () { //in this demodulator we've already changed values in the drag_move() function so we shouldn't do too much here. | ||||
|         demodulator_buttons_update(); | ||||
|         var to_return = this.dragged_range !== Demodulator.draggable_ranges.none; //this part is required for cliking anywhere on the scale to set offset | ||||
|         this.dragged_range = Demodulator.draggable_ranges.none; | ||||
|         return to_return; | ||||
|     }; | ||||
|  | ||||
| } | ||||
|  | ||||
| Demodulator_default_analog.prototype = new Demodulator(); | ||||
|  | ||||
| function mkenvelopes(visible_range) //called from mkscale | ||||
| { | ||||
| @@ -498,7 +330,10 @@ function mkenvelopes(visible_range) //called from mkscale | ||||
|     for (var i = 0; i < demodulators.length; i++) { | ||||
|         demodulators[i].envelope.draw(visible_range); | ||||
|     } | ||||
|     if (demodulators.length) secondary_demod_waterfall_set_zoom(demodulators[0].low_cut, demodulators[0].high_cut); | ||||
|     if (demodulators.length) { | ||||
|         var bandpass = demodulators[0].getBandpass() | ||||
|         secondary_demod_waterfall_set_zoom(bandpass.low_cut, bandpass.high_cut); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function demodulator_remove(which) { | ||||
| @@ -519,33 +354,22 @@ function demodulator_analog_replace(subtype, for_digital) { //this function shou | ||||
|         secondary_demod_close_window(); | ||||
|         secondary_demod_listbox_update(); | ||||
|     } | ||||
|     if (!demodulators || !demodulators[0] || demodulators[0].subtype !== subtype) { | ||||
|     if (!demodulators || !demodulators[0] || demodulators[0].get_modulation() !== subtype) { | ||||
|         last_analog_demodulator_subtype = subtype; | ||||
|         var temp_offset = 0; | ||||
|         if (demodulators.length) { | ||||
|             temp_offset = demodulators[0].offset_frequency; | ||||
|             temp_offset = demodulators[0].get_offset_frequency(); | ||||
|             demodulator_remove(0); | ||||
|         } | ||||
|         demodulator_add(new Demodulator_default_analog(temp_offset, subtype)); | ||||
|         var demod = new Demodulator(temp_offset, subtype); | ||||
|         demod.start(); | ||||
|         demodulator_add(demod); | ||||
|     } | ||||
|     demodulator_buttons_update(); | ||||
|     update_digitalvoice_panels("openwebrx-panel-metadata-" + subtype); | ||||
|     updateHash(); | ||||
| } | ||||
|  | ||||
| Demodulator.prototype.set_offset_frequency = function(to_what) { | ||||
|     if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return; | ||||
|     this.offset_frequency = Math.round(to_what); | ||||
|     this.set(); | ||||
|     mkenvelopes(get_visible_freq_range()); | ||||
|     tunedFrequencyDisplay.setFrequency(center_freq + to_what); | ||||
|     updateHash(); | ||||
| } | ||||
|  | ||||
| Demodulator.prototype.get_offset_frequency = function() { | ||||
|     return this.offset_frequency; | ||||
| } | ||||
|  | ||||
| function waterfallWidth() { | ||||
|     return $('body').width(); | ||||
| } | ||||
| @@ -988,7 +812,7 @@ function zoom_set(level) { | ||||
|     level = parseInt(level); | ||||
|     zoom_level = level; | ||||
|     //zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+waterfallWidth()/2); //zoom to screen center instead of demod envelope | ||||
|     zoom_center_rel = demodulators[0].offset_frequency; | ||||
|     zoom_center_rel = demodulators[0].get_offset_frequency(); | ||||
|     zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack | ||||
|     resize_canvases(true); | ||||
|     mkscale(); | ||||
| @@ -1468,12 +1292,6 @@ var mute = false; | ||||
| // Optimalise these if audio lags or is choppy: | ||||
| var audio_buffer_maximal_length_sec = 1; //actual number of samples are calculated from sample rate | ||||
|  | ||||
| function webrx_set_param(what, value) { | ||||
|     var params = {}; | ||||
|     params[what] = value; | ||||
|     ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); | ||||
| } | ||||
|  | ||||
| function parseHash() { | ||||
|     if (!window.location.hash) { | ||||
|         return {}; | ||||
| @@ -1512,7 +1330,7 @@ function updateHash() { | ||||
|     if (!demod) return; | ||||
|     window.location.hash = $.map({ | ||||
|         freq: demod.get_offset_frequency() + center_freq, | ||||
|         mod: demod.subtype, | ||||
|         mod: demod.get_modulation(), | ||||
|         secondary_mod: secondary_demod | ||||
|     }, function(value, key){ | ||||
|         if (!value) return undefined; | ||||
| @@ -1543,6 +1361,7 @@ function synchronize_demodulator_init(params) { | ||||
|     sync_params = $.extend(sync_params, params || {}); | ||||
|     if (sync_params.initialParams && sync_params.modes && sync_params.features) { | ||||
|         initialize_demodulator(sync_params.initialParams); | ||||
|         delete sync_params.initialParams; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1557,10 +1376,7 @@ function initialize_demodulator(initialParams) { | ||||
|     if (params.offset_frequency) { | ||||
|         demodulators[0].set_offset_frequency(params.offset_frequency); | ||||
|     } | ||||
|     ws.send(JSON.stringify({ | ||||
|         "type": "dspcontrol", | ||||
|         "action": "start" | ||||
|     })); | ||||
|     demodulators[0].start() | ||||
| } | ||||
|  | ||||
| var reconnect_timeout = false; | ||||
| @@ -1836,7 +1652,7 @@ function update_dmr_timeslot_filtering() { | ||||
|     }).toArray().reduce(function (acc, v) { | ||||
|         return acc | v; | ||||
|     }, 0); | ||||
|     webrx_set_param("dmr_filter", filter); | ||||
|     demodulators[0].setDmrFilter(filter); | ||||
| } | ||||
|  | ||||
| function playButtonClick() { | ||||
| @@ -1932,7 +1748,7 @@ function demodulator_buttons_update() { | ||||
|     var $buttons = $(".openwebrx-demodulator-button"); | ||||
|     $buttons.removeClass("highlighted").removeClass('disabled'); | ||||
|     if (!demodulators.length) return; | ||||
|     var mod = demodulators[0].subtype; | ||||
|     var mod = demodulators[0].get_modulation(); | ||||
|     $("#openwebrx-button-" + mod).addClass("highlighted"); | ||||
|     if (secondary_demod) { | ||||
|         $("#openwebrx-button-dig").addClass("highlighted"); | ||||
| @@ -1997,9 +1813,7 @@ function demodulator_digital_replace(subtype) { | ||||
|     secondary_demod_start(subtype); | ||||
|     demodulator_analog_replace(mode.underlying[0], true); | ||||
|     if (mode.bandpass) { | ||||
|         demodulators[0].low_cut = mode.bandpass.low_cut; | ||||
|         demodulators[0].high_cut = mode.bandpass.high_cut; | ||||
|         demodulators[0].set(); | ||||
|         demodulators[0].setBandpass(mode.bandpass); | ||||
|     } | ||||
|     demodulator_buttons_update(); | ||||
|     $('#openwebrx-panel-digimodes').attr('data-mode', subtype); | ||||
|   | ||||
| @@ -139,6 +139,7 @@ class OpenWebRxReceiverClient(Client): | ||||
|     def handleTextMessage(self, conn, message): | ||||
|         try: | ||||
|             message = json.loads(message) | ||||
|             logger.debug(message) | ||||
|             if "type" in message: | ||||
|                 if message["type"] == "dspcontrol": | ||||
|                     if "action" in message and message["action"] == "start": | ||||
| @@ -146,7 +147,7 @@ class OpenWebRxReceiverClient(Client): | ||||
|  | ||||
|                     if "params" in message: | ||||
|                         params = message["params"] | ||||
|                         self.setDspProperties(params) | ||||
|                         self.getDsp().setProperties(params) | ||||
|  | ||||
|                 elif message["type"] == "config": | ||||
|                     if "params" in message: | ||||
| @@ -163,7 +164,7 @@ class OpenWebRxReceiverClient(Client): | ||||
|                     if "params" in message: | ||||
|                         self.connectionProperties = message["params"] | ||||
|                         if self.dsp: | ||||
|                             self.setDspProperties(self.connectionProperties) | ||||
|                             self.getDsp().setProperties(self.connectionProperties) | ||||
|  | ||||
|             else: | ||||
|                 logger.warning("received message without type: {0}".format(message)) | ||||
| @@ -172,39 +173,30 @@ class OpenWebRxReceiverClient(Client): | ||||
|             logger.warning("message is not json: {0}".format(message)) | ||||
|  | ||||
|     def setSdr(self, id=None): | ||||
|         while True: | ||||
|             next = None | ||||
|             if id is not None: | ||||
|                 next = SdrService.getSource(id) | ||||
|             if next is None: | ||||
|                 next = SdrService.getFirstSource() | ||||
|             if next is None: | ||||
|                 # exit condition: no sdrs available | ||||
|                 self.handleNoSdrsAvailable() | ||||
|                 return | ||||
|         next = None | ||||
|         if id is not None: | ||||
|             next = SdrService.getSource(id) | ||||
|         if next is None: | ||||
|             next = SdrService.getFirstSource() | ||||
|         if next is None: | ||||
|             # exit condition: no sdrs available | ||||
|             self.handleNoSdrsAvailable() | ||||
|             return | ||||
|  | ||||
|             # exit condition: no change | ||||
|             if next == self.sdr: | ||||
|                 return | ||||
|         # exit condition: no change | ||||
|         if next == self.sdr: | ||||
|             return | ||||
|  | ||||
|             self.stopDsp() | ||||
|         self.stopDsp() | ||||
|  | ||||
|             if self.configSub is not None: | ||||
|                 self.configSub.cancel() | ||||
|                 self.configSub = None | ||||
|         if self.configSub is not None: | ||||
|             self.configSub.cancel() | ||||
|             self.configSub = None | ||||
|  | ||||
|             self.sdr = next | ||||
|  | ||||
|             self.startDsp() | ||||
|  | ||||
|             # keep trying until we find a suitable SDR | ||||
|             if self.sdr.getState() == SdrSource.STATE_FAILED: | ||||
|                 self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName())) | ||||
|             else: | ||||
|                 break | ||||
|         self.sdr = next | ||||
|  | ||||
|         # send initial config | ||||
|         self.setDspProperties(self.connectionProperties) | ||||
|         self.getDsp().setProperties(self.connectionProperties) | ||||
|  | ||||
|         stack = PropertyStack() | ||||
|         stack.addLayer(0, self.sdr.getProps()) | ||||
| @@ -236,9 +228,14 @@ class OpenWebRxReceiverClient(Client): | ||||
|         self.write_sdr_error("No SDR Devices available") | ||||
|  | ||||
|     def startDsp(self): | ||||
|         if self.dsp is None and self.sdr is not None: | ||||
|             self.dsp = DspManager(self, self.sdr) | ||||
|             self.dsp.start() | ||||
|         while True: | ||||
|             logger.debug("starting dsp...") | ||||
|             self.getDsp().start() | ||||
|             if self.sdr.getState() == SdrSource.STATE_FAILED: | ||||
|                 self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName())) | ||||
|                 self.setSdr() | ||||
|             else: | ||||
|                 break | ||||
|  | ||||
|     def close(self): | ||||
|         self.stopDsp() | ||||
| @@ -250,6 +247,7 @@ class OpenWebRxReceiverClient(Client): | ||||
|         super().close() | ||||
|  | ||||
|     def stopDsp(self): | ||||
|         logger.debug("stopDsp") | ||||
|         if self.dsp is not None: | ||||
|             self.dsp.stop() | ||||
|             self.dsp = None | ||||
| @@ -270,9 +268,11 @@ class OpenWebRxReceiverClient(Client): | ||||
|         for key, value in params.items(): | ||||
|             protected[key] = value | ||||
|  | ||||
|     def setDspProperties(self, params): | ||||
|         for key, value in params.items(): | ||||
|             self.dsp.setProperty(key, value) | ||||
|     def getDsp(self): | ||||
|         if self.dsp is None: | ||||
|             logger.debug("new DSP") | ||||
|             self.dsp = DspManager(self, self.sdr) | ||||
|         return self.dsp | ||||
|  | ||||
|     def write_spectrum_data(self, data): | ||||
|         self.mp_send(bytes([0x01]) + data) | ||||
|   | ||||
| @@ -135,6 +135,7 @@ class DspManager(csdr.output): | ||||
|         super().__init__() | ||||
|  | ||||
|     def start(self): | ||||
|         logger.debug(self.sdrSource) | ||||
|         if self.sdrSource.isAvailable(): | ||||
|             self.dsp.start() | ||||
|  | ||||
| @@ -160,6 +161,10 @@ class DspManager(csdr.output): | ||||
|             sub.cancel() | ||||
|         self.subscriptions = [] | ||||
|  | ||||
|     def setProperties(self, props): | ||||
|         for k, v in props.items(): | ||||
|             self.setProperty(k, v) | ||||
|  | ||||
|     def setProperty(self, prop, value): | ||||
|         self.props[prop] = value | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl