diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index a2ca863..29ae34a 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -302,18 +302,6 @@ input[type=range]:focus::-ms-fill-upper color: #ff6262; } -#openwebrx-problems span -{ - background: #ff6262; - padding: 3px; - font-size: 8pt; - color: white; - font-weight: bold; - border-radius: 4px; - -moz-border-radius: 4px; - margin: 0px 2px 0px 2px; -} - /*#webrx-freq-show { visibility: hidden; diff --git a/htdocs/index.html b/htdocs/index.html index a7dfa10..30dcce3 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -129,7 +129,7 @@
-
OpenWebRX client log
+
OpenWebRX client log
Author: AndrĂ¡s Retzler, HA7ILM
You can support OpenWebRX development via PayPal!
diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index a45b2e5..13a6c5a 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -33,7 +33,6 @@ var center_freq; var audio_buffer_current_size_debug = 0; var audio_buffer_all_size_debug = 0; var audio_buffer_current_count_debug = 0; -var audio_buffer_current_size = 0; var fft_size; var fft_fps; var fft_compression = "none"; @@ -42,23 +41,6 @@ var audio_compression = "none"; var waterfall_setup_done = 0; var secondary_fft_size; var audio_allowed; - -/*function fade(something,from,to,time_ms,fps) -{ - something.style.opacity=from; - something.fade_i=0; - n_of_iters=time_ms/(1000/fps); - change=(to-from)/(n_of_iters-1); - - something.fade_timer=window.setInterval( - function(){ - if(something.fade_i++= parseInt(wfmax.value)) { if (!which) wfmin.value = (parseInt(wfmax.value) - 1).toString(); else wfmax.value = (parseInt(wfmin.value) + 1).toString(); @@ -208,9 +193,9 @@ function setSmeterRelativeValue(value) { var bar = e("openwebrx-smeter-bar"); var outer = e("openwebrx-smeter-outer"); bar.style.width = (outer.offsetWidth * value).toString() + "px"; - bgRed = "linear-gradient(to top, #ff5939 , #961700)"; - bgGreen = "linear-gradient(to top, #22ff2f , #008908)"; - bgYellow = "linear-gradient(to top, #fff720 , #a49f00)"; + var bgRed = "linear-gradient(to top, #ff5939 , #961700)"; + var bgGreen = "linear-gradient(to top, #22ff2f , #008908)"; + var bgYellow = "linear-gradient(to top, #fff720 , #a49f00)"; bar.style.background = (value > 0.9) ? bgRed : ((value > 0.7) ? bgYellow : bgGreen); } @@ -253,8 +238,8 @@ function animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exe if (typeof to_exec === "undefined") to_exec = 0; object.style[style_name] = from.toString() + unit; object.anim_i = 0; - n_of_iters = time_ms / (1000 / fps); - change = (to - from) / (n_of_iters); + var n_of_iters = time_ms / (1000 / fps); + var change = (to - from) / (n_of_iters); if (typeof object.anim_timer !== "undefined") { window.clearInterval(object.anim_timer); } @@ -263,7 +248,8 @@ function animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exe if (object.anim_i++ < n_of_iters) { if (accel === 1) object.style[style_name] = (parseFloat(object.style[style_name]) + change).toString() + unit; else { - remain = parseFloat(object.style[style_name]) - to; + var remain = parseFloat(object.style[style_name]) - to; + var new_val; if (Math.abs(remain) > 9 || unit !== "px") new_val = (to + accel * remain); else { if (Math.abs(remain) < 2) new_val = to; @@ -282,7 +268,7 @@ function animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exe } function animate_to(object, style_name, unit, to, accel, time_ms, fps, to_exec) { - from = parseFloat(style_value(object, style_name)); + var from = parseFloat(style_value(object, style_name)); animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exec); } @@ -293,8 +279,8 @@ function animate_to(object, style_name, unit, to, accel, time_ms, fps, to_exec) demodulators = []; -demodulator_color_index = 0; -demodulator_colors = ["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"] +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; @@ -308,17 +294,17 @@ function demod_envelope_draw(range, from, to, color, line) { // // A "drag range" object is returned, containing information about the draggable areas of the envelope // (beginning, ending and the line showing the offset frequency). if (typeof color === "undefined") color = "#ffff00"; //yellow - env_bounding_line_w = 5; // - env_att_w = 5; // _______ ___env_h2 in px ___|_____ - env_h1 = 17; // _/| \_ ___env_h1 in px _/ |_ \_ - env_h2 = 5; // |||env_att_line_w |_env_lineplus - env_lineplus = 1; // ||env_bounding_line_w - env_line_click_area = 6; + var env_bounding_line_w = 5; // + var env_att_w = 5; // _______ ___env_h2 in px ___|_____ + var env_h1 = 17; // _/| \_ ___env_h1 in px _/ |_ \_ + var env_h2 = 5; // |||env_att_line_w |_env_lineplus + var env_lineplus = 1; // ||env_bounding_line_w + var env_line_click_area = 6; //range=get_visible_freq_range(); - from_px = scale_px_from_freq(from, range); - to_px = scale_px_from_freq(to, range); + var from_px = scale_px_from_freq(from, range); + var to_px = scale_px_from_freq(to, range); if (to_px < from_px) /* swap'em */ { - temp_px = to_px; + var temp_px = to_px; to_px = from_px; from_px = temp_px; } @@ -352,7 +338,7 @@ function demod_envelope_draw(range, from, to, color, line) { // } if (typeof line !== "undefined") // out of screen? { - line_px = scale_px_from_freq(line, range); + var line_px = scale_px_from_freq(line, range); if (!(line_px < 0 || line_px > window.innerWidth)) { drag_ranges.line = {x1: line_px - env_line_click_area / 2, x2: line_px + env_line_click_area / 2}; drag_ranges.line_on_screen = true; @@ -365,10 +351,10 @@ function demod_envelope_draw(range, from, to, color, line) { // } function demod_envelope_where_clicked(x, drag_ranges, key_modifiers) { // Check exactly what the user has clicked based on ranges returned by demod_envelope_draw(). - in_range = function (x, range) { + var in_range = function (x, range) { return range.x1 <= x && range.x2 >= x; }; - dr = demodulator.draggable_ranges; + var dr = Demodulator.draggable_ranges; if (key_modifiers.shiftKey) { //Check first: shift + center drag emulates BFO knob @@ -386,29 +372,27 @@ 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 ******* +//******* class Demodulator ******* // this can be used as a base class for ANY demodulator -demodulator = function (offset_frequency) { +Demodulator = function (offset_frequency) { //console.log("this too"); this.offset_frequency = offset_frequency; - this.has_audio_output = true; - this.has_text_output = false; this.envelope = {}; this.color = demodulators_get_next_color(); this.stop = function () { }; -} +}; //ranges on filter envelope that can be dragged: -demodulator.draggable_ranges = { +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() +}; //to which parameter these correspond in demod_envelope_draw() -//******* class demodulator_default_analog ******* +//******* 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 @@ -416,10 +400,10 @@ demodulator_response_time = 50; //in ms; if we don't limit the number of SETs sent to the server, audio will underrun (possibly output buffer is cleared on SETs in GNU Radio -function demodulator_default_analog(offset_frequency, subtype) { +function Demodulator_default_analog(offset_frequency, subtype) { //console.log("hopefully this happens"); //http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain - demodulator.call(this, offset_frequency); + Demodulator.call(this, offset_frequency); this.subtype = subtype; this.filter = { min_passband: 100, @@ -469,7 +453,7 @@ function demodulator_default_analog(offset_frequency, subtype) { this.doset(false); this.set_after = false; this.wait_for_timer = true; - timeout_this = this; //http://stackoverflow.com/a/2130411 + 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(); @@ -481,7 +465,7 @@ function demodulator_default_analog(offset_frequency, subtype) { }; this.doset = function (first_time) { //this function sends demodulator parameters to the server - params = { + var params = { "low_cut": this.low_cut, "high_cut": this.high_cut, "offset_freq": this.offset_frequency @@ -503,38 +487,31 @@ function demodulator_default_analog(offset_frequency, subtype) { this.color, center_freq + this.parent.offset_frequency); }; - this.envelope.dragged_range = demodulator.draggable_ranges.none; + 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); - //console.log("dragged_range: "+this.dragged_range.toString()); 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; + return this.dragged_range !== Demodulator.draggable_ranges.none; }; this.envelope.drag_move = function (x) { - dr = demodulator.draggable_ranges; + 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 - freq_change = Math.round(this.visible_range.hps * (x - this.drag_origin.x)); - /*if(this.dragged_range==dr.beginning||this.dragged_range==dr.ending) - { - //we don't let the passband be too small - if(this.parent.low_cut+new_freq_change<=this.parent.high_cut-this.parent.filter.min_passband) this.freq_change=new_freq_change; - else return; - } - var new_value;*/ + 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. - minus = (this.dragged_range === dr.bfo) ? -1 : 1; + 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. @@ -570,16 +547,16 @@ function demodulator_default_analog(offset_frequency, subtype) { return true; }; - this.envelope.drag_end = function (x) { //in this demodulator we've already changed values in the drag_move() function so we shouldn't do too much here. + 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(); - 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; + 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(); +Demodulator_default_analog.prototype = new Demodulator(); function mkenvelopes(visible_range) //called from mkscale { @@ -600,8 +577,8 @@ function demodulator_add(what) { mkenvelopes(get_visible_freq_range()); } -last_analog_demodulator_subtype = 'nfm'; -last_digital_demodulator_subtype = 'bpsk31'; +var last_analog_demodulator_subtype = 'nfm'; +var last_digital_demodulator_subtype = 'bpsk31'; function demodulator_analog_replace(subtype, for_digital) { //this function should only exist until the multi-demodulator capability is added if (!(typeof for_digital !== "undefined" && for_digital && secondary_demod)) { @@ -614,7 +591,7 @@ function demodulator_analog_replace(subtype, for_digital) { //this function shou temp_offset = demodulators[0].offset_frequency; demodulator_remove(0); } - demodulator_add(new demodulator_default_analog(temp_offset, subtype)); + demodulator_add(new Demodulator_default_analog(temp_offset, subtype)); demodulator_buttons_update(); update_digitalvoice_panels("openwebrx-panel-metadata-" + subtype); } @@ -655,14 +632,12 @@ var scale_canvas_drag_params = { }; function scale_canvas_mousedown(evt) { - with (scale_canvas_drag_params) { - mouse_down = true; - drag = false; - start_x = evt.pageX; - key_modifiers.shiftKey = evt.shiftKey; - key_modifiers.altKey = evt.altKey; - key_modifiers.ctrlKey = evt.ctrlKey; - } + scale_canvas_drag_params.mouse_down = true; + scale_canvas_drag_params.drag = false; + scale_canvas_drag_params.start_x = evt.pageX; + scale_canvas_drag_params.key_modifiers.shiftKey = evt.shiftKey; + scale_canvas_drag_params.key_modifiers.altKey = evt.altKey; + scale_canvas_drag_params.key_modifiers.ctrlKey = evt.ctrlKey; evt.preventDefault(); } @@ -672,18 +647,19 @@ function scale_offset_freq_from_px(x, visible_range) { } function scale_canvas_mousemove(evt) { - var event_handled; + var event_handled = false; + var i; if (scale_canvas_drag_params.mouse_down && !scale_canvas_drag_params.drag && Math.abs(evt.pageX - scale_canvas_drag_params.start_x) > canvas_drag_min_delta) //we can use the main drag_min_delta thing of the main canvas { scale_canvas_drag_params.drag = true; //call the drag_start for all demodulators (and they will decide if they're dragged, based on X coordinate) - for (var i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_start(evt.pageX, scale_canvas_drag_params.key_modifiers); + for (i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_start(evt.pageX, scale_canvas_drag_params.key_modifiers); scale_canvas.style.cursor = "move"; } else if (scale_canvas_drag_params.drag) { //call the drag_move for all demodulators (and they will decide if they're dragged) - for (var i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_move(evt.pageX); + for (i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_move(evt.pageX); if (!event_handled) demodulator_set_offset_frequency(0, scale_offset_freq_from_px(evt.pageX)); } @@ -699,7 +675,7 @@ function scale_canvas_end_drag(x) { scale_canvas_drag_params.drag = false; scale_canvas_drag_params.mouse_down = false; var event_handled = false; - for (var i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_end(x); + for (var i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_end(); if (!event_handled) demodulator_set_offset_frequency(0, scale_offset_freq_from_px(x)); } @@ -712,8 +688,8 @@ function scale_px_from_freq(f, range) { } function get_visible_freq_range() { - out = {}; - fcalc = function (x) { + var out = {}; + var fcalc = function (x) { return Math.round(((-zoom_offset_px + x) / canvases[0].clientWidth) * bandwidth) + (center_freq - bandwidth / 2); }; out.start = fcalc(0); @@ -793,8 +769,8 @@ var scale_min_space_bw_texts = 50; var scale_min_space_bw_small_markers = 7; function get_scale_mark_spacing(range) { - out = {}; - fcalc = function (freq) { + var out = {}; + var fcalc = function (freq) { out.numlarge = (range.bw / freq); out.large = canvas_container.clientWidth / out.numlarge; //distance between large markers (these have text) out.ratio = 5; //(ratio-1) small markers exist per large marker @@ -807,8 +783,8 @@ function get_scale_mark_spacing(range) { out.smallbw = freq / out.ratio; return true; }; - for (i = scale_markers_levels.length - 1; i >= 0; i--) { - mp = scale_markers_levels[i]; + for (var i = scale_markers_levels.length - 1; i >= 0; i--) { + var mp = scale_markers_levels[i]; if (!fcalc(mp.large_marker_per_hz)) continue; //console.log(mp.large_marker_per_hz); //console.log(out); @@ -818,6 +794,8 @@ function get_scale_mark_spacing(range) { return out; } +var range; + function mkscale() { //clear the lower part of the canvas (where frequency scale resides; the upper part is used by filter envelopes): range = get_visible_freq_range(); @@ -827,17 +805,18 @@ function mkscale() { scale_ctx.font = "bold 11px sans-serif"; scale_ctx.textBaseline = "top"; scale_ctx.fillStyle = "#fff"; - spacing = get_scale_mark_spacing(range); + var spacing = get_scale_mark_spacing(range); //console.log(spacing); - marker_hz = Math.ceil(range.start / spacing.smallbw) * spacing.smallbw; - text_h_pos = 22 + 10 + ((is_firefox) ? 3 : 0); - var text_to_draw; + var marker_hz = Math.ceil(range.start / spacing.smallbw) * spacing.smallbw; + var text_h_pos = 22 + 10 + ((is_firefox) ? 3 : 0); + var text_to_draw = ''; var ftext = function (f) { text_to_draw = format_frequency(spacing.params.format, f, spacing.params.pre_divide, spacing.params.decimals); }; var last_large; + var x; for (; ;) { - var x = scale_px_from_freq(marker_hz, range); + x = scale_px_from_freq(marker_hz, range); if (x > window.innerWidth) break; scale_ctx.beginPath(); scale_ctx.moveTo(x, 22); @@ -875,7 +854,7 @@ function mkscale() { // on the left side scale_ctx.textAlign = "center"; var f = first_large - spacing.smallbw * spacing.ratio; - var x = scale_px_from_freq(f, range); + x = scale_px_from_freq(f, range); ftext(f); var w = scale_ctx.measureText(text_to_draw).width; if (x + w / 2 > 0) scale_ctx.fillText(text_to_draw, x, 22 + 10); @@ -889,7 +868,7 @@ function mkscale() { } function resize_scale() { - ratio = window.devicePixelRatio || 1; + var ratio = window.devicePixelRatio || 1; var w = window.innerWidth; var h = 47; scale_canvas.style.width = w + "px"; @@ -904,7 +883,7 @@ function resize_scale() { } function canvas_get_freq_offset(relativeX) { - rel = (relativeX / canvases[0].clientWidth); + var rel = (relativeX / canvases[0].clientWidth); return Math.round((bandwidth * rel) - (bandwidth / 2)); } @@ -912,14 +891,10 @@ function canvas_get_frequency(relativeX) { return center_freq + canvas_get_freq_offset(relativeX); } -/*function canvas_format_frequency(relativeX) -{ - return (canvas_get_frequency(relativeX)/1e6).toFixed(3)+" MHz"; -}*/ function format_frequency(format, freq_hz, pre_divide, decimals) { - out = format.replace("{x}", (freq_hz / pre_divide).toFixed(decimals)); - at = out.indexOf(".") + 4; + var out = format.replace("{x}", (freq_hz / pre_divide).toFixed(decimals)); + var at = out.indexOf(".") + 4; while (decimals > 3) { out = out.substr(0, at) + "," + out.substr(at); at += 4; @@ -928,9 +903,13 @@ function format_frequency(format, freq_hz, pre_divide, decimals) { return out; } -canvas_drag = false; -canvas_drag_min_delta = 1; -canvas_mouse_down = false; +var canvas_drag = false; +var canvas_drag_min_delta = 1; +var canvas_mouse_down = false; +var canvas_drag_last_x; +var canvas_drag_last_y; +var canvas_drag_start_x; +var canvas_drag_start_y; function canvas_mousedown(evt) { canvas_mouse_down = true; @@ -942,7 +921,7 @@ function canvas_mousedown(evt) { function canvas_mousemove(evt) { if (!waterfall_setup_done) return; - relativeX = get_relative_x(evt); + var relativeX = get_relative_x(evt); if (canvas_mouse_down) { if (!canvas_drag && Math.abs(evt.pageX - canvas_drag_start_x) > canvas_drag_min_delta) { canvas_drag = true; @@ -950,7 +929,6 @@ function canvas_mousemove(evt) { } if (canvas_drag) { var deltaX = canvas_drag_last_x - evt.pageX; - var deltaY = canvas_drag_last_y - evt.pageY; var dpx = range.hps * deltaX; if ( !(zoom_center_rel + dpx > (bandwidth / 2 - canvas_container.clientWidth * (1 - zoom_center_where) * range.hps)) && @@ -968,13 +946,13 @@ function canvas_mousemove(evt) { else e("webrx-mouse-freq").innerHTML = format_frequency("{x} MHz", canvas_get_frequency(relativeX), 1e6, 4); } -function canvas_container_mouseleave(evt) { +function canvas_container_mouseleave() { canvas_end_drag(); } function canvas_mouseup(evt) { if (!waterfall_setup_done) return; - relativeX = get_relative_x(evt); + var relativeX = get_relative_x(evt); if (!canvas_drag) { demodulator_set_offset_frequency(0, canvas_get_freq_offset(relativeX)); @@ -1011,30 +989,29 @@ function canvas_mousewheel(evt) { } -zoom_max_level_hps = 33; //Hz/pixel -zoom_levels_count = 14; +var zoom_max_level_hps = 33; //Hz/pixel +var zoom_levels_count = 14; function get_zoom_coeff_from_hps(hps) { var shown_bw = (window.innerWidth * hps); return bandwidth / shown_bw; } -zoom_levels = [1]; -zoom_level = 0; -zoom_freq = 0; -zoom_offset_px = 0; -zoom_center_rel = 0; -zoom_center_where = 0; +var zoom_levels = [1]; +var zoom_level = 0; +var zoom_offset_px = 0; +var zoom_center_rel = 0; +var zoom_center_where = 0; -smeter_level = 0; +var smeter_level = 0; function mkzoomlevels() { zoom_levels = [1]; - 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; // logarithmic interpolation - zoom_ratio = Math.pow(maxc, 1 / zoom_levels_count); - for (i = 1; i < zoom_levels_count; i++) + var zoom_ratio = Math.pow(maxc, 1 / zoom_levels_count); + for (var i = 1; i < zoom_levels_count; i++) zoom_levels.push(Math.pow(zoom_ratio, i)); } @@ -1059,14 +1036,13 @@ function zoom_set(level) { //zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+canvas_container.clientWidth/2); //zoom to screen center instead of demod envelope zoom_center_rel = demodulators[0].offset_frequency; zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack - console.log(zoom_center_where, zoom_center_rel, -canvases[0].offsetLeft + canvas_container.clientWidth / 2); resize_canvases(true); mkscale(); bookmarks.position(); } function zoom_calc() { - winsize = canvas_container.clientWidth; + var winsize = canvas_container.clientWidth; var canvases_new_width = winsize * zoom_levels[zoom_level]; 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; @@ -1088,14 +1064,14 @@ function resize_waterfall_container(check_init) { } -audio_server_output_rate = 11025; -audio_client_resampling_factor = 4; +var audio_server_output_rate = 11025; +var audio_client_resampling_factor = 4; function audio_calculate_resampling(targetRate) { //both at the server and the client - output_range_max = 12000; - output_range_min = 8000; - i = 1; + var output_range_max = 12000; + var output_range_min = 8000; + var i = 1; while (true) { audio_server_output_rate = Math.floor(targetRate / i); if (audio_server_output_rate < output_range_min) { @@ -1110,10 +1086,10 @@ function audio_calculate_resampling(targetRate) { //both at the server and the c } -debug_ws_data_received = 0; -debug_ws_time_start = 0; -max_clients_num = 0; -client_num = 0; +var debug_ws_data_received = 0; +var debug_ws_time_start = 0; +var max_clients_num = 0; +var client_num = 0; var currentprofile; var COMPRESS_FFT_PAD_N = 10; //should be the same as in csdr.c @@ -1127,32 +1103,32 @@ function on_ws_recv(evt) { divlog("Server acknowledged WebSocket connection."); } else { try { - json = JSON.parse(evt.data); + var json = JSON.parse(evt.data); switch (json.type) { case "config": - config = json.value; - window.waterfall_colors = config.waterfall_colors; - window.waterfall_min_level_default = config.waterfall_min_level; - window.waterfall_max_level_default = config.waterfall_max_level; - window.waterfall_auto_level_margin = config.waterfall_auto_level_margin; + var config = json['value']; + window.waterfall_colors = config['waterfall_colors']; + window.waterfall_min_level_default = config['waterfall_min_level']; + window.waterfall_max_level_default = config['waterfall_max_level']; + window.waterfall_auto_level_margin = config['waterfall_auto_level_margin']; waterfallColorsDefault(); - window.starting_mod = config.start_mod; - window.starting_offset_frequency = config.start_offset_freq; - window.audio_buffering_fill_to = config.client_audio_buffer_size; - bandwidth = config.samp_rate; - center_freq = config.center_freq + config.lfo_offset; - fft_size = config.fft_size; - fft_fps = config.fft_fps; - audio_compression = config.audio_compression; + window.starting_mod = config['start_mod']; + window.starting_offset_frequency = config['start_offset_freq']; + window.audio_buffering_fill_to = config['client_audio_buffer_size']; + bandwidth = config['samp_rate']; + center_freq = config['center_freq'] + config['lfo_offset']; + fft_size = config['fft_size']; + fft_fps = config['fft_fps']; + audio_compression = config['audio_compression']; divlog("Audio stream is " + ((audio_compression === "adpcm") ? "compressed" : "uncompressed") + "."); - fft_compression = config.fft_compression; + fft_compression = config['fft_compression']; divlog("FFT stream is " + ((fft_compression === "adpcm") ? "compressed" : "uncompressed") + "."); - max_clients_num = config.max_clients; + max_clients_num = config['max_clients']; progressbar_set(e("openwebrx-bar-clients"), client_num / max_clients_num, "Clients [" + client_num + "]", client_num > max_clients_num * 0.85); - mathbox_waterfall_colors = config.mathbox_waterfall_colors; - mathbox_waterfall_frequency_resolution = config.mathbox_waterfall_frequency_resolution; - mathbox_waterfall_history_length = config.mathbox_waterfall_history_length; + mathbox_waterfall_colors = config['mathbox_waterfall_colors']; + mathbox_waterfall_frequency_resolution = config['mathbox_waterfall_frequency_resolution']; + mathbox_waterfall_history_length = config['mathbox_waterfall_history_length']; waterfall_init(); audio_preinit(); @@ -1167,75 +1143,79 @@ function on_ws_recv(evt) { } waterfall_clear(); - currentprofile = config.profile_id; + currentprofile = config['profile_id']; $('#openwebrx-sdr-profiles-listbox').val(currentprofile); break; case "secondary_config": - window.secondary_fft_size = json.value.secondary_fft_size; - window.secondary_bw = json.value.secondary_bw; - window.if_samp_rate = json.value.if_samp_rate; + var s = json['value']; + window.secondary_fft_size = s['secondary_fft_size']; + window.secondary_bw = s['secondary_bw']; + window.if_samp_rate = s['if_samp_rate']; secondary_demod_init_canvases(); break; case "receiver_details": - var r = json.value; - e('webrx-rx-title').innerHTML = r.receiver_name; - e('webrx-rx-desc').innerHTML = r.receiver_location + ' | Loc: ' + r.locator + ', ASL: ' + r.receiver_asl + ' m, [maps]'; - e('webrx-rx-photo-title').innerHTML = r.photo_title; - e('webrx-rx-photo-desc').innerHTML = r.photo_desc; + var r = json['value']; + e('webrx-rx-title').innerHTML = r['receiver_name']; + e('webrx-rx-desc').innerHTML = r['receiver_location'] + ' | Loc: ' + r['locator'] + ', ASL: ' + r['receiver_asl'] + ' m, [maps]'; + e('webrx-rx-photo-title').innerHTML = r['photo_title']; + e('webrx-rx-photo-desc').innerHTML = r['photo_desc']; break; case "smeter": - smeter_level = json.value; + smeter_level = json['value']; setSmeterAbsoluteValue(smeter_level); break; case "cpuusage": - var server_cpu_usage = json.value; + var server_cpu_usage = json['value']; progressbar_set(e("openwebrx-bar-server-cpu"), server_cpu_usage, "Server CPU [" + Math.round(server_cpu_usage * 100) + "%]", server_cpu_usage > 85); break; case "clients": - client_num = json.value; + client_num = json['value']; progressbar_set(e("openwebrx-bar-clients"), client_num / max_clients_num, "Clients [" + client_num + "]", client_num > max_clients_num * 0.85); break; case "profiles": var listbox = e("openwebrx-sdr-profiles-listbox"); - listbox.innerHTML = json.value.map(function (profile) { - return '"; + listbox.innerHTML = json['value'].map(function (profile) { + return '"; }).join(""); if (currentprofile) { $('#openwebrx-sdr-profiles-listbox').val(currentprofile); } break; case "features": - for (var feature in json.value) { - $('[data-feature="' + feature + '"')[json.value[feature] ? "show" : "hide"](); + var features = json['value']; + for (var feature in features) { + if (features.hasOwnProperty(feature)) { + $('[data-feature="' + feature + '"')[features[feature] ? "show" : "hide"](); + } } break; case "metadata": - update_metadata(json.value); + update_metadata(json['value']); break; case "wsjt_message": - update_wsjt_panel(json.value); + update_wsjt_panel(json['value']); break; case "dial_frequencies": - var as_bookmarks = json.value.map(function (d) { + var as_bookmarks = json['value'].map(function (d) { return { - name: d.mode.toUpperCase(), - digital_modulation: d.mode, - frequency: d.frequency + name: d['mode'].toUpperCase(), + digital_modulation: d['mode'], + frequency: d['frequency'] }; }); bookmarks.replace_bookmarks(as_bookmarks, 'dial_frequencies'); break; case "aprs_data": - update_packet_panel(json.value); + update_packet_panel(json['value']); break; case "bookmarks": - bookmarks.replace_bookmarks(json.value, "server"); + bookmarks.replace_bookmarks(json['value'], "server"); break; case "sdr_error": - divlog(json.value, true); + divlog(json['value'], true); break; default: - console.warn('received message of unknown type: ' + json.type); + console.warn('received message of unknown type: ' + json['type']); } } catch (e) { // don't lose exception @@ -1246,8 +1226,12 @@ function on_ws_recv(evt) { // binary messages debug_ws_data_received += evt.data.byteLength / 1000; - type = new Uint8Array(evt.data, 0, 1)[0]; - data = evt.data.slice(1); + var type = new Uint8Array(evt.data, 0, 1)[0]; + var data = evt.data.slice(1); + + var waterfall_i16; + var waterfall_f32; + var i; switch (type) { case 1: @@ -1257,9 +1241,9 @@ function on_ws_recv(evt) { } else if (fft_compression === "adpcm") { fft_codec.reset(); - var waterfall_i16 = fft_codec.decode(new Uint8Array(data)); - var waterfall_f32 = new Float32Array(waterfall_i16.length - COMPRESS_FFT_PAD_N); - for (var i = 0; i < waterfall_i16.length; i++) waterfall_f32[i] = waterfall_i16[i + COMPRESS_FFT_PAD_N] / 100; + waterfall_i16 = fft_codec.decode(new Uint8Array(data)); + waterfall_f32 = new Float32Array(waterfall_i16.length - COMPRESS_FFT_PAD_N); + for (i = 0; i < waterfall_i16.length; i++) waterfall_f32[i] = waterfall_i16[i + COMPRESS_FFT_PAD_N] / 100; waterfall_add(waterfall_f32); } break; @@ -1274,7 +1258,7 @@ function on_ws_recv(evt) { audio_prepare(audio_data); audio_buffer_current_size_debug += audio_data.length; audio_buffer_all_size_debug += audio_data.length; - if (!(ios || is_chrome) && (audio_initialized === 0 && audio_prepared_buffers.length > audio_buffering_fill_to)) audio_init() + if (!(ios || is_chrome) && (audio_initialized === 0 && audio_prepared_buffers.length > audio_buffering_fill_to)) audio_init(); break; case 3: // secondary FFT @@ -1283,10 +1267,10 @@ function on_ws_recv(evt) { } else if (fft_compression === "adpcm") { fft_codec.reset(); - var waterfall_i16 = fft_codec.decode(new Uint8Array(data)); - var waterfall_f32 = new Float32Array(waterfall_i16.length - COMPRESS_FFT_PAD_N); - for (var i = 0; i < waterfall_i16.length; i++) waterfall_f32[i] = waterfall_i16[i + COMPRESS_FFT_PAD_N] / 100; - secondary_demod_waterfall_add(waterfall_f32); //TODO digimodes + waterfall_i16 = fft_codec.decode(new Uint8Array(data)); + waterfall_f32 = new Float32Array(waterfall_i16.length - COMPRESS_FFT_PAD_N); + for (i = 0; i < waterfall_i16.length; i++) waterfall_f32[i] = waterfall_i16[i + COMPRESS_FFT_PAD_N] / 100; + secondary_demod_waterfall_add(waterfall_f32); } break; case 4: @@ -1300,24 +1284,25 @@ function on_ws_recv(evt) { } function update_metadata(meta) { - if (meta.protocol) switch (meta.protocol) { + var el; + if (meta['protocol']) switch (meta['protocol']) { case 'DMR': - if (meta.slot) { - var el = $("#openwebrx-panel-metadata-dmr").find(".openwebrx-dmr-timeslot-panel").get(meta.slot); + if (meta['slot']) { + el = $("#openwebrx-panel-metadata-dmr").find(".openwebrx-dmr-timeslot-panel").get(meta['slot']); var id = ""; var name = ""; var target = ""; var group = false; - $(el)[meta.sync ? "addClass" : "removeClass"]("sync"); - if (meta.sync && meta.sync === "voice") { - id = (meta.additional && meta.additional.callsign) || meta.source || ""; - name = (meta.additional && meta.additional.fname) || ""; - if (meta.type === "group") { + $(el)[meta['sync'] ? "addClass" : "removeClass"]("sync"); + if (meta['sync'] && meta['sync'] === "voice") { + id = (meta['additional'] && meta['additional']['callsign']) || meta['source'] || ""; + name = (meta['additional'] && meta['additional']['fname']) || ""; + if (meta['type'] === "group") { target = "Talkgroup: "; group = true; } - if (meta.type === "direct") target = "Direct: "; - target += meta.target || ""; + if (meta['type'] === "direct") target = "Direct: "; + target += meta['target'] || ""; $(el).addClass("active"); } else { $(el).removeClass("active"); @@ -1331,20 +1316,20 @@ function update_metadata(meta) { } break; case 'YSF': - var el = $("#openwebrx-panel-metadata-ysf"); + el = $("#openwebrx-panel-metadata-ysf"); - var mode = " " + var mode = " "; var source = ""; var up = ""; var down = ""; - if (meta.mode && meta.mode !== "") { - mode = "Mode: " + meta.mode; - source = meta.source || ""; - if (meta.lat && meta.lon && meta.source) { - source = "" + source; + if (meta['mode'] && meta['mode'] !== "") { + mode = "Mode: " + meta['mode']; + source = meta['source'] || ""; + if (meta['lat'] && meta['lon'] && meta['source']) { + source = "" + source; } - up = meta.up ? "Up: " + meta.up : ""; - down = meta.down ? "Down: " + meta.down : ""; + up = meta['up'] ? "Up: " + meta['up'] : ""; + down = meta['down'] ? "Down: " + meta['down'] : ""; $(el).find(".openwebrx-meta-slot").addClass("active"); } else { $(el).find(".openwebrx-meta-slot").removeClass("active"); @@ -1372,15 +1357,16 @@ function update_wsjt_panel(msg) { return ('' + i).padStart(2, "0"); }; var linkedmsg = msg['msg']; + var matches; if (['FT8', 'JT65', 'JT9', 'FT4'].indexOf(msg['mode']) >= 0) { - var matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/); + matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/); if (matches && matches[2] !== 'RR73') { linkedmsg = html_escape(matches[1]) + '' + matches[2] + ''; } else { linkedmsg = html_escape(linkedmsg); } } else if (msg['mode'] === 'WSPR') { - var matches = linkedmsg.match(/([A-Z0-9]*\s)([A-R]{2}[0-9]{2})(\s[0-9]+)/); + matches = linkedmsg.match(/([A-Z0-9]*\s)([A-R]{2}[0-9]{2})(\s[0-9]+)/); if (matches) { linkedmsg = html_escape(matches[1]) + '' + matches[2] + '' + html_escape(matches[3]); } else { @@ -1455,7 +1441,7 @@ function update_packet_panel(msg) { styles['background-position-x'] = -(msg.symbol.index % 16) * 15 + 'px'; styles['background-position-y'] = -Math.floor(msg.symbol.index / 16) * 15 + 'px'; if (msg.symbol.table !== '/' && msg.symbol.table !== '\\') { - s = {} + var s = {}; s['background-position-x'] = -(msg.symbol.tableindex % 16) * 15 + 'px'; s['background-position-y'] = -Math.floor(msg.symbol.tableindex / 16) * 15 + 'px'; overlay = '
'; @@ -1497,21 +1483,10 @@ function clear_metadata() { $(".openwebrx-dmr-timeslot-panel").removeClass("muted"); } -function add_problem(what) { - problems_span = e("openwebrx-problems"); - for (var i = 0; i < problems_span.children.length; i++) if (problems_span.children[i].innerHTML === what) return; - new_span = document.createElement("span"); - new_span.innerHTML = what; - problems_span.appendChild(new_span); - window.setTimeout(function (ps, ns) { - ps.removeChild(ns); - }, 1000, problems_span, new_span); -} - -waterfall_measure_minmax = false; -waterfall_measure_minmax_now = false; -waterfall_measure_minmax_min = 1e100; -waterfall_measure_minmax_max = -1e100; +var waterfall_measure_minmax = false; +var waterfall_measure_minmax_now = false; +var waterfall_measure_minmax_min = 1e100; +var waterfall_measure_minmax_max = -1e100; function waterfall_measure_minmax_do(what) { waterfall_measure_minmax_min = Math.min(waterfall_measure_minmax_min, Math.min.apply(Math, what)); @@ -1524,7 +1499,7 @@ function waterfall_measure_minmax_print() { function on_ws_opened() { ws.send("SERVER DE CLIENT client=openwebrx.js type=receiver"); - divlog("WebSocket opened to " + ws_url); + divlog("WebSocket opened to " + ws.url); debug_ws_data_received = 0; debug_ws_time_start = new Date().getTime(); reconnect_timeout = false; @@ -1540,10 +1515,9 @@ function divlog(what, is_error) { if (e("openwebrx-panel-log").openwebrxHidden) toggle_panel("openwebrx-panel-log"); //show panel if any error is present } e("openwebrx-debugdiv").innerHTML += what + "
"; - //var wls=e("openwebrx-log-scroll"); - //wls.scrollTop=wls.scrollHeight; //scroll to bottom - $(".nano").nanoScroller(); - $(".nano").nanoScroller({scroll: 'bottom'}); + var nano = $('.nano'); + nano.nanoScroller(); + nano.nanoScroller({scroll: 'bottom'}); } var audio_context; @@ -1552,13 +1526,9 @@ var volume = 1.0; var volumeBeforeMute = 100.0; var mute = false; -var audio_received = Array(); -var audio_buffer_index = 0; var audio_resampler; var audio_codec = new sdrjs.ImaAdpcm(); var audio_node; -//var audio_received_sample_rate = 48000; -var audio_input_buffer_size; // Optimalise these if audio lags or is choppy: var audio_buffer_size; @@ -1569,7 +1539,6 @@ var audio_flush_interval_ms = 500; //the interval in which audio_flush() is call var audio_prepared_buffers = Array(); var audio_rebuffer; var audio_last_output_buffer; -var audio_last_output_offset = 0; var audio_buffering = false; //var audio_buffering_fill_to=4; //on audio underrun we wait until this n*audio_buffer_size samples are present //tnx to the hint from HA3FLT, now we have about half the response time! (original value: 10) @@ -1602,55 +1571,6 @@ function audio_prepare(data) { } } - -function audio_prepare_without_resampler(data) { - audio_rebuffer.push(sdrjs.ConvertI16_F(data)); - console.log("prepare", data.length, audio_rebuffer.remaining()); - while (audio_rebuffer.remaining()) { - audio_prepared_buffers.push(audio_rebuffer.take()); - audio_buffer_current_count_debug++; - } - if (audio_buffering && audio_prepared_buffers.length > audio_buffering_fill_to) audio_buffering = false; -} - -function audio_prepare_old(data) { - //console.log("audio_prepare :: "+data.length.toString()); - //console.log("data.len = "+data.length.toString()); - var dopush = function () { - console.log(audio_last_output_buffer); - audio_prepared_buffers.push(audio_last_output_buffer); - audio_last_output_offset = 0; - audio_last_output_buffer = new Float32Array(audio_buffer_size); - audio_buffer_current_count_debug++; - }; - - var original_data_length = data.length; - var f32data = new Float32Array(data.length); - for (var i = 0; i < data.length; i++) f32data[i] = data[i] / 32768; //convert_i16_f - data = audio_resampler.process(f32data); - console.log(data, data.length, original_data_length); - if (data.length === 0) return; - if (audio_last_output_offset + data.length <= audio_buffer_size) { //array fits into output buffer - for (var i = 0; i < data.length; i++) audio_last_output_buffer[i + audio_last_output_offset] = data[i]; - audio_last_output_offset += data.length; - console.log("fits into; offset=" + audio_last_output_offset.toString()); - if (audio_last_output_offset === audio_buffer_size) dopush(); - } - else { //array is larger than the remaining space in the output buffer - var copied = audio_buffer_size - audio_last_output_offset; - var remain = data.length - copied; - for (var i = 0; i < audio_buffer_size - audio_last_output_offset; i++) //fill the remaining space in the output buffer - audio_last_output_buffer[i + audio_last_output_offset] = data[i];///32768; - dopush();//push the output buffer and create a new one - console.log("larger than; copied half: " + copied.toString() + ", now at: " + audio_last_output_offset.toString()); - for (var i = 0; i < remain; i++) //copy the remaining input samples to the new output buffer - audio_last_output_buffer[i] = data[i + copied];///32768; - audio_last_output_offset += remain; - console.log("larger than; remained: " + remain.toString() + ", now at: " + audio_last_output_offset.toString()); - } - if (audio_buffering && audio_prepared_buffers.length > audio_buffering_fill_to) audio_buffering = false; -} - if (!AudioBuffer.prototype.copyToChannel) { //Chrome 36 does not have it, Firefox does AudioBuffer.prototype.copyToChannel = function (input, channel) //input is Float32Array { @@ -1668,7 +1588,6 @@ function audio_onprocess(e) { } if (audio_prepared_buffers.length === 0) { audio_buffer_progressbar_update(); - /*add_problem("audio underrun");*/ audio_buffering = true; e.outputBuffer.copyToChannel(silence, 0); } else { @@ -1712,8 +1631,8 @@ function audio_buffer_progressbar_update() { function audio_flush() { - flushed = false; - we_have_more_than = function (sec) { + var flushed = false; + var we_have_more_than = function (sec) { return sec * audio_context.sampleRate < audio_prepared_buffers.length * audio_buffer_size; }; if (we_have_more_than(audio_buffer_maximal_length_sec)) while (we_have_more_than(audio_buffer_decrease_to_on_overrun_sec)) { @@ -1721,77 +1640,23 @@ function audio_flush() { flushed = true; audio_prepared_buffers.shift(); } - //if(flushed) add_problem("audio overrun"); -} - - -function audio_onprocess_notused(e) { - //https://github.com/0xfe/experiments/blob/master/www/tone/js/sinewave.js - if (audio_received.length === 0) { - add_problem("audio underrun"); - return; - } - output = e.outputBuffer.getChannelData(0); - int_buffer = audio_received[0]; - read_remain = audio_buffer_size; - //audio_buffer_maximal_length=120; - - obi = 0; //output buffer index - debug_str = ""; - while (1) { - if (int_buffer.length - audio_buffer_index > read_remain) { - for (i = audio_buffer_index; i < audio_buffer_index + read_remain; i++) - output[obi++] = int_buffer[i] / 32768; - //debug_str+="added whole ibl="+int_buffer.length.toString()+" abi="+audio_buffer_index.toString()+" "+(int_buffer.length-audio_buffer_index).toString()+">"+read_remain.toString()+" obi="+obi.toString()+"\n"; - audio_buffer_index += read_remain; - break; - } - else { - for (i = audio_buffer_index; i < int_buffer.length; i++) - output[obi++] = int_buffer[i] / 32768; - read_remain -= (int_buffer.length - audio_buffer_index); - audio_buffer_current_size -= audio_received[0].length; - /*if (audio_received.length>audio_buffer_maximal_length) - { - add_problem("audio overrun"); - audio_received.splice(0,audio_received.length-audio_buffer_maximal_length); - } - else*/ - audio_received.splice(0, 1); - //debug_str+="added remain, remain="+read_remain.toString()+" abi="+audio_buffer_index.toString()+" alen="+int_buffer.length.toString()+" i="+i.toString()+" arecva="+audio_received.length.toString()+" obi="+obi.toString()+"\n"; - audio_buffer_index = 0; - if (audio_received.length === 0 || read_remain === 0) return; - int_buffer = audio_received[0]; - } - } - //debug_str+="obi="+obi.toString(); - //alert(debug_str); -} - -function audio_flush_notused() { - if (audio_buffer_current_size > audio_buffer_maximal_length_sec * audio_context.sampleRate) { - add_problem("audio overrun"); - console.log("audio_flush() :: size: " + audio_buffer_current_size.toString() + " allowed: " + (audio_buffer_maximal_length_sec * audio_context.sampleRate).toString()); - while (audio_buffer_current_size > audio_buffer_maximal_length_sec * audio_context.sampleRate * 0.5) { - audio_buffer_current_size -= audio_received[0].length; - audio_received.splice(0, 1); - } - } } function webrx_set_param(what, value) { - params = {}; + var params = {}; params[what] = value; ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); } var starting_mute = false; +var starting_offset_frequency; +var starting_mod; function parsehash() { + var h; if (h = window.location.hash) { h.substring(1).split(",").forEach(function (x) { - harr = x.split("="); - //console.log(harr); + var harr = x.split("="); if (harr[0] === "mute") toggleMute(); else if (harr[0] === "mod") starting_mod = harr[1]; else if (harr[0] === "sql") { @@ -1857,7 +1722,7 @@ function audio_init() { audio_initialized = 1; // only tell on_ws_recv() not to call it again //on Chrome v36, createJavaScriptNode has been replaced by createScriptProcessor - createjsnode_function = (audio_context.createJavaScriptNode === undefined) ? audio_context.createScriptProcessor.bind(audio_context) : audio_context.createJavaScriptNode.bind(audio_context); + var createjsnode_function = (audio_context.createJavaScriptNode === undefined) ? audio_context.createScriptProcessor.bind(audio_context) : audio_context.createJavaScriptNode.bind(audio_context); audio_node = createjsnode_function(audio_buffer_size, 0, 1); audio_node.onaudioprocess = audio_onprocess; audio_node.connect(audio_context.destination); @@ -1865,7 +1730,7 @@ function audio_init() { //https://github.com/grantgalitz/XAudioJS/blob/master/XAudioServer.js //audio_resampler = new Resampler(audio_received_sample_rate, audio_context.sampleRate, 1, audio_buffer_size, true); //audio_input_buffer_size = audio_buffer_size*(audio_received_sample_rate/audio_context.sampleRate); - webrx_set_param("audio_rate", audio_context.sampleRate); //Don't try to resample //TODO remove this + webrx_set_param("audio_rate", audio_context.sampleRate); window.setInterval(audio_flush, audio_flush_interval_ms); divlog('Web Audio API succesfully initialized, sample rate: ' + audio_context.sampleRate.toString() + " sps"); @@ -1913,7 +1778,7 @@ function on_ws_closed() { setTimeout(open_websocket, reconnect_timeout); } -function on_ws_error(event) { +function on_ws_error() { divlog("WebSocket error.", 1); } @@ -1921,13 +1786,15 @@ String.prototype.startswith = function (str) { return this.indexOf(str) === 0; }; //http://stackoverflow.com/questions/646628/how-to-check-if-a-string-startswith-another-string +var ws; + function open_websocket() { var protocol = 'ws'; if (window.location.toString().startsWith('https://')) { protocol = 'wss'; } - ws_url = protocol + "://" + (window.location.origin.split("://")[1]) + "/ws/"; //guess automatically -> now default behaviour + var ws_url = protocol + "://" + (window.location.origin.split("://")[1]) + "/ws/"; //guess automatically -> now default behaviour if (!("WebSocket" in window)) divlog("Your browser does not support WebSocket, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser."); ws = new WebSocket(ws_url); @@ -1947,19 +1814,19 @@ function waterfall_mkcolor(db_value, waterfall_colors_arg) { if (typeof waterfall_colors_arg === 'undefined') waterfall_colors_arg = waterfall_colors; if (db_value < waterfall_min_level) db_value = waterfall_min_level; if (db_value > waterfall_max_level) db_value = waterfall_max_level; - full_scale = waterfall_max_level - waterfall_min_level; - relative_value = db_value - waterfall_min_level; - value_percent = relative_value / full_scale; - percent_for_one_color = 1 / (waterfall_colors_arg.length - 1); - index = Math.floor(value_percent / percent_for_one_color); - remain = (value_percent - percent_for_one_color * index) / percent_for_one_color; + var full_scale = waterfall_max_level - waterfall_min_level; + var relative_value = db_value - waterfall_min_level; + var value_percent = relative_value / full_scale; + var percent_for_one_color = 1 / (waterfall_colors_arg.length - 1); + var index = Math.floor(value_percent / percent_for_one_color); + var remain = (value_percent - percent_for_one_color * index) / percent_for_one_color; return color_between(waterfall_colors_arg[index + 1], waterfall_colors_arg[index], remain); } function color_between(first, second, percent) { - output = 0; - for (i = 0; i < 4; i++) { - add = ((((first & (0xff << (i * 8))) >>> 0) * percent) + (((second & (0xff << (i * 8))) >>> 0) * (1 - percent))) & (0xff << (i * 8)); + var output = 0; + for (var i = 0; i < 4; i++) { + var add = ((((first & (0xff << (i * 8))) >>> 0) * percent) + (((second & (0xff << (i * 8))) >>> 0) * (1 - percent))) & (0xff << (i * 8)); output |= add >>> 0; } return output >>> 0; @@ -1970,7 +1837,7 @@ var canvas_context; var canvases = []; var canvas_default_height = 200; var canvas_container; -var canvas_phantom; +var canvas_actual_line; function add_canvas() { var new_canvas = document.createElement("canvas"); @@ -2019,7 +1886,7 @@ function resize_canvases(zoom) { if (typeof zoom === "undefined") zoom = false; if (!zoom) mkzoomlevels(); zoom_calc(); - new_width = (canvas_container.clientWidth * zoom_levels[zoom_level]).toString() + "px"; + var new_width = (canvas_container.clientWidth * zoom_levels[zoom_level]).toString() + "px"; var zoom_value = zoom_offset_px.toString() + "px"; canvases.forEach(function (p) { p.style.width = new_width; @@ -2037,8 +1904,6 @@ function waterfall_init() { waterfall_setup_done = 1; } -var waterfall_dont_scale = 0; - var mathbox_shift = function () { if (mathbox_data_current_depth < mathbox_data_max_depth) mathbox_data_current_depth++; if (mathbox_data_index + 1 >= mathbox_data_max_depth) mathbox_data_index = 0; @@ -2077,9 +1942,9 @@ function waterfall_add(data) { mathbox_shift(); } else { //Add line to waterfall image - oneline_image = canvas_context.createImageData(w, 1); - for (x = 0; x < w; x++) { - color = waterfall_mkcolor(data[x]); + var oneline_image = canvas_context.createImageData(w, 1); + for (var x = 0; x < w; x++) { + var color = waterfall_mkcolor(data[x]); for (i = 0; i < 4; i++) oneline_image.data[x * 4 + i] = ((color >>> 0) >> ((3 - i) * 8)) & 0xff; } @@ -2099,7 +1964,6 @@ function check_top_bar_congestion() { }; var wet = e("webrx-rx-title"); var wed = e("webrx-rx-desc"); - var rightmost = Math.max(rmf(wet), rmf(wed)); var tl = e("openwebrx-main-buttons"); [wet, wed].map(function (what) { @@ -2119,6 +1983,16 @@ var MATHBOX_MODES = var mathbox_mode = MATHBOX_MODES.UNINITIALIZED; var mathbox; var mathbox_element; +var mathbox_waterfall_colors; +var mathbox_waterfall_frequency_resolution; +var mathbox_waterfall_history_length; +var mathbox_correction_for_z; +var mathbox_data_max_depth; +var mathbox_data_current_depth; +var mathbox_data_index; +var mathbox_data; +var mathbox_data_global_index; +var mathbox_container; function mathbox_init() { //mathbox_waterfall_history_length is defined in the config @@ -2133,12 +2007,12 @@ function mathbox_init() { plugins: ['core', 'controls', 'cursor', 'stats'], controls: {klass: THREE.OrbitControls} }); - three = mathbox.three; + var three = mathbox.three; if (typeof three === "undefined") divlog("3D waterfall cannot be initialized because WebGL is not supported in your browser.", true); three.renderer.setClearColor(new THREE.Color(0x808080), 1.0); mathbox_container.appendChild((mathbox_element = three.renderer.domElement)); - view = mathbox + var view = mathbox .set({ scale: 1080, focus: 3 @@ -2191,18 +2065,18 @@ function mathbox_init() { if (!mathbox_data_index_valid(zIndex)) return {y: undefined, dBValue: undefined, zAdd: 0}; var index = Math.trunc(xIndex + realZIndex * fft_size); var dBValue = mathbox_data[index]; + var y; if (dBValue > waterfall_max_level) y = 1; else if (dBValue < waterfall_min_level) y = 0; else y = (dBValue - waterfall_min_level) / (waterfall_max_level - waterfall_min_level); - mathbox_dbg = {dbv: dBValue, indexval: index, mbd: mathbox_data.length, yval: y}; if (!y) y = 0; return {y: y, dBValue: dBValue, zAdd: zAdd}; }; - var points = view.area({ + view.area({ expr: function (emit, x, z, i, j, t) { var y; - remapResult = remap(x, z, t); + var remapResult = remap(x, z, t); if ((y = remapResult.y) === undefined) return; emit(x, y, z + remapResult.zAdd); }, @@ -2212,7 +2086,7 @@ function mathbox_init() { axes: [1, 3] }); - var colors = view.area({ + view.area({ expr: function (emit, x, z, i, j, t) { var dBValue; if ((dBValue = remap(x, z, t).dBValue) === undefined) return; @@ -2265,7 +2139,6 @@ function waterfall_clear() { { var x = canvases.shift(); x.parentNode.removeChild(x); - delete x; } add_canvas(); } @@ -2287,7 +2160,8 @@ var bookmarks; function openwebrx_init() { if (ios || is_chrome) e("openwebrx-big-grey").style.display = "table-cell"; - (opb = e("openwebrx-play-button-text")).style.marginTop = (window.innerHeight / 2 - opb.clientHeight / 2).toString() + "px"; + var opb = e("openwebrx-play-button-text"); + opb.style.marginTop = (window.innerHeight / 2 - opb.clientHeight / 2).toString() + "px"; init_rx_photo(); open_websocket(); secondary_demod_init(); @@ -2342,25 +2216,17 @@ var rt = function (s, n) { return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + n) ? c : c - 26); }); }; -var irt = function (s, n) { - return s.replace(/[a-zA-Z]/g, function (c) { - return String.fromCharCode((c >= "a" ? 97 : 65) <= (c = c.charCodeAt(0) - n) ? c : c + 26); - }); -}; -var sendmail2 = function (s) { - window.location.href = "mailto:" + irt(s.replace("=", String.fromCharCode(0100)).replace("$", "."), 8); -}; var audio_debug_time_start = 0; var audio_debug_time_last_start = 0; function debug_audio() { if (audio_debug_time_start === 0) return; //audio_init has not been called - time_now = (new Date()).getTime(); - audio_debug_time_since_last_call = (time_now - audio_debug_time_last_start) / 1000; + var time_now = (new Date()).getTime(); + var audio_debug_time_since_last_call = (time_now - audio_debug_time_last_start) / 1000; audio_debug_time_last_start = time_now; //now - audio_debug_time_taken = (time_now - audio_debug_time_start) / 1000; - kbps_mult = (audio_compression === "adpcm") ? 8 : 16; + var audio_debug_time_taken = (time_now - audio_debug_time_start) / 1000; + var kbps_mult = (audio_compression === "adpcm") ? 8 : 16; //e("openwebrx-audio-sps").innerHTML= // ((audio_compression=="adpcm")?"ADPCM compressed":"uncompressed")+" audio downlink:
"+(audio_buffer_current_size_debug*kbps_mult/audio_debug_time_since_last_call).toFixed(0)+" kbps ("+ // (audio_buffer_all_size_debug*kbps_mult/audio_debug_time_taken).toFixed(1)+" kbps avg.), feed at "+ @@ -2389,19 +2255,19 @@ function debug_audio() { // ======================= PANELS ======================= // ======================================================== -panel_margin = 5.9; +var panel_margin = 5.9; function pop_bottommost_panel(from) { - min_order = parseInt(from[0].dataset.panelOrder); - min_index = 0; - for (i = 0; i < from.length; i++) { - actual_order = parseInt(from[i].dataset.panelOrder); + var min_order = parseInt(from[0].dataset.panelOrder); + var min_index = 0; + for (var i = 0; i < from.length; i++) { + var actual_order = parseInt(from[i].dataset.panelOrder); if (actual_order < min_order) { min_index = i; min_order = actual_order; } } - to_return = from[min_index]; + var to_return = from[min_index]; from.splice(min_index, 1); return to_return; } @@ -2441,26 +2307,20 @@ function toggle_panel(what, on) { function first_show_panel(panel) { panel.style.transitionDuration = 0; panel.style.transitionDelay = 0; - rotx = (Math.random() > 0.5) ? -90 : 90; - roty = 0; + var rotx = (Math.random() > 0.5) ? -90 : 90; + var roty = 0; if (Math.random() > 0.5) { - rottemp = rotx; + var rottemp = rotx; rotx = roty; roty = rottemp; } if (rotx !== 0 && Math.random() > 0.5) rotx = 270; - //console.log(rotx,roty); - transformString = "perspective( 599px ) rotateX( %1deg ) rotateY( %2deg )" + panel.style.transform = "perspective( 599px ) rotateX( %1deg ) rotateY( %2deg )" .replace("%1", rotx.toString()).replace("%2", roty.toString()); - //console.log(transformString); - //console.log(panel); - panel.style.transform = transformString; window.setTimeout(function () { panel.style.transitionDuration = "599ms"; panel.style.transitionDelay = (Math.floor(Math.random() * 500)).toString() + "ms"; panel.style.transform = "perspective( 599px ) rotateX( 0deg ) rotateY( 0deg )"; - //panel.style.transitionDuration="0ms"; - //panel.style.transitionDelay="0"; }, 1); } @@ -2471,8 +2331,8 @@ function place_panels(function_apply) { var left_col = []; var right_col = []; var plist = e("openwebrx-panels-container").children; - for (i = 0; i < plist.length; i++) { - c = plist[i]; + for (var i = 0; i < plist.length; i++) { + var c = plist[i]; if (c.className.indexOf("openwebrx-panel") >= 0) { if (c.openwebrxHidden) { c.style.display = "none"; @@ -2480,7 +2340,7 @@ function place_panels(function_apply) { } c.style.display = "block"; c.openwebrxPanelTransparent = (!!c.dataset.panelTransparent); - newSize = c.dataset.panelSize.split(","); + var newSize = c.dataset.panelSize.split(","); if (c.dataset.panelPos === "left") { left_col.push(c); } @@ -2496,7 +2356,8 @@ function place_panels(function_apply) { } } - y = hoffset; //was y=0 before hoffset + var y = hoffset; //was y=0 before hoffset + var p; while (left_col.length > 0) { p = pop_bottommost_panel(left_col); p.style.left = "0px"; @@ -2576,8 +2437,22 @@ function demodulator_analog_replace_last() { |___/ */ -secondary_demod = false; -secondary_demod_offset_freq = 0; +var secondary_demod = false; +var secondary_demod_fft_offset_db = 30; //need to calculate that later +var secondary_demod_canvases_initialized = false; +var secondary_demod_listbox_updating = false; +var secondary_demod_channel_freq = 1000; +var secondary_demod_waiting_for_set = false; +var secondary_demod_low_cut; +var secondary_demod_high_cut; +var secondary_demod_mousedown = false; +var secondary_demod_canvas_width; +var secondary_demod_canvas_left; +var secondary_demod_canvas_container; +var secondary_demod_current_canvas_actual_line; +var secondary_demod_current_canvas_context; +var secondary_demod_current_canvas_index; +var secondary_demod_canvases; function demodulator_digital_replace_last() { demodulator_digital_replace(last_digital_demodulator_subtype); @@ -2621,7 +2496,6 @@ function secondary_demod_create_canvas() { new_canvas.height = $(secondary_demod_canvas_container).height(); new_canvas.style.width = $(secondary_demod_canvas_container).width() + "px"; new_canvas.style.height = $(secondary_demod_canvas_container).height() + "px"; - console.log(new_canvas.width, new_canvas.height, new_canvas.style.width, new_canvas.style.height); secondary_demod_current_canvas_actual_line = new_canvas.height - 1; $(secondary_demod_canvas_container).children().last().before(new_canvas); return new_canvas; @@ -2643,7 +2517,6 @@ function secondary_demod_init_canvases() { secondary_demod_current_canvas_actual_line = $(secondary_demod_canvas_container).height() - 1; secondary_demod_current_canvas_index = 0; secondary_demod_canvases_initialized = true; - //secondary_demod_update_channel_freq_from_event(); mkscale(); //so that the secondary waterfall zoom level will be initialized } @@ -2652,7 +2525,6 @@ function secondary_demod_canvases_update_top() { } function secondary_demod_swap_canvases() { - console.log("swap"); secondary_demod_canvases[0 + !secondary_demod_current_canvas_index].openwebrx_top -= $(secondary_demod_canvas_container).height() * 2; secondary_demod_current_canvas_index = 0 + !secondary_demod_current_canvas_index; secondary_demod_current_canvas_context = secondary_demod_canvases[secondary_demod_current_canvas_index].getContext("2d"); @@ -2679,22 +2551,11 @@ function secondary_demod_start(subtype) { secondary_demod = subtype; } -function secondary_demod_set() { - ws.send(JSON.stringify({"type": "dspcontrol", "params": {"secondary_offset_freq": secondary_demod_offset_freq}})); -} - function secondary_demod_stop() { ws.send(JSON.stringify({"type": "dspcontrol", "params": {"secondary_mod": false}})); secondary_demod = false; } -function secondary_demod_push_binary_data(x) { - secondary_demod_push_data(Array.from(x).map(function (y) { - return y ? "1" : "0" - }).join("") - ); -} - function secondary_demod_push_data(x) { x = Array.from(x).filter(function (y) { var c = y.charCodeAt(0); @@ -2716,10 +2577,6 @@ function secondary_demod_push_data(x) { $("#openwebrx-cursor-blink").before(x); } -function secondary_demod_data_clear() { - $("#openwebrx-cursor-blink").prevAll().remove(); -} - function secondary_demod_close_window() { secondary_demod_stop(); toggle_panel("openwebrx-panel-digimodes", false); @@ -2727,17 +2584,15 @@ function secondary_demod_close_window() { toggle_panel("openwebrx-panel-packet-message", false); } -secondary_demod_fft_offset_db = 30; //need to calculate that later - function secondary_demod_waterfall_add(data) { if (!secondary_demod) return; var w = secondary_fft_size; //Add line to waterfall image var oneline_image = secondary_demod_current_canvas_context.createImageData(w, 1); - for (x = 0; x < w; x++) { + for (var x = 0; x < w; x++) { var color = waterfall_mkcolor(data[x] + secondary_demod_fft_offset_db); - for (i = 0; i < 4; i++) oneline_image.data[x * 4 + i] = ((color >>> 0) >> ((3 - i) * 8)) & 0xff; + for (var i = 0; i < 4; i++) oneline_image.data[x * 4 + i] = ((color >>> 0) >> ((3 - i) * 8)) & 0xff; } //Draw image @@ -2750,10 +2605,6 @@ function secondary_demod_waterfall_add(data) { if (secondary_demod_current_canvas_actual_line < 0) secondary_demod_swap_canvases(); } -var secondary_demod_canvases_initialized = false; - -secondary_demod_listbox_updating = false; - function secondary_demod_listbox_changed() { if (secondary_demod_listbox_updating) return; var sdm = $("#openwebrx-secondary-demod-listbox")[0].value; @@ -2762,35 +2613,27 @@ function secondary_demod_listbox_changed() { } else { demodulator_digital_replace(sdm); } - update_dial_button(); } function secondary_demod_listbox_update() { secondary_demod_listbox_updating = true; $("#openwebrx-secondary-demod-listbox").val((secondary_demod) ? secondary_demod : "none"); - console.log("update"); secondary_demod_listbox_updating = false; } -secondary_demod_channel_freq = 1000; - function secondary_demod_update_marker() { var width = Math.max((secondary_bw / (if_samp_rate / 2)) * secondary_demod_canvas_width, 5); var center_at = (secondary_demod_channel_freq / (if_samp_rate / 2)) * secondary_demod_canvas_width + secondary_demod_canvas_left; var left = center_at - width / 2; - //console.log("sdum", width, left); $("#openwebrx-digimode-select-channel").width(width).css("left", left + "px") } -secondary_demod_waiting_for_set = false; - function secondary_demod_update_channel_freq_from_event(evt) { if (typeof evt !== "undefined") { var relativeX = (evt.offsetX) ? evt.offsetX : evt.layerX; secondary_demod_channel_freq = secondary_demod_low_cut + (relativeX / $(secondary_demod_canvas_container).width()) * (secondary_demod_high_cut - secondary_demod_low_cut); } - //console.log("toset:", secondary_demod_channel_freq); if (!secondary_demod_waiting_for_set) { secondary_demod_waiting_for_set = true; window.setTimeout(function () { @@ -2798,7 +2641,6 @@ function secondary_demod_update_channel_freq_from_event(evt) { "type": "dspcontrol", "params": {"secondary_offset_freq": Math.floor(secondary_demod_channel_freq)} })); - //console.log("doneset:", secondary_demod_channel_freq); secondary_demod_waiting_for_set = false; }, 50 @@ -2808,8 +2650,6 @@ function secondary_demod_update_channel_freq_from_event(evt) { secondary_demod_update_marker(); } -secondary_demod_mousedown = false; - function secondary_demod_canvas_container_mousein() { $("#openwebrx-digimode-select-channel").css("opacity", "0.7"); //.css("border-width", "1px"); } @@ -2838,7 +2678,7 @@ function secondary_demod_waterfall_set_zoom(low_cut, high_cut) { var hctmp = high_cut; var lctmp = low_cut; low_cut = -hctmp; - low_cut = -lctmp; + high_cut = -lctmp; } else if (low_cut < 0 && high_cut > 0) { high_cut = Math.max(Math.abs(high_cut), Math.abs(low_cut)); @@ -2858,6 +2698,6 @@ function secondary_demod_waterfall_set_zoom(low_cut, high_cut) { } function sdr_profile_changed() { - value = $('#openwebrx-sdr-profiles-listbox').val(); + var value = $('#openwebrx-sdr-profiles-listbox').val(); ws.send(JSON.stringify({type: "selectprofile", params: {profile: value}})); }