From 72062c8570a24f8db0ccc03cc5c232f2bd68d74e Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Wed, 16 Oct 2019 13:17:47 +0200 Subject: [PATCH] let's apply some formatting --- htdocs/openwebrx.js | 4044 +++++++++++++++++++++---------------------- 1 file changed, 1926 insertions(+), 2118 deletions(-) diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index a0f9129..a45b2e5 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -21,34 +21,25 @@ */ -is_firefox=navigator.userAgent.indexOf("Firefox")!=-1; +is_firefox = navigator.userAgent.indexOf("Firefox") >= 0; function arrayBufferToString(buf) { - //http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers - return String.fromCharCode.apply(null, new Uint8Array(buf)); -} - -function getFirstChars(buf, num) -{ - var u8buf=new Uint8Array(buf); - var output=String(); - num=Math.min(num,u8buf.length); - for(i=0;i=parseInt(wfmax.value)) - { - if(!which) wfmin.value=(parseInt(wfmax.value)-1).toString(); - else wfmax.value=(parseInt(wfmin.value)+1).toString(); - } - waterfall_min_level=parseInt(wfmin.value); - waterfall_max_level=parseInt(wfmax.value); -} -function waterfallColorsDefault() -{ - waterfall_min_level=waterfall_min_level_default; - waterfall_max_level=waterfall_max_level_default; - e("openwebrx-waterfall-color-min").value=waterfall_min_level.toString(); - e("openwebrx-waterfall-color-max").value=waterfall_max_level.toString(); +function zoomOutOneStep() { + zoom_set(zoom_level - 1); } -function waterfallColorsAuto() -{ - e("openwebrx-waterfall-color-min").value=(waterfall_measure_minmax_min-waterfall_auto_level_margin[0]).toString(); - e("openwebrx-waterfall-color-max").value=(waterfall_measure_minmax_max+waterfall_auto_level_margin[1]).toString(); - updateWaterfallColors(0); +function zoomInTotal() { + zoom_set(zoom_levels.length - 1); } -function setSmeterRelativeValue(value) -{ - if(value<0) value=0; - if(value>1.0) value=1.0; - 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)"; - bar.style.background=(value>0.9)?bgRed:((value>0.7)?bgYellow:bgGreen); - //bar.style.backgroundColor=(value>0.9)?"#ff5939":((value>0.7)?"#fff720":"#22ff2f"); +function zoomOutTotal() { + zoom_set(0); } -function getLogSmeterValue(value) -{ - return 10*Math.log10(value); +function setSquelchToAuto() { + e("openwebrx-panel-squelch").value = (getLogSmeterValue(smeter_level) + 10).toString(); + updateSquelch(); } -function getLinearSmeterValue(db_value) -{ - return Math.pow(10,db_value/10); +function updateSquelch() { + var sliderValue = parseInt(e("openwebrx-panel-squelch").value); + var outputValue = (sliderValue === parseInt(e("openwebrx-panel-squelch").min)) ? 0 : getLinearSmeterValue(sliderValue); + ws.send(JSON.stringify({"type": "dspcontrol", "params": {"squelch_level": outputValue}})); +} + +function updateWaterfallColors(which) { + wfmax = e("openwebrx-waterfall-color-max"); + wfmin = e("openwebrx-waterfall-color-min"); + if (parseInt(wfmin.value) >= parseInt(wfmax.value)) { + if (!which) wfmin.value = (parseInt(wfmax.value) - 1).toString(); + else wfmax.value = (parseInt(wfmin.value) + 1).toString(); + } + waterfall_min_level = parseInt(wfmin.value); + waterfall_max_level = parseInt(wfmax.value); +} + +function waterfallColorsDefault() { + waterfall_min_level = waterfall_min_level_default; + waterfall_max_level = waterfall_max_level_default; + e("openwebrx-waterfall-color-min").value = waterfall_min_level.toString(); + e("openwebrx-waterfall-color-max").value = waterfall_max_level.toString(); +} + +function waterfallColorsAuto() { + e("openwebrx-waterfall-color-min").value = (waterfall_measure_minmax_min - waterfall_auto_level_margin[0]).toString(); + e("openwebrx-waterfall-color-max").value = (waterfall_measure_minmax_max + waterfall_auto_level_margin[1]).toString(); + updateWaterfallColors(0); +} + +function setSmeterRelativeValue(value) { + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + 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)"; + bar.style.background = (value > 0.9) ? bgRed : ((value > 0.7) ? bgYellow : bgGreen); +} + +function getLogSmeterValue(value) { + return 10 * Math.log10(value); +} + +function getLinearSmeterValue(db_value) { + return Math.pow(10, db_value / 10); } function setSmeterAbsoluteValue(value) //the value that comes from `csdr squelch_and_smeter_cc` { - var logValue=getLogSmeterValue(value); - var lowLevel=waterfall_min_level-20; - var highLevel=waterfall_max_level+20; - var percent=(logValue-lowLevel)/(highLevel-lowLevel); - setSmeterRelativeValue(percent); - e("openwebrx-smeter-db").innerHTML=logValue.toFixed(1)+" dB"; + var logValue = getLogSmeterValue(value); + var lowLevel = waterfall_min_level - 20; + var highLevel = waterfall_max_level + 20; + var percent = (logValue - lowLevel) / (highLevel - lowLevel); + setSmeterRelativeValue(percent); + e("openwebrx-smeter-db").innerHTML = logValue.toFixed(1) + " dB"; } -function typeInAnimation(element,timeout,what,onFinish) -{ - if(!what) { onFinish(); return; } - element.innerHTML+=what[0]; - window.setTimeout( function(){typeInAnimation(element,timeout,what.substring(1),onFinish);}, timeout ); +function typeInAnimation(element, timeout, what, onFinish) { + if (!what) { + onFinish(); + return; + } + element.innerHTML += what[0]; + window.setTimeout(function () { + typeInAnimation(element, timeout, what.substring(1), onFinish); + }, timeout); } - // ======================================================== // ================= ANIMATION ROUTINES ================= // ======================================================== -function animate(object,style_name,unit,from,to,accel,time_ms,fps,to_exec) -{ - //console.log(object.className); - 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); - if(typeof object.anim_timer!="undefined") { window.clearInterval(object.anim_timer); } - object.anim_timer=window.setInterval( - function(){ - if(object.anim_i++9||unit!="px") new_val=(to+accel*remain); - else {if(Math.abs(remain)<2) new_val=to; - else new_val=to+remain-(remain/Math.abs(remain));} - object.style[style_name]=new_val.toString()+unit; - } - } - else - {object.style[style_name]=to.toString()+unit; window.clearInterval(object.anim_timer); delete object.anim_timer; } - if(to_exec!=0) to_exec(); - },1000/fps); +function animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exec) { + //console.log(object.className); + 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); + if (typeof object.anim_timer !== "undefined") { + window.clearInterval(object.anim_timer); + } + object.anim_timer = window.setInterval( + function () { + 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; + if (Math.abs(remain) > 9 || unit !== "px") new_val = (to + accel * remain); + else { + if (Math.abs(remain) < 2) new_val = to; + else new_val = to + remain - (remain / Math.abs(remain)); + } + object.style[style_name] = new_val.toString() + unit; + } + } + else { + object.style[style_name] = to.toString() + unit; + window.clearInterval(object.anim_timer); + delete object.anim_timer; + } + if (to_exec !== 0) to_exec(); + }, 1000 / fps); } -function animate_to(object,style_name,unit,to,accel,time_ms,fps,to_exec) -{ - from=parseFloat(style_value(object,style_name)); - animate(object,style_name,unit,from,to,accel,time_ms,fps,to_exec); +function animate_to(object, style_name, unit, to, accel, time_ms, fps, to_exec) { + from = parseFloat(style_value(object, style_name)); + animate(object, style_name, unit, from, to, accel, time_ms, fps, to_exec); } @@ -279,245 +291,239 @@ function animate_to(object,style_name,unit,to,accel,time_ms,fps,to_exec) // ================ DEMODULATOR ROUTINES ================ // ======================================================== -demodulators=[] +demodulators = []; -demodulator_color_index=0; -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++]); +demodulator_color_index = 0; +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). - // Envelope is drawn on the scale canvas. - // 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; - //range=get_visible_freq_range(); - from_px=scale_px_from_freq(from,range); - to_px=scale_px_from_freq(to,range); - if(to_pxwindow.innerWidth)) // out of screen? - { - drag_ranges.beginning={x1:from_px, x2: from_px+env_bounding_line_w+env_att_w}; - drag_ranges.ending={x1:to_px-env_bounding_line_w-env_att_w, x2: to_px}; - drag_ranges.whole_envelope={x1:from_px, x2: to_px}; - drag_ranges.envelope_on_screen=true; - scale_ctx.beginPath(); - scale_ctx.moveTo(from_px,env_h1); - scale_ctx.lineTo(from_px+env_bounding_line_w, env_h1); - scale_ctx.lineTo(from_px+env_bounding_line_w+env_att_w, env_h2); - scale_ctx.lineTo(to_px-env_bounding_line_w-env_att_w, env_h2); - scale_ctx.lineTo(to_px-env_bounding_line_w, env_h1); - scale_ctx.lineTo(to_px, env_h1); - scale_ctx.globalAlpha = 0.3; - scale_ctx.fill(); - scale_ctx.globalAlpha = 1; - scale_ctx.stroke(); - } - if(typeof line != "undefined") // out of screen? - { - 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; - scale_ctx.moveTo(line_px,env_h1+env_lineplus); - scale_ctx.lineTo(line_px,env_h2-env_lineplus); - scale_ctx.stroke(); - } - } - return drag_ranges; + from_px -= (env_att_w + env_bounding_line_w); + to_px += (env_att_w + env_bounding_line_w); + // do drawing: + scale_ctx.lineWidth = 3; + scale_ctx.strokeStyle = color; + scale_ctx.fillStyle = color; + var drag_ranges = {envelope_on_screen: false, line_on_screen: false}; + if (!(to_px < 0 || from_px > window.innerWidth)) // out of screen? + { + drag_ranges.beginning = {x1: from_px, x2: from_px + env_bounding_line_w + env_att_w}; + drag_ranges.ending = {x1: to_px - env_bounding_line_w - env_att_w, x2: to_px}; + drag_ranges.whole_envelope = {x1: from_px, x2: to_px}; + drag_ranges.envelope_on_screen = true; + scale_ctx.beginPath(); + scale_ctx.moveTo(from_px, env_h1); + scale_ctx.lineTo(from_px + env_bounding_line_w, env_h1); + scale_ctx.lineTo(from_px + env_bounding_line_w + env_att_w, env_h2); + scale_ctx.lineTo(to_px - env_bounding_line_w - env_att_w, env_h2); + scale_ctx.lineTo(to_px - env_bounding_line_w, env_h1); + scale_ctx.lineTo(to_px, env_h1); + scale_ctx.globalAlpha = 0.3; + scale_ctx.fill(); + scale_ctx.globalAlpha = 1; + scale_ctx.stroke(); + } + if (typeof line !== "undefined") // out of screen? + { + 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; + scale_ctx.moveTo(line_px, env_h1 + env_lineplus); + scale_ctx.lineTo(line_px, env_h2 - env_lineplus); + scale_ctx.stroke(); + } + } + return drag_ranges; } -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) { return range.x1<=x&&range.x2>=x; } - dr=demodulator.draggable_ranges; +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) { + return range.x1 <= x && range.x2 >= x; + }; + dr = demodulator.draggable_ranges; - if(key_modifiers.shiftKey) - { - //Check first: shift + center drag emulates BFO knob - if(drag_ranges.line_on_screen&&in_range(x,drag_ranges.line)) return dr.bfo; - //Check second: shift + envelope drag emulates PBF knob - if(drag_ranges.envelope_on_screen&&in_range(x,drag_ranges.whole_envelope)) return dr.pbs; - } - if(drag_ranges.envelope_on_screen) - { - // For low and high cut: - if(in_range(x,drag_ranges.beginning)) return dr.beginning; - if(in_range(x,drag_ranges.ending)) return dr.ending; - // Last priority: having clicked anything else on the envelope, without holding the shift key - if(in_range(x,drag_ranges.whole_envelope)) return dr.anything_else; - } - return dr.none; //User doesn't drag the envelope for this demodulator + if (key_modifiers.shiftKey) { + //Check first: shift + center drag emulates BFO knob + if (drag_ranges.line_on_screen && in_range(x, drag_ranges.line)) return dr.bfo; + //Check second: shift + envelope drag emulates PBF knob + if (drag_ranges.envelope_on_screen && in_range(x, drag_ranges.whole_envelope)) return dr.pbs; + } + if (drag_ranges.envelope_on_screen) { + // For low and high cut: + if (in_range(x, drag_ranges.beginning)) return dr.beginning; + if (in_range(x, drag_ranges.ending)) return dr.ending; + // Last priority: having clicked anything else on the envelope, without holding the shift key + if (in_range(x, drag_ranges.whole_envelope)) return dr.anything_else; + } + 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) -{ - //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(){}; +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={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.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; +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) -{ - //console.log("hopefully this happens"); - //http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain - demodulator.call(this,offset_frequency); - this.subtype=subtype; - this.filter={ - min_passband: 100, - high_cut_limit: (audio_server_output_rate/2)-1, //audio_context.sampleRate/2, - low_cut_limit: (-audio_server_output_rate/2)+1 //-audio_context.sampleRate/2 - }; - //Subtypes only define some filter parameters and the mod string sent to server, - //so you may set these parameters in your custom child class. - //Why? As of demodulation is done on the server, difference is mainly on the server side. - this.server_mod=subtype; - if(subtype=="lsb") - { - this.low_cut=-3000; - this.high_cut=-300; - this.server_mod="ssb"; - } - else if(subtype=="usb") - { - this.low_cut=300; - this.high_cut=3000; - this.server_mod="ssb"; - } - else if(subtype=="cw") - { - this.low_cut=700; - this.high_cut=900; - this.server_mod="ssb"; - } - else if(subtype=="nfm") - { - this.low_cut=-4000; - this.high_cut=4000; - } - else if(subtype=="dmr" || subtype=="ysf") - { - this.low_cut=-4000; - this.high_cut=4000; - } - else if(subtype=="dstar" || subtype=="nxdn") - { - this.low_cut=-3250; - this.high_cut=3250; +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); + this.subtype = subtype; + this.filter = { + min_passband: 100, + high_cut_limit: (audio_server_output_rate / 2) - 1, //audio_context.sampleRate/2, + low_cut_limit: (-audio_server_output_rate / 2) + 1 //-audio_context.sampleRate/2 + }; + //Subtypes only define some filter parameters and the mod string sent to server, + //so you may set these parameters in your custom child class. + //Why? As of demodulation is done on the server, difference is mainly on the server side. + this.server_mod = subtype; + if (subtype === "lsb") { + this.low_cut = -3000; + this.high_cut = -300; + this.server_mod = "ssb"; + } + else if (subtype === "usb") { + this.low_cut = 300; + this.high_cut = 3000; + this.server_mod = "ssb"; + } + else if (subtype === "cw") { + this.low_cut = 700; + this.high_cut = 900; + this.server_mod = "ssb"; + } + else if (subtype === "nfm") { + this.low_cut = -4000; + this.high_cut = 4000; + } + else if (subtype === "dmr" || subtype === "ysf") { + this.low_cut = -4000; + this.high_cut = 4000; + } + else if (subtype === "dstar" || subtype === "nxdn") { + this.low_cut = -3250; + this.high_cut = 3250; + } + else if (subtype === "am") { + this.low_cut = -4000; + this.high_cut = 4000; } - else if(subtype=="am") - { - this.low_cut=-4000; - this.high_cut=4000; - } - 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; - 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.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; + 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 - params = { - "low_cut": this.low_cut, - "high_cut": this.high_cut, - "offset_freq": this.offset_frequency - }; - if (first_time) params.mod = this.server_mod; - ws.send(JSON.stringify({"type":"dspcontrol","params":params})); - } - this.doset(true); //we set parameters on object creation + this.doset = function (first_time) { //this function sends demodulator parameters to the server + params = { + "low_cut": this.low_cut, + "high_cut": this.high_cut, + "offset_freq": this.offset_frequency + }; + if (first_time) params.mod = this.server_mod; + ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); + }; + this.doset(true); //we set parameters on object creation - //******* envelope object ******* - // for drawing the filter envelope above scale - this.envelope.parent=this; + //******* 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.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; + 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; - }; + // 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; + }; - this.envelope.drag_move=function(x) - { - dr=demodulator.draggable_ranges; - 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) + this.envelope.drag_move = function (x) { + dr = demodulator.draggable_ranges; + 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; @@ -525,110 +531,99 @@ function demodulator_default_analog(offset_frequency,subtype) } var new_value;*/ - //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; - //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.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.high_cut_limit) return true; - //nor the filter passband be too small - if(new_value-this.parent.low_cutbandwidth/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: - e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",center_freq+this.parent.offset_frequency,1e6,4); - return true; - }; + //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; + //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.low_cut_limit) 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.high_cut_limit) 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: + e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", center_freq + this.parent.offset_frequency, 1e6, 4); + 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. - 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; - return to_return; - }; + 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. + 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; + return to_return; + }; } -demodulator_default_analog.prototype=new demodulator(); +demodulator_default_analog.prototype = new demodulator(); function mkenvelopes(visible_range) //called from mkscale { - scale_ctx.clearRect(0,0,scale_ctx.canvas.width,22); //clear the upper part of the canvas (where filter envelopes reside) - for (var i=0;ibandwidth/2||to_what<-bandwidth/2) return; - demodulators[0].offset_frequency=Math.round(to_what); - demodulators[0].set(); - mkenvelopes(get_visible_freq_range()); +function demodulator_set_offset_frequency(which, to_what) { + if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return; + demodulators[0].offset_frequency = Math.round(to_what); + demodulators[0].set(); + mkenvelopes(get_visible_freq_range()); $("#webrx-actual-freq").html(format_frequency("{x} MHz", center_freq + to_what, 1e6, 4)); } @@ -640,273 +635,260 @@ function demodulator_set_offset_frequency(which,to_what) var scale_ctx; var scale_canvas; -function scale_setup() -{ - e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",canvas_get_frequency(window.innerWidth/2),1e6,4); - scale_canvas=e("openwebrx-scale-canvas"); - scale_ctx=scale_canvas.getContext("2d"); - scale_canvas.addEventListener("mousedown", scale_canvas_mousedown, false); - scale_canvas.addEventListener("mousemove", scale_canvas_mousemove, false); - scale_canvas.addEventListener("mouseup", scale_canvas_mouseup, false); - resize_scale(); - var frequency_container = e("openwebrx-frequency-container"); - frequency_container.addEventListener("mousemove", frequency_container_mousemove, false); +function scale_setup() { + e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", canvas_get_frequency(window.innerWidth / 2), 1e6, 4); + scale_canvas = e("openwebrx-scale-canvas"); + scale_ctx = scale_canvas.getContext("2d"); + scale_canvas.addEventListener("mousedown", scale_canvas_mousedown, false); + scale_canvas.addEventListener("mousemove", scale_canvas_mousemove, false); + scale_canvas.addEventListener("mouseup", scale_canvas_mouseup, false); + resize_scale(); + var frequency_container = e("openwebrx-frequency-container"); + frequency_container.addEventListener("mousemove", frequency_container_mousemove, false); } -var scale_canvas_drag_params={ - mouse_down: false, - drag: false, - start_x: 0, - key_modifiers: {shiftKey:false, altKey: false, ctrlKey: false} +var scale_canvas_drag_params = { + mouse_down: false, + drag: false, + start_x: 0, + key_modifiers: {shiftKey: false, altKey: false, ctrlKey: false} }; -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; - } - evt.preventDefault(); +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; + } + evt.preventDefault(); } -function scale_offset_freq_from_px(x, visible_range) -{ - if(typeof visible_range === "undefined") visible_range=get_visible_freq_range(); - return (visible_range.start+visible_range.bw*(x/canvas_container.clientWidth))-center_freq; +function scale_offset_freq_from_px(x, visible_range) { + if (typeof visible_range === "undefined") visible_range = get_visible_freq_range(); + return (visible_range.start + visible_range.bw * (x / canvas_container.clientWidth)) - center_freq; } -function scale_canvas_mousemove(evt) -{ - var event_handled; - 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 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); + 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); + if (!event_handled) demodulator_set_offset_frequency(0, scale_offset_freq_from_px(evt.pageX)); + } } function frequency_container_mousemove(evt) { - var frequency = center_freq + scale_offset_freq_from_px(evt.pageX); + var frequency = center_freq + scale_offset_freq_from_px(evt.pageX); e("webrx-mouse-freq").innerHTML = format_frequency("{x} MHz", frequency, 1e6, 4); } -function scale_canvas_end_drag(x) -{ - scale_canvas.style.cursor="default"; - scale_canvas_drag_params.drag=false; - scale_canvas_drag_params.mouse_down=false; - var event_handled=false; - for (var i=0;i=scale_min_space_bw_small_markers&&freq.toString()[0]!="5") {out.small/=2; out.ratio*=2; } - out.smallbw=freq/out.ratio; - return true; - } - for(i=scale_markers_levels.length-1;i>=0;i--) - { - mp=scale_markers_levels[i]; - if (!fcalc(mp.large_marker_per_hz)) continue; - //console.log(mp.large_marker_per_hz); - //console.log(out); - if (out.large-mp.estimated_text_width>scale_min_space_bw_texts) break; - } - out.params=mp; - return out; +function get_scale_mark_spacing(range) { + out = {}; + 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 + out.small = out.large / out.ratio; //distance between small markers + if (out.small < scale_min_space_bw_small_markers) return false; + if (out.small / 2 >= scale_min_space_bw_small_markers && freq.toString()[0] !== "5") { + out.small /= 2; + out.ratio *= 2; + } + out.smallbw = freq / out.ratio; + return true; + }; + for (i = scale_markers_levels.length - 1; i >= 0; i--) { + mp = scale_markers_levels[i]; + if (!fcalc(mp.large_marker_per_hz)) continue; + //console.log(mp.large_marker_per_hz); + //console.log(out); + if (out.large - mp.estimated_text_width > scale_min_space_bw_texts) break; + } + out.params = mp; + return out; } -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(); - mkenvelopes(range); //when scale changes we will always have to redraw filter envelopes, too - scale_ctx.clearRect(0,22,scale_ctx.canvas.width,scale_ctx.canvas.height-22); - scale_ctx.strokeStyle = "#fff"; - scale_ctx.font = "bold 11px sans-serif"; - scale_ctx.textBaseline = "top"; - scale_ctx.fillStyle = "#fff"; - 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 ftext=function(f) {text_to_draw=format_frequency(spacing.params.format,f,spacing.params.pre_divide,spacing.params.decimals);} - var last_large; - for(;;) - { - var x=scale_px_from_freq(marker_hz,range); - if(x>window.innerWidth) break; - scale_ctx.beginPath(); - scale_ctx.moveTo(x, 22); - if(marker_hz%spacing.params.large_marker_per_hz==0) - { //large marker - if(typeof first_large == "undefined") var first_large=marker_hz; - last_large=marker_hz; - scale_ctx.lineWidth=3.5; - scale_ctx.lineTo(x,22+11); - ftext(marker_hz); - var text_measured=scale_ctx.measureText(text_to_draw); - scale_ctx.textAlign = "center"; - //advanced text drawing begins - if( zoom_level==0 && (range.start+spacing.smallbw*spacing.ratio>marker_hz) && (x=scale_min_space_bw_texts) - { //and if we have enough space to draw it correctly without clipping - scale_ctx.textAlign = "left"; - scale_ctx.fillText(text_to_draw, 0, text_h_pos); - } - } - else if( zoom_level==0 && (range.end-spacing.smallbw*spacing.ratiowindow.innerWidth-text_measured.width/2) ) - { // if this is the last overall marker when zoomed out... and if it would be clipped off the screen... - if(window.innerWidth-text_measured.width-scale_px_from_freq(marker_hz-spacing.smallbw*spacing.ratio,range)>=scale_min_space_bw_texts) - { //and if we have enough space to draw it correctly without clipping - scale_ctx.textAlign = "right"; - scale_ctx.fillText(text_to_draw, window.innerWidth, text_h_pos); - } - } - else scale_ctx.fillText(text_to_draw, x, text_h_pos); //draw text normally - } - else - { //small marker - scale_ctx.lineWidth=2; - scale_ctx.lineTo(x,22+8); - } - marker_hz+=spacing.smallbw; - scale_ctx.stroke(); - } - if(zoom_level!=0) - { // if zoomed, we don't want the texts to disappear because their markers can't be seen - // on the left side - scale_ctx.textAlign = "center"; - var f=first_large-spacing.smallbw*spacing.ratio; - var 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); - // on the right side - f=last_large+spacing.smallbw*spacing.ratio; - x=scale_px_from_freq(f,range); - ftext(f); - w=scale_ctx.measureText(text_to_draw).width; - if(x-w/2 window.innerWidth) break; + scale_ctx.beginPath(); + scale_ctx.moveTo(x, 22); + if (marker_hz % spacing.params.large_marker_per_hz === 0) { //large marker + if (typeof first_large === "undefined") var first_large = marker_hz; + last_large = marker_hz; + scale_ctx.lineWidth = 3.5; + scale_ctx.lineTo(x, 22 + 11); + ftext(marker_hz); + var text_measured = scale_ctx.measureText(text_to_draw); + scale_ctx.textAlign = "center"; + //advanced text drawing begins + if (zoom_level === 0 && (range.start + spacing.smallbw * spacing.ratio > marker_hz) && (x < text_measured.width / 2)) { //if this is the first overall marker when zoomed out... and if it would be clipped off the screen... + if (scale_px_from_freq(marker_hz + spacing.smallbw * spacing.ratio, range) - text_measured.width >= scale_min_space_bw_texts) { //and if we have enough space to draw it correctly without clipping + scale_ctx.textAlign = "left"; + scale_ctx.fillText(text_to_draw, 0, text_h_pos); + } + } + else if (zoom_level === 0 && (range.end - spacing.smallbw * spacing.ratio < marker_hz) && (x > window.innerWidth - text_measured.width / 2)) { // if this is the last overall marker when zoomed out... and if it would be clipped off the screen... + if (window.innerWidth - text_measured.width - scale_px_from_freq(marker_hz - spacing.smallbw * spacing.ratio, range) >= scale_min_space_bw_texts) { //and if we have enough space to draw it correctly without clipping + scale_ctx.textAlign = "right"; + scale_ctx.fillText(text_to_draw, window.innerWidth, text_h_pos); + } + } + else scale_ctx.fillText(text_to_draw, x, text_h_pos); //draw text normally + } + else { //small marker + scale_ctx.lineWidth = 2; + scale_ctx.lineTo(x, 22 + 8); + } + marker_hz += spacing.smallbw; + scale_ctx.stroke(); + } + if (zoom_level !== 0) { // if zoomed, we don't want the texts to disappear because their markers can't be seen + // on the left side + scale_ctx.textAlign = "center"; + var f = first_large - spacing.smallbw * spacing.ratio; + var 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); + // on the right side + f = last_large + spacing.smallbw * spacing.ratio; + x = scale_px_from_freq(f, range); + ftext(f); + w = scale_ctx.measureText(text_to_draw).width; + if (x - w / 2 < window.innerWidth) scale_ctx.fillText(text_to_draw, x, 22 + 10); + } } -function resize_scale() -{ +function resize_scale() { ratio = window.devicePixelRatio || 1; var w = window.innerWidth; var h = 47; @@ -914,22 +896,20 @@ function resize_scale() scale_canvas.style.height = h + "px"; w *= ratio; h *= ratio; - scale_canvas.width = w; + scale_canvas.width = w; scale_canvas.height = h; scale_ctx.scale(ratio, ratio); - mkscale(); - bookmarks.position(); + mkscale(); + bookmarks.position(); } -function canvas_get_freq_offset(relativeX) -{ - rel=(relativeX/canvases[0].clientWidth); - return Math.round((bandwidth*rel)-(bandwidth/2)); +function canvas_get_freq_offset(relativeX) { + rel = (relativeX / canvases[0].clientWidth); + return Math.round((bandwidth * rel) - (bandwidth / 2)); } -function canvas_get_frequency(relativeX) -{ - return center_freq+canvas_get_freq_offset(relativeX); +function canvas_get_frequency(relativeX) { + return center_freq + canvas_get_freq_offset(relativeX); } /*function canvas_format_frequency(relativeX) @@ -937,241 +917,218 @@ function canvas_get_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; - while(decimals>3) - { - out=out.substr(0,at)+","+out.substr(at); - at+=4; - decimals-=3; - } - return out; +function format_frequency(format, freq_hz, pre_divide, decimals) { + out = format.replace("{x}", (freq_hz / pre_divide).toFixed(decimals)); + at = out.indexOf(".") + 4; + while (decimals > 3) { + out = out.substr(0, at) + "," + out.substr(at); + at += 4; + decimals -= 3; + } + return out; } -canvas_drag=false; -canvas_drag_min_delta=1; -canvas_mouse_down=false; +canvas_drag = false; +canvas_drag_min_delta = 1; +canvas_mouse_down = false; -function canvas_mousedown(evt) -{ - canvas_mouse_down=true; - canvas_drag=false; - canvas_drag_last_x=canvas_drag_start_x=evt.pageX; - canvas_drag_last_y=canvas_drag_start_y=evt.pageY; - evt.preventDefault(); //don't show text selection mouse pointer +function canvas_mousedown(evt) { + canvas_mouse_down = true; + canvas_drag = false; + canvas_drag_last_x = canvas_drag_start_x = evt.pageX; + canvas_drag_last_y = canvas_drag_start_y = evt.pageY; + evt.preventDefault(); //don't show text selection mouse pointer } -function canvas_mousemove(evt) -{ - if(!waterfall_setup_done) return; - 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; - canvas_container.style.cursor="move"; - } - 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)) && - !(zoom_center_rel+dpx<-bandwidth/2+canvas_container.clientWidth*zoom_center_where*range.hps) - ) { zoom_center_rel+=dpx; } - resize_canvases(false); - canvas_drag_last_x=evt.pageX; - canvas_drag_last_y=evt.pageY; - mkscale(); - bookmarks.position(); - } - } - else e("webrx-mouse-freq").innerHTML=format_frequency("{x} MHz",canvas_get_frequency(relativeX),1e6,4); +function canvas_mousemove(evt) { + if (!waterfall_setup_done) return; + 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; + canvas_container.style.cursor = "move"; + } + 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)) && + !(zoom_center_rel + dpx < -bandwidth / 2 + canvas_container.clientWidth * zoom_center_where * range.hps) + ) { + zoom_center_rel += dpx; + } + resize_canvases(false); + canvas_drag_last_x = evt.pageX; + canvas_drag_last_y = evt.pageY; + mkscale(); + bookmarks.position(); + } + } + else e("webrx-mouse-freq").innerHTML = format_frequency("{x} MHz", canvas_get_frequency(relativeX), 1e6, 4); } -function canvas_container_mouseleave(evt) -{ - canvas_end_drag(); +function canvas_container_mouseleave(evt) { + canvas_end_drag(); } -function canvas_mouseup(evt) -{ - if(!waterfall_setup_done) return; - relativeX = get_relative_x(evt); +function canvas_mouseup(evt) { + if (!waterfall_setup_done) return; + relativeX = get_relative_x(evt); - if(!canvas_drag) - { - demodulator_set_offset_frequency(0, canvas_get_freq_offset(relativeX)); - } - else - { - canvas_end_drag(); - } - canvas_mouse_down=false; + if (!canvas_drag) { + demodulator_set_offset_frequency(0, canvas_get_freq_offset(relativeX)); + } + else { + canvas_end_drag(); + } + canvas_mouse_down = false; } -function canvas_end_drag() -{ - canvas_container.style.cursor="crosshair"; - canvas_mouse_down=false; +function canvas_end_drag() { + canvas_container.style.cursor = "crosshair"; + canvas_mouse_down = false; } -function zoom_center_where_calc(screenposX) -{ - //return (screenposX-(window.innerWidth-canvas_container.clientWidth))/canvas_container.clientWidth; - return screenposX/canvas_container.clientWidth; +function zoom_center_where_calc(screenposX) { + //return (screenposX-(window.innerWidth-canvas_container.clientWidth))/canvas_container.clientWidth; + return screenposX / canvas_container.clientWidth; } function get_relative_x(evt) { - var relativeX = (evt.offsetX)?evt.offsetX:evt.layerX; + var relativeX = (evt.offsetX) ? evt.offsetX : evt.layerX; if ($(evt.target).closest(canvas_container).length) return relativeX; - // compensate for the frequency scale, since that is not resized by the browser. + // compensate for the frequency scale, since that is not resized by the browser. return relativeX - zoom_offset_px; } -function canvas_mousewheel(evt) -{ - if(!waterfall_setup_done) return; - var relativeX = get_relative_x(evt); - var dir=(evt.deltaY/Math.abs(evt.deltaY))>0; - zoom_step(dir, relativeX, zoom_center_where_calc(evt.pageX)); - evt.preventDefault(); +function canvas_mousewheel(evt) { + if (!waterfall_setup_done) return; + var relativeX = get_relative_x(evt); + var dir = (evt.deltaY / Math.abs(evt.deltaY)) > 0; + zoom_step(dir, relativeX, zoom_center_where_calc(evt.pageX)); + evt.preventDefault(); } -zoom_max_level_hps=33; //Hz/pixel -zoom_levels_count=14; +zoom_max_level_hps = 33; //Hz/pixel +zoom_levels_count = 14; -function get_zoom_coeff_from_hps(hps) -{ - var shown_bw=(window.innerWidth*hps); - return bandwidth/shown_bw; +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; +zoom_levels = [1]; +zoom_level = 0; +zoom_freq = 0; +zoom_offset_px = 0; +zoom_center_rel = 0; +zoom_center_where = 0; -smeter_level=0; +smeter_level = 0; -function mkzoomlevels() -{ - zoom_levels=[1]; - 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-1)) return; - if(out) --zoom_level; - else ++zoom_level; +function zoom_step(out, where, onscreen) { + if ((out && zoom_level === 0) || (!out && zoom_level >= zoom_levels_count - 1)) return; + if (out) --zoom_level; + else ++zoom_level; - zoom_center_rel=canvas_get_freq_offset(where); - //console.log("zoom_step || zlevel: "+zoom_level.toString()+" zlevel_val: "+zoom_levels[zoom_level].toString()+" zoom_center_rel: "+zoom_center_rel.toString()); - zoom_center_where=onscreen; - //console.log(zoom_center_where, zoom_center_rel, where); - resize_canvases(true); - mkscale(); - bookmarks.position(); + zoom_center_rel = canvas_get_freq_offset(where); + //console.log("zoom_step || zlevel: "+zoom_level.toString()+" zlevel_val: "+zoom_levels[zoom_level].toString()+" zoom_center_rel: "+zoom_center_rel.toString()); + zoom_center_where = onscreen; + //console.log(zoom_center_where, zoom_center_rel, where); + resize_canvases(true); + mkscale(); + bookmarks.position(); } -function zoom_set(level) -{ - if(!(level>=0&&level<=zoom_levels.length-1)) return; - level=parseInt(level); - zoom_level = 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_set(level) { + if (!(level >= 0 && level <= zoom_levels.length - 1)) return; + level = parseInt(level); + zoom_level = 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 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; - if(zoom_offset_px 0) zoom_offset_px = 0; + if (zoom_offset_px < winsize - canvases_new_width) + zoom_offset_px = winsize - canvases_new_width; + //console.log("zoom_calc || zopx:"+zoom_offset_px.toString()+ " maxoff:"+(winsize-canvases_new_width).toString()+" relval:"+(0.5+zoom_center_rel/bandwidth).toString() ); } -function resize_waterfall_container(check_init) -{ - if(check_init&&!waterfall_setup_done) return; - var numHeight; - mathbox_container.style.height=canvas_container.style.height=(numHeight=window.innerHeight-e("webrx-top-container").clientHeight-e("openwebrx-scale-container").clientHeight).toString()+"px"; - if(mathbox) - { - //mathbox.three.camera.aspect = document.body.offsetWidth / numHeight; - //mathbox.three.camera.updateProjectionMatrix(); - mathbox.three.renderer.setSize(document.body.offsetWidth, numHeight); - console.log(document.body.offsetWidth, numHeight); - } +function resize_waterfall_container(check_init) { + if (check_init && !waterfall_setup_done) return; + var numHeight; + mathbox_container.style.height = canvas_container.style.height = (numHeight = window.innerHeight - e("webrx-top-container").clientHeight - e("openwebrx-scale-container").clientHeight).toString() + "px"; + if (mathbox) { + //mathbox.three.camera.aspect = document.body.offsetWidth / numHeight; + //mathbox.three.camera.updateProjectionMatrix(); + mathbox.three.renderer.setSize(document.body.offsetWidth, numHeight); + console.log(document.body.offsetWidth, numHeight); + } } -audio_server_output_rate=11025; -audio_client_resampling_factor=4; +audio_server_output_rate = 11025; +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; - while(true) - { - audio_server_output_rate = Math.floor(targetRate / i); - if(audio_server_output_rate < output_range_min) - { - audio_client_resampling_factor = audio_server_output_rate = 0; - divlog("Your audio card sampling rate ("+targetRate.toString()+") is not supported.
Please change your operating system default settings in order to fix this.",1); - } - if(audio_server_output_rate >= output_range_min && audio_server_output_rate <= output_range_max) break; //okay, we're done - i++; - } - audio_client_resampling_factor=i; - console.log("audio_calculate_resampling() :: "+audio_client_resampling_factor.toString()+", "+audio_server_output_rate.toString()); +function audio_calculate_resampling(targetRate) { //both at the server and the client + output_range_max = 12000; + output_range_min = 8000; + i = 1; + while (true) { + audio_server_output_rate = Math.floor(targetRate / i); + if (audio_server_output_rate < output_range_min) { + audio_client_resampling_factor = audio_server_output_rate = 0; + divlog("Your audio card sampling rate (" + targetRate.toString() + ") is not supported.
Please change your operating system default settings in order to fix this.", 1); + } + if (audio_server_output_rate >= output_range_min && audio_server_output_rate <= output_range_max) break; //okay, we're done + i++; + } + audio_client_resampling_factor = i; + console.log("audio_calculate_resampling() :: " + audio_client_resampling_factor.toString() + ", " + audio_server_output_rate.toString()); } -debug_ws_data_received=0; +debug_ws_data_received = 0; debug_ws_time_start = 0; -max_clients_num=0; +max_clients_num = 0; client_num = 0; var currentprofile; -var COMPRESS_FFT_PAD_N=10; //should be the same as in csdr.c +var COMPRESS_FFT_PAD_N = 10; //should be the same as in csdr.c -function on_ws_recv(evt) -{ - if (typeof evt.data == 'string') { +function on_ws_recv(evt) { + if (typeof evt.data === 'string') { // text messages debug_ws_data_received += evt.data.length / 1000; - if (evt.data.substr(0, 16) == "CLIENT DE SERVER") { - divlog("Server acknowledged WebSocket connection."); - } else { - try { - json = JSON.parse(evt.data) - switch (json.type) { + if (evt.data.substr(0, 16) === "CLIENT DE SERVER") { + divlog("Server acknowledged WebSocket connection."); + } else { + try { + json = JSON.parse(evt.data); + switch (json.type) { case "config": config = json.value; window.waterfall_colors = config.waterfall_colors; @@ -1180,136 +1137,136 @@ function on_ws_recv(evt) window.waterfall_auto_level_margin = config.waterfall_auto_level_margin; waterfallColorsDefault(); - window.starting_mod = config.start_mod + 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; - divlog( "FFT stream is "+ ((fft_compression=="adpcm")?"compressed":"uncompressed")+"." ) - 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); + fft_fps = config.fft_fps; + audio_compression = config.audio_compression; + divlog("Audio stream is " + ((audio_compression === "adpcm") ? "compressed" : "uncompressed") + "."); + fft_compression = config.fft_compression; + divlog("FFT stream is " + ((fft_compression === "adpcm") ? "compressed" : "uncompressed") + "."); + 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_frequency_resolution = config.mathbox_waterfall_frequency_resolution; + mathbox_waterfall_history_length = config.mathbox_waterfall_history_length; - waterfall_init(); - audio_preinit(); - bookmarks.loadLocalBookmarks(); + waterfall_init(); + audio_preinit(); + bookmarks.loadLocalBookmarks(); - if (audio_allowed) { - if (audio_initialized) { - initialize_demodulator(); - } else { - audio_init(); - } - } - waterfall_clear(); + if (audio_allowed) { + if (audio_initialized) { + initialize_demodulator(); + } else { + audio_init(); + } + } + waterfall_clear(); currentprofile = config.profile_id; - $('#openwebrx-sdr-profiles-listbox').val(currentprofile); - break; + $('#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; secondary_demod_init_canvases(); - break; + 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; - break; + break; case "smeter": smeter_level = json.value; setSmeterAbsoluteValue(smeter_level); - break; + break; case "cpuusage": - 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; + 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; - progressbar_set(e("openwebrx-bar-clients"), client_num / max_clients_num, "Clients [" + client_num + "]", client_num > max_clients_num*0.85); - break; + 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){ + 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"](); - } - break; - case "metadata": - update_metadata(json.value); - break; - case "wsjt_message": - update_wsjt_panel(json.value); - break; - case "dial_frequencies": - var as_bookmarks = json.value.map(function(d){ - return { - 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); - break; - case "bookmarks": - bookmarks.replace_bookmarks(json.value, "server"); - break; - case "sdr_error": - divlog(json.value, true); - break; + $('#openwebrx-sdr-profiles-listbox').val(currentprofile); + } + break; + case "features": + for (var feature in json.value) { + $('[data-feature="' + feature + '"')[json.value[feature] ? "show" : "hide"](); + } + break; + case "metadata": + update_metadata(json.value); + break; + case "wsjt_message": + update_wsjt_panel(json.value); + break; + case "dial_frequencies": + var as_bookmarks = json.value.map(function (d) { + return { + 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); + break; + case "bookmarks": + bookmarks.replace_bookmarks(json.value, "server"); + break; + case "sdr_error": + divlog(json.value, true); + break; default: console.warn('received message of unknown type: ' + json.type); - } - } catch (e) { - // don't lose exception - console.error(e) - } - } + } + } catch (e) { + // don't lose exception + console.error(e) + } + } } else if (evt.data instanceof ArrayBuffer) { // binary messages debug_ws_data_received += evt.data.byteLength / 1000; - type = new Uint8Array(evt.data, 0, 1)[0] - data = evt.data.slice(1) + type = new Uint8Array(evt.data, 0, 1)[0]; + data = evt.data.slice(1); switch (type) { case 1: // FFT data - if (fft_compression=="none") { + if (fft_compression === "none") { waterfall_add(new Float32Array(data)); - } else if (fft_compression == "adpcm") { + } 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;iaudio_buffering_fill_to)) audio_init() - break; + if (!(ios || is_chrome) && (audio_initialized === 0 && audio_prepared_buffers.length > audio_buffering_fill_to)) audio_init() + break; case 3: // secondary FFT - if (fft_compression == "none") { + if (fft_compression === "none") { secondary_demod_waterfall_add(new Float32Array(data)); - } else if (fft_compression == "adpcm") { + } 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= 0) { var matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/); - if (matches && matches[2] != 'RR73') { + if (matches && matches[2] !== 'RR73') { linkedmsg = html_escape(matches[1]) + '' + matches[2] + ''; } else { linkedmsg = html_escape(linkedmsg); } - } else if (msg['mode'] == 'WSPR') { + } else if (msg['mode'] === 'WSPR') { var 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]); @@ -1430,11 +1389,11 @@ function update_wsjt_panel(msg) { } $b.append($( '' + - '' + pad(t.getUTCHours()) + pad(t.getUTCMinutes()) + pad(t.getUTCSeconds()) + '' + - '' + msg['db'] + '' + - '' + msg['dt'] + '' + - '' + msg['freq'] + '' + - '' + linkedmsg + '' + + '' + pad(t.getUTCHours()) + pad(t.getUTCMinutes()) + pad(t.getUTCSeconds()) + '' + + '' + msg['db'] + '' + + '' + msg['dt'] + '' + + '' + msg['freq'] + '' + + '' + linkedmsg + '' + '' )); $b.scrollTop($b[0].scrollHeight); @@ -1445,8 +1404,8 @@ var digital_removal_interval; // remove old wsjt messages in fixed intervals function init_digital_removal_timer() { if (digital_removal_interval) clearInterval(digital_removal_interval); - digital_removal_interval = setInterval(function(){ - ['#openwebrx-panel-wsjt-message', '#openwebrx-panel-packet-message'].forEach(function(root){ + digital_removal_interval = setInterval(function () { + ['#openwebrx-panel-wsjt-message', '#openwebrx-panel-packet-message'].forEach(function (root) { var $elements = $(root + ' tbody tr'); // limit to 1000 entries in the list since browsers get laggy at some point var toRemove = $elements.length - 1000; @@ -1457,18 +1416,20 @@ function init_digital_removal_timer() { } function update_packet_panel(msg) { - var $b = $('#openwebrx-panel-packet-message tbody'); - var pad = function(i) { return ('' + i).padStart(2, "0"); } + var $b = $('#openwebrx-panel-packet-message').find('tbody'); + var pad = function (i) { + return ('' + i).padStart(2, "0"); + }; - if (msg.type && msg.type == 'thirdparty' && msg.data) { + if (msg.type && msg.type === 'thirdparty' && msg.data) { msg = msg.data; } var source = msg.source; if (msg.type) { - if (msg.type == 'item') { + if (msg.type === 'item') { source = msg.item; } - if (msg.type == 'object') { + if (msg.type === 'object') { source = msg.object; } } @@ -1483,26 +1444,28 @@ function update_packet_panel(msg) { var classes = []; var styles = {}; var overlay = ''; - var stylesToString = function(s) { - return $.map(s, function(value, key){ return key + ':' + value + ';'}).join('') - } + var stylesToString = function (s) { + return $.map(s, function (value, key) { + return key + ':' + value + ';' + }).join('') + }; if (msg.symbol) { classes.push('aprs-symbol'); - classes.push('aprs-symboltable-' + (msg.symbol.table == '/' ? 'normal' : 'alternate')); + classes.push('aprs-symboltable-' + (msg.symbol.table === '/' ? 'normal' : 'alternate')); 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 != '\\') { + if (msg.symbol.table !== '/' && msg.symbol.table !== '\\') { s = {} s['background-position-x'] = -(msg.symbol.tableindex % 16) * 15 + 'px'; s['background-position-y'] = -Math.floor(msg.symbol.tableindex / 16) * 15 + 'px'; - overlay='
'; + overlay = '
'; } } else if (msg.lat && msg.lon) { classes.push('openwebrx-maps-pin'); } var attrs = [ 'class="' + classes.join(' ') + '"', - 'style="' + stylesToString(styles) + '"', + 'style="' + stylesToString(styles) + '"' ].join(' '); if (msg.lat && msg.lon) { link = '' + overlay + ''; @@ -1512,18 +1475,18 @@ function update_packet_panel(msg) { $b.append($( '' + - '' + timestamp + '' + - '' + source + '' + - '' + link + '' + - '' + (msg.comment || msg.message || '') + '' + + '' + timestamp + '' + + '' + source + '' + + '' + link + '' + + '' + (msg.comment || msg.message || '') + '' + '' )); $b.scrollTop($b[0].scrollHeight); } function update_digitalvoice_panels(showing) { - $(".openwebrx-meta-panel").each(function(_, p){ - toggle_panel(p.id, p.id == showing); + $(".openwebrx-meta-panel").each(function (_, p) { + toggle_panel(p.id, p.id === showing); }); clear_metadata(); } @@ -1534,61 +1497,57 @@ function clear_metadata() { $(".openwebrx-dmr-timeslot-panel").removeClass("muted"); } -function add_problem(what) -{ - problems_span=e("openwebrx-problems"); - for(var i=0;i"+what+""; - 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 +function divlog(what, is_error) { + is_error = !!is_error; + was_error |= is_error; + if (is_error) { + what = "" + what + ""; + 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' }); + $(".nano").nanoScroller({scroll: 'bottom'}); } var audio_context; -var audio_initialized=0; +var audio_initialized = 0; var volume = 1.0; var volumeBeforeMute = 100.0; var mute = false; @@ -1596,17 +1555,16 @@ var mute = false; var audio_received = Array(); var audio_buffer_index = 0; var audio_resampler; -var audio_codec=new sdrjs.ImaAdpcm(); -var audio_compression="unknown"; +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; -var audio_buffer_maximal_length_sec=3; //actual number of samples are calculated from sample rate -var audio_buffer_decrease_to_on_overrun_sec=2.2; -var audio_flush_interval_ms=500; //the interval in which audio_flush() is called +var audio_buffer_maximal_length_sec = 3; //actual number of samples are calculated from sample rate +var audio_buffer_decrease_to_on_overrun_sec = 2.2; +var audio_flush_interval_ms = 500; //the interval in which audio_flush() is called var audio_prepared_buffers = Array(); var audio_rebuffer; @@ -1614,413 +1572,397 @@ 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) +//tnx to the hint from HA3FLT, now we have about half the response time! (original value: 10) -function gain_ff(gain_value,data) //great! solved clicking! will have to move to sdr.js +function gain_ff(gain_value, data) //great! solved clicking! will have to move to sdr.js { - for(var i=0;iaudio_buffering_fill_to) { console.log("buffers now: "+audio_prepared_buffers.length.toString()); audio_buffering=false; } + //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) { + console.log("buffers now: " + audio_prepared_buffers.length.toString()); + audio_buffering = false; + } } -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_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++; - }; +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;iaudio_buffering_fill_to) audio_buffering=false; + 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 - { - var cd=this.getChannelData(channel); - for(var i=0;iaudio_buffer_maximal_length_sec; - var underrun=audio_prepared_buffers.length==0; - var text="buffer"; - if(overrun) { text="overrun"; console.log("audio overrun, "+(++audio_overrun_cnt).toString()); } - if(underrun) { text="underrun"; console.log("audio underrun, "+(++audio_underrun_cnt).toString()); } - if(overrun||underrun) - { - audio_buffer_progressbar_update_disabled=true; - window.setTimeout(function(){audio_buffer_progressbar_update_disabled=false; audio_buffer_progressbar_update();},1000); - } - progressbar_set(e("openwebrx-bar-audio-buffer"),(underrun)?1:audio_buffer_value/1.5,"Audio "+text+" ["+(audio_buffer_value).toFixed(1)+" s]",overrun||underrun||audio_buffer_value<0.25); +function audio_buffer_progressbar_update() { + if (audio_buffer_progressbar_update_disabled) return; + var audio_buffer_value = (audio_prepared_buffers.length * audio_buffer_size) / audio_context.sampleRate; + audio_buffer_total_average_level_length++; + audio_buffer_total_average_level = (audio_buffer_total_average_level * ((audio_buffer_total_average_level_length - 1) / audio_buffer_total_average_level_length)) + (audio_buffer_value / audio_buffer_total_average_level_length); + var overrun = audio_buffer_value > audio_buffer_maximal_length_sec; + var underrun = audio_prepared_buffers.length === 0; + var text = "buffer"; + if (overrun) { + text = "overrun"; + console.log("audio overrun, " + (++audio_overrun_cnt).toString()); + } + if (underrun) { + text = "underrun"; + console.log("audio underrun, " + (++audio_underrun_cnt).toString()); + } + if (overrun || underrun) { + audio_buffer_progressbar_update_disabled = true; + window.setTimeout(function () { + audio_buffer_progressbar_update_disabled = false; + audio_buffer_progressbar_update(); + }, 1000); + } + progressbar_set(e("openwebrx-bar-audio-buffer"), (underrun) ? 1 : audio_buffer_value / 1.5, "Audio " + text + " [" + (audio_buffer_value).toFixed(1) + " s]", overrun || underrun || audio_buffer_value < 0.25); } - -function audio_flush() -{ - flushed=false; - we_have_more_than=function(sec){ return sec*audio_context.sampleRateread_remain) - { - for (i=audio_buffer_index; i"+read_remain.toString()+" obi="+obi.toString()+"\n"; - audio_buffer_index+=read_remain; - break; - } - else - { - for (i=audio_buffer_index; iaudio_buffer_maximal_length) + 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); + 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 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) -{ +function webrx_set_param(what, value) { params = {}; params[what] = value; - ws.send(JSON.stringify({"type":"dspcontrol","params":params})); + ws.send(JSON.stringify({"type": "dspcontrol", "params": params})); } var starting_mute = false; -function parsehash() -{ - if(h=window.location.hash) - { - h.substring(1).split(",").forEach(function(x){ - harr=x.split("="); - //console.log(harr); - if(harr[0]=="mute") toggleMute(); - else if(harr[0]=="mod") starting_mod = harr[1]; - else if(harr[0]=="sql") - { - e("openwebrx-panel-squelch").value=harr[1]; - updateSquelch(); - } - else if(harr[0]=="freq") - { - console.log(parseInt(harr[1])); - console.log(center_freq); - starting_offset_frequency = parseInt(harr[1])-center_freq; - } - }); +function parsehash() { + if (h = window.location.hash) { + h.substring(1).split(",").forEach(function (x) { + harr = x.split("="); + //console.log(harr); + if (harr[0] === "mute") toggleMute(); + else if (harr[0] === "mod") starting_mod = harr[1]; + else if (harr[0] === "sql") { + e("openwebrx-panel-squelch").value = harr[1]; + updateSquelch(); + } + else if (harr[0] === "freq") { + console.log(parseInt(harr[1])); + console.log(center_freq); + starting_offset_frequency = parseInt(harr[1]) - center_freq; + } + }); - } + } } -function audio_preinit() -{ - try - { - window.AudioContext = window.AudioContext||window.webkitAudioContext; - audio_context = new AudioContext(); - } - catch(e) - { - divlog('Your browser does not support Web Audio API, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser.', 1); - return; - } +function audio_preinit() { + try { + window.AudioContext = window.AudioContext || window.webkitAudioContext; + audio_context = new AudioContext(); + } + catch (e) { + divlog('Your browser does not support Web Audio API, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser.', 1); + return; + } - if(audio_context.sampleRate<44100*2) - audio_buffer_size = 4096; - else if(audio_context.sampleRate>=44100*2 && audio_context.sampleRate<44100*4) - audio_buffer_size = 4096 * 2; - else if(audio_context.sampleRate>44100*4) - audio_buffer_size = 4096 * 4; + if (audio_context.sampleRate < 44100 * 2) + audio_buffer_size = 4096; + else if (audio_context.sampleRate >= 44100 * 2 && audio_context.sampleRate < 44100 * 4) + audio_buffer_size = 4096 * 2; + else if (audio_context.sampleRate > 44100 * 4) + audio_buffer_size = 4096 * 4; if (!audio_rebuffer) { - audio_rebuffer = new sdrjs.Rebuffer(audio_buffer_size,sdrjs.REBUFFER_FIXED); + audio_rebuffer = new sdrjs.Rebuffer(audio_buffer_size, sdrjs.REBUFFER_FIXED); audio_last_output_buffer = new Float32Array(audio_buffer_size); //we send our setup packet parsehash(); audio_calculate_resampling(audio_context.sampleRate); - audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor,1); + audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor, 1); } - ws.send(JSON.stringify({"type":"dspcontrol","action":"start","params":{"output_rate":audio_server_output_rate}})); + ws.send(JSON.stringify({ + "type": "dspcontrol", + "action": "start", + "params": {"output_rate": audio_server_output_rate} + })); } -function audio_init() -{ - if(is_chrome) audio_context.resume() - if(starting_mute) toggleMute(); +function audio_init() { + if (is_chrome) audio_context.resume(); + if (starting_mute) toggleMute(); - if(audio_client_resampling_factor==0) return; //if failed to find a valid resampling factor... + if (audio_client_resampling_factor === 0) return; //if failed to find a valid resampling factor... - audio_debug_time_start=(new Date()).getTime(); - audio_debug_time_last_start=audio_debug_time_start; - audio_buffer_current_count_debug = 0; + audio_debug_time_start = (new Date()).getTime(); + audio_debug_time_last_start = audio_debug_time_start; + audio_buffer_current_count_debug = 0; - //https://github.com/0xfe/experiments/blob/master/www/tone/js/sinewave.js - audio_initialized=1; // only tell on_ws_recv() not to call it again + //https://github.com/0xfe/experiments/blob/master/www/tone/js/sinewave.js + 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); - audio_node = createjsnode_function(audio_buffer_size, 0, 1); - audio_node.onaudioprocess = audio_onprocess; - audio_node.connect(audio_context.destination); - // --- Resampling --- - //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 + //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); + audio_node = createjsnode_function(audio_buffer_size, 0, 1); + audio_node.onaudioprocess = audio_onprocess; + audio_node.connect(audio_context.destination); + // --- Resampling --- + //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 - window.setInterval(audio_flush,audio_flush_interval_ms); - divlog('Web Audio API succesfully initialized, sample rate: '+audio_context.sampleRate.toString()+ " sps"); - initialize_demodulator(); + window.setInterval(audio_flush, audio_flush_interval_ms); + divlog('Web Audio API succesfully initialized, sample rate: ' + audio_context.sampleRate.toString() + " sps"); + initialize_demodulator(); - //hide log panel in a second (if user has not hidden it yet) - window.setTimeout(function(){ - if(typeof e("openwebrx-panel-log").openwebrxHidden == "undefined" && !was_error) - { - toggle_panel("openwebrx-panel-log"); - //animate(e("openwebrx-panel-log"),"opacity","",1,0,0.9,1000,60); - //window.setTimeout(function(){toggle_panel("openwebrx-panel-log");e("openwebrx-panel-log").style.opacity="1";},1200) - } - },2000); + //hide log panel in a second (if user has not hidden it yet) + window.setTimeout(function () { + if (typeof e("openwebrx-panel-log").openwebrxHidden === "undefined" && !was_error) { + toggle_panel("openwebrx-panel-log"); + //animate(e("openwebrx-panel-log"),"opacity","",1,0,0.9,1000,60); + //window.setTimeout(function(){toggle_panel("openwebrx-panel-log");e("openwebrx-panel-log").style.opacity="1";},1200) + } + }, 2000); } function initialize_demodulator() { - demodulator_analog_replace(starting_mod); - if(starting_offset_frequency) - { - demodulators[0].offset_frequency = starting_offset_frequency; - e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",center_freq+starting_offset_frequency,1e6,4); - demodulators[0].set(); - mkscale(); - } + demodulator_analog_replace(starting_mod); + if (starting_offset_frequency) { + demodulators[0].offset_frequency = starting_offset_frequency; + e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", center_freq + starting_offset_frequency, 1e6, 4); + demodulators[0].set(); + mkscale(); + } } var reconnect_timeout = false; -function on_ws_closed() -{ - try - { - audio_node.disconnect(); - } - catch (dont_care) {} - audio_initialized = 0; - if (reconnect_timeout) { - // max value: roundabout 8 and a half minutes - reconnect_timeout = Math.min(reconnect_timeout * 2, 512000); - } else { - // initial value: 1s - reconnect_timeout = 1000; - } - divlog("WebSocket has closed unexpectedly. Attempting to reconnect in " + reconnect_timeout / 1000 + " seconds...", 1); +function on_ws_closed() { + try { + audio_node.disconnect(); + } + catch (dont_care) { + } + audio_initialized = 0; + if (reconnect_timeout) { + // max value: roundabout 8 and a half minutes + reconnect_timeout = Math.min(reconnect_timeout * 2, 512000); + } else { + // initial value: 1s + reconnect_timeout = 1000; + } + divlog("WebSocket has closed unexpectedly. Attempting to reconnect in " + reconnect_timeout / 1000 + " seconds...", 1); - setTimeout(open_websocket, reconnect_timeout); + setTimeout(open_websocket, reconnect_timeout); } -function on_ws_error(event) -{ - divlog("WebSocket error.",1); +function on_ws_error(event) { + divlog("WebSocket error.", 1); } -String.prototype.startswith=function(str){ return this.indexOf(str) == 0; }; //http://stackoverflow.com/questions/646628/how-to-check-if-a-string-startswith-another-string +String.prototype.startswith = function (str) { + return this.indexOf(str) === 0; +}; //http://stackoverflow.com/questions/646628/how-to-check-if-a-string-startswith-another-string -function open_websocket() -{ - var protocol = 'ws'; - if (window.location.toString().startsWith('https://')) { - protocol = 'wss'; - } +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 - 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); - ws.onopen = on_ws_opened; - ws.onmessage = on_ws_recv; - ws.onclose = on_ws_closed; - ws.binaryType = "arraybuffer"; - window.onbeforeunload = function() { //http://stackoverflow.com/questions/4812686/closing-websocket-correctly-html5-javascript - ws.onclose = function () {}; - ws.close(); - }; - ws.onerror = on_ws_error; + 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); + ws.onopen = on_ws_opened; + ws.onmessage = on_ws_recv; + ws.onclose = on_ws_closed; + ws.binaryType = "arraybuffer"; + window.onbeforeunload = function () { //http://stackoverflow.com/questions/4812686/closing-websocket-correctly-html5-javascript + ws.onclose = function () { + }; + ws.close(); + }; + ws.onerror = on_ws_error; } -function waterfall_mkcolor(db_value, waterfall_colors_arg) -{ - if(typeof waterfall_colors_arg === 'undefined') waterfall_colors_arg = waterfall_colors; - if(db_valuewaterfall_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; - return color_between(waterfall_colors_arg[index+1],waterfall_colors_arg[index],remain); +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; + 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)); - output |= add>>>0; - } - return output>>>0; +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)); + output |= add >>> 0; + } + return output >>> 0; } @@ -2030,20 +1972,19 @@ var canvas_default_height = 200; var canvas_container; var canvas_phantom; -function add_canvas() -{ - var new_canvas = document.createElement("canvas"); - new_canvas.width=fft_size; - new_canvas.height=canvas_default_height; - canvas_actual_line=canvas_default_height-1; - new_canvas.style.width=(canvas_container.clientWidth*zoom_levels[zoom_level]).toString()+"px"; - new_canvas.style.left=zoom_offset_px.toString()+"px"; - new_canvas.style.height=canvas_default_height.toString()+"px"; - new_canvas.openwebrx_top=(-canvas_default_height+1); - new_canvas.style.top=new_canvas.openwebrx_top.toString()+"px"; - canvas_context = new_canvas.getContext("2d"); - canvas_container.appendChild(new_canvas); - canvases.push(new_canvas); +function add_canvas() { + var new_canvas = document.createElement("canvas"); + new_canvas.width = fft_size; + new_canvas.height = canvas_default_height; + canvas_actual_line = canvas_default_height - 1; + new_canvas.style.width = (canvas_container.clientWidth * zoom_levels[zoom_level]).toString() + "px"; + new_canvas.style.left = zoom_offset_px.toString() + "px"; + new_canvas.style.height = canvas_default_height.toString() + "px"; + new_canvas.openwebrx_top = (-canvas_default_height + 1); + new_canvas.style.top = new_canvas.openwebrx_top.toString() + "px"; + canvas_context = new_canvas.getContext("2d"); + canvas_container.appendChild(new_canvas); + canvases.push(new_canvas); while (canvas_container && canvas_container.clientHeight + canvas_default_height * 2 < canvases.length * canvas_default_height) { var c = canvases.shift(); if (!c) break; @@ -2052,806 +1993,673 @@ function add_canvas() } -function init_canvas_container() -{ - canvas_container=e("webrx-canvas-container"); - mathbox_container=e("openwebrx-mathbox-container"); - canvas_container.addEventListener("mouseleave",canvas_container_mouseleave, false); - canvas_container.addEventListener("mousemove", canvas_mousemove, false); - canvas_container.addEventListener("mouseup", canvas_mouseup, false); - canvas_container.addEventListener("mousedown", canvas_mousedown, false); - canvas_container.addEventListener("wheel",canvas_mousewheel, false); - var frequency_container = e("openwebrx-frequency-container"); - frequency_container.addEventListener("wheel",canvas_mousewheel, false); - add_canvas(); +function init_canvas_container() { + canvas_container = e("webrx-canvas-container"); + mathbox_container = e("openwebrx-mathbox-container"); + canvas_container.addEventListener("mouseleave", canvas_container_mouseleave, false); + canvas_container.addEventListener("mousemove", canvas_mousemove, false); + canvas_container.addEventListener("mouseup", canvas_mouseup, false); + canvas_container.addEventListener("mousedown", canvas_mousedown, false); + canvas_container.addEventListener("wheel", canvas_mousewheel, false); + var frequency_container = e("openwebrx-frequency-container"); + frequency_container.addEventListener("wheel", canvas_mousewheel, false); + add_canvas(); } -canvas_maxshift=0; +canvas_maxshift = 0; -function shift_canvases() -{ - canvases.forEach(function(p) - { - p.style.top=(p.openwebrx_top++).toString()+"px"; - }); - canvas_maxshift++; +function shift_canvases() { + canvases.forEach(function (p) { + p.style.top = (p.openwebrx_top++).toString() + "px"; + }); + canvas_maxshift++; } -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 zoom_value=zoom_offset_px.toString()+"px"; - canvases.forEach(function(p) - { - p.style.width=new_width; - p.style.left=zoom_value; - }); +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 zoom_value = zoom_offset_px.toString() + "px"; + canvases.forEach(function (p) { + p.style.width = new_width; + p.style.left = zoom_value; + }); } -function waterfall_init() -{ - init_canvas_container(); - resize_waterfall_container(false); /* then */ resize_canvases(); - scale_setup(); - mkzoomlevels(); - waterfall_setup_done=1; +function waterfall_init() { + init_canvas_container(); + resize_waterfall_container(false); + /* then */ + resize_canvases(); + scale_setup(); + mkzoomlevels(); + waterfall_setup_done = 1; } -var waterfall_dont_scale=0; +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; - else mathbox_data_index++; - mathbox_data_global_index++; -} +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; + else mathbox_data_index++; + mathbox_data_global_index++; +}; -var mathbox_clear_data = function() -{ - mathbox_data_index = 50; - mathbox_data_current_depth = 0; -} +var mathbox_clear_data = function () { + mathbox_data_index = 50; + mathbox_data_current_depth = 0; +}; -//var mathbox_get_data_line = function(x) //x counts from 0 to mathbox_data_current_depth -//{ -// return (mathbox_data_max_depth + mathbox_data_index - mathbox_data_current_depth + x - 1) % mathbox_data_max_depth; -//} -// -//var mathbox_data_index_valid = function(x) //x counts from 0 to mathbox_data_current_depth -//{ -// return xmathbox_data_max_depth-mathbox_data_current_depth; -} +var mathbox_data_index_valid = function (x) { + return x > mathbox_data_max_depth - mathbox_data_current_depth; +}; +function waterfall_add(data) { + if (!waterfall_setup_done) return; + var w = fft_size; -function waterfall_add(data) -{ - if(!waterfall_setup_done) return; - var w=fft_size; + if (waterfall_measure_minmax) waterfall_measure_minmax_do(data); + if (waterfall_measure_minmax_now) { + waterfall_measure_minmax_do(data); + waterfall_measure_minmax_now = false; + waterfallColorsAuto(); + } - if(waterfall_measure_minmax) waterfall_measure_minmax_do(data); - if(waterfall_measure_minmax_now) { - waterfall_measure_minmax_do(data); - waterfall_measure_minmax_now=false; - waterfallColorsAuto(); - } - - //waterfall_shift(); - // ==== do scaling if required ==== - /*if(waterfall_dont_scale) - { - scaled=data; - for(i=scaled.length;i1) - { - scaled[i]=data[j]*(remain/pixel_per_point)+data[j+1]*((1-remain)/pixel_per_point); - remain--; - } - else - { - j++; - scaled[i]=data[j]*(remain/pixel_per_point)+data[j+1]*((1-remain)/pixel_per_point); - remain=pixel_per_point-(1-remain); - } - } - - } - else - { //make line smaller (linear decimation, moving average) - point_per_pixel=(to-from)/w; - scaled=Array(); - j=0; - remain=point_per_pixel; - last_pixel=0; - for(i=from; i1) - { - last_pixel+=data[i]; - remain--; - } - else - { - last_pixel+=data[i]*remain; - scaled[j++]=last_pixel/point_per_pixel; - last_pixel=data[i]*(1-remain); - remain=point_per_pixel-(1-remain); //? - } - } - } - } - - //Add line to waterfall image - base=(h-1)*w*4; - for(x=0;x>>0)>>((3-i)*8))&0xff; - }*/ - - if (mathbox_mode==MATHBOX_MODES.WATERFALL) { - //Handle mathbox - for(var i=0;i>>0)>>((3-i)*8))&0xff; + oneline_image = canvas_context.createImageData(w, 1); + for (x = 0; x < w; x++) { + color = waterfall_mkcolor(data[x]); + for (i = 0; i < 4; i++) + oneline_image.data[x * 4 + i] = ((color >>> 0) >> ((3 - i) * 8)) & 0xff; } //Draw image canvas_context.putImageData(oneline_image, 0, canvas_actual_line--); shift_canvases(); - if(canvas_actual_line<0) add_canvas(); - } + if (canvas_actual_line < 0) add_canvas(); + } } -/* -function waterfall_shift() -{ - w=canvas.width; - h=canvas.height; - for(y=0; ytl.offsetLeft-20) what.style.opacity=what.style.opacity="0"; - else wet.style.opacity=wed.style.opacity="1"; - }); + [wet, wed].map(function (what) { + if (rmf(what) > tl.offsetLeft - 20) what.style.opacity = what.style.opacity = "0"; + else wet.style.opacity = wed.style.opacity = "1"; + }); } var MATHBOX_MODES = -{ - UNINITIALIZED: 0, - NONE: 1, - WATERFALL: 2, - CONSTELLATION: 3 -}; + { + UNINITIALIZED: 0, + NONE: 1, + WATERFALL: 2, + CONSTELLATION: 3 + }; var mathbox_mode = MATHBOX_MODES.UNINITIALIZED; var mathbox; var mathbox_element; -function mathbox_init() -{ - //mathbox_waterfall_history_length is defined in the config - mathbox_data_max_depth = fft_fps * mathbox_waterfall_history_length; //how many lines can the buffer store - mathbox_data_current_depth = 0; //how many lines are in the buffer currently - mathbox_data_index = 0; //the index of the last empty line / the line to be overwritten - mathbox_data = new Float32Array(fft_size * mathbox_data_max_depth); - mathbox_data_global_index = 0; - mathbox_correction_for_z = 0; +function mathbox_init() { + //mathbox_waterfall_history_length is defined in the config + mathbox_data_max_depth = fft_fps * mathbox_waterfall_history_length; //how many lines can the buffer store + mathbox_data_current_depth = 0; //how many lines are in the buffer currently + mathbox_data_index = 0; //the index of the last empty line / the line to be overwritten + mathbox_data = new Float32Array(fft_size * mathbox_data_max_depth); + mathbox_data_global_index = 0; + mathbox_correction_for_z = 0; - mathbox = mathBox({ - plugins: ['core', 'controls', 'cursor', 'stats'], - controls: { klass: THREE.OrbitControls }, + mathbox = mathBox({ + plugins: ['core', 'controls', 'cursor', 'stats'], + controls: {klass: THREE.OrbitControls} }); three = mathbox.three; - if(typeof three == "undefined") divlog("3D waterfall cannot be initialized because WebGL is not supported in your browser.", true); + 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)); + mathbox_container.appendChild((mathbox_element = three.renderer.domElement)); view = mathbox - .set({ - scale: 1080, - focus: 3, - }) - .camera({ - proxy: true, - position: [-2, 1, 3], - }) - .cartesian({ - range: [[-1, 1], [0, 1], [0, 1]], - scale: [2, 2/3, 1], - }); + .set({ + scale: 1080, + focus: 3 + }) + .camera({ + proxy: true, + position: [-2, 1, 3] + }) + .cartesian({ + range: [[-1, 1], [0, 1], [0, 1]], + scale: [2, 2 / 3, 1] + }); view.axis({ - axis: 1, - width: 3, - color: "#fff", - }); + axis: 1, + width: 3, + color: "#fff" + }); view.axis({ - axis: 2, - width: 3, - color: "#fff", - //offset: [0, 0, 0], - }); + axis: 2, + width: 3, + color: "#fff" + //offset: [0, 0, 0], + }); view.axis({ - axis: 3, - width: 3, - color: "#fff", - }); + axis: 3, + width: 3, + color: "#fff" + }); view.grid({ - width: 2, - opacity: 0.5, - axes: [1, 3], - zOrder: 1, - color: "#fff", + width: 2, + opacity: 0.5, + axes: [1, 3], + zOrder: 1, + color: "#fff" }); - //var remap = function (v) { return Math.sqrt(.5 + .5 * v); }; + var remap = function (x, z, t) { + var currentTimePos = mathbox_data_global_index / (fft_fps * 1.0); + var realZAdd = (-(t - currentTimePos) / mathbox_waterfall_history_length); + var zAdd = realZAdd - mathbox_correction_for_z; + if (zAdd < -0.2 || zAdd > 0.2) { + mathbox_correction_for_z = realZAdd; + } - - var remap = function(x,z,t) - { - var currentTimePos = mathbox_data_global_index/(fft_fps*1.0); - var realZAdd = (-(t-currentTimePos)/mathbox_waterfall_history_length); - var zAdd = realZAdd - mathbox_correction_for_z; - if(zAdd<-0.2 || zAdd>0.2) { mathbox_correction_for_z = realZAdd; } - - var xIndex = Math.trunc(((x+1)/2.0)*fft_size); //x: frequency - var zIndex = Math.trunc(z*(mathbox_data_max_depth-1)); //z: time - var realZIndex = mathbox_get_data_line(zIndex); - if(!mathbox_data_index_valid(zIndex)) return {y: undefined, dBValue: undefined, zAdd: 0 }; - //if(realZIndex>=(mathbox_data_max_depth-1)) console.log("realZIndexundef", realZIndex, zIndex); - var index = Math.trunc(xIndex + realZIndex * fft_size); - /*if(mathbox_data[index]==undefined) console.log("Undef", index, mathbox_data.length, zIndex, - realZIndex, mathbox_data_max_depth, - mathbox_data_current_depth, mathbox_data_index);*/ - var dBValue = mathbox_data[index]; - //y=1; - if(dBValue>waterfall_max_level) y = 1; - else 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({ - expr: function (emit, x, z, i, j, t) { - var y; - remapResult=remap(x,z,t); - if((y=remapResult.y)==undefined) return; - emit(x, y, z+remapResult.zAdd); - }, - width: mathbox_waterfall_frequency_resolution, - height: mathbox_data_max_depth - 1, - channels: 3, - axes: [1, 3], + expr: function (emit, x, z, i, j, t) { + var y; + remapResult = remap(x, z, t); + if ((y = remapResult.y) === undefined) return; + emit(x, y, z + remapResult.zAdd); + }, + width: mathbox_waterfall_frequency_resolution, + height: mathbox_data_max_depth - 1, + channels: 3, + axes: [1, 3] }); var colors = view.area({ - expr: function (emit, x, z, i, j, t) { - var dBValue; - if((dBValue=remap(x,z,t).dBValue)==undefined) return; - var color=waterfall_mkcolor(dBValue, mathbox_waterfall_colors); - var b = (color&0xff)/255.0; - var g = ((color&0xff00)>>8)/255.0; - var r = ((color&0xff0000)>>16)/255.0; - emit(r, g, b, 1.0); - }, - width: mathbox_waterfall_frequency_resolution, - height: mathbox_data_max_depth - 1, - channels: 4, - axes: [1, 3], + expr: function (emit, x, z, i, j, t) { + var dBValue; + if ((dBValue = remap(x, z, t).dBValue) === undefined) return; + var color = waterfall_mkcolor(dBValue, mathbox_waterfall_colors); + var b = (color & 0xff) / 255.0; + var g = ((color & 0xff00) >> 8) / 255.0; + var r = ((color & 0xff0000) >> 16) / 255.0; + emit(r, g, b, 1.0); + }, + width: mathbox_waterfall_frequency_resolution, + height: mathbox_data_max_depth - 1, + channels: 4, + axes: [1, 3] }); view.surface({ - shaded: true, - points: '<<', - colors: '<', - color: 0xFFFFFF, + shaded: true, + points: '<<', + colors: '<', + color: 0xFFFFFF }); view.surface({ - fill: false, - lineX: false, - lineY: false, - points: '<<', - colors: '<', - color: 0xFFFFFF, - width: 2, - blending: 'add', - opacity: .25, - zBias: 5, + fill: false, + lineX: false, + lineY: false, + points: '<<', + colors: '<', + color: 0xFFFFFF, + width: 2, + blending: 'add', + opacity: .25, + zBias: 5 }); - mathbox_mode = MATHBOX_MODES.NONE; - - //mathbox_element.style.width="100%"; - //mathbox_element.style.height="100%"; + mathbox_mode = MATHBOX_MODES.NONE; } -function mathbox_toggle() -{ +function mathbox_toggle() { - if(mathbox_mode == MATHBOX_MODES.UNINITIALIZED) mathbox_init(); - mathbox_mode = (mathbox_mode == MATHBOX_MODES.NONE) ? MATHBOX_MODES.WATERFALL : MATHBOX_MODES.NONE; - mathbox_container.style.display = (mathbox_mode == MATHBOX_MODES.WATERFALL) ? "block" : "none"; - mathbox_clear_data(); - waterfall_clear(); + if (mathbox_mode === MATHBOX_MODES.UNINITIALIZED) mathbox_init(); + mathbox_mode = (mathbox_mode === MATHBOX_MODES.NONE) ? MATHBOX_MODES.WATERFALL : MATHBOX_MODES.NONE; + mathbox_container.style.display = (mathbox_mode === MATHBOX_MODES.WATERFALL) ? "block" : "none"; + mathbox_clear_data(); + waterfall_clear(); } -function waterfall_clear() -{ - while(canvases.length) //delete all canvases - { - var x=canvases.shift(); - x.parentNode.removeChild(x); - delete x; - } - add_canvas(); +function waterfall_clear() { + while (canvases.length) //delete all canvases + { + var x = canvases.shift(); + x.parentNode.removeChild(x); + delete x; + } + add_canvas(); } -function openwebrx_resize() -{ - resize_canvases(); - resize_waterfall_container(true); - resize_scale(); - check_top_bar_congestion(); +function openwebrx_resize() { + resize_canvases(); + resize_waterfall_container(true); + resize_scale(); + check_top_bar_congestion(); } -function init_header() -{ - $('#openwebrx-main-buttons li[data-toggle-panel]').click(function() { +function init_header() { + $('#openwebrx-main-buttons').find('li[data-toggle-panel]').click(function () { toggle_panel($(this).data('toggle-panel')); }); } 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"; - init_rx_photo(); - open_websocket(); +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"; + init_rx_photo(); + open_websocket(); secondary_demod_init(); digimodes_init(); - place_panels(first_show_panel); - window.setTimeout(function(){window.setInterval(debug_audio,1000);},1000); - window.addEventListener("resize",openwebrx_resize); - check_top_bar_congestion(); - init_header(); - bookmarks = new BookmarkBar(); + place_panels(first_show_panel); + window.setTimeout(function () { + window.setInterval(debug_audio, 1000); + }, 1000); + window.addEventListener("resize", openwebrx_resize); + check_top_bar_congestion(); + init_header(); + bookmarks = new BookmarkBar(); - //Synchronise volume with slider - updateVolume(); + //Synchronise volume with slider + updateVolume(); } function digimodes_init() { - $(".openwebrx-meta-panel").each(function(_, p){ + $(".openwebrx-meta-panel").each(function (_, p) { p.openwebrxHidden = true; }); // initialze DMR timeslot muting - $('.openwebrx-dmr-timeslot-panel').click(function(e) { + $('.openwebrx-dmr-timeslot-panel').click(function (e) { $(e.currentTarget).toggleClass("muted"); update_dmr_timeslot_filtering(); }); } function update_dmr_timeslot_filtering() { - var filter = $('.openwebrx-dmr-timeslot-panel').map(function(index, el){ + var filter = $('.openwebrx-dmr-timeslot-panel').map(function (index, el) { return (!$(el).hasClass("muted")) << index; - }).toArray().reduce(function(acc, v){ + }).toArray().reduce(function (acc, v) { return acc | v; }, 0); webrx_set_param("dmr_filter", filter); } -function iosPlayButtonClick() -{ - //On iOS, we can only start audio from a click or touch event. - audio_init(); - e("openwebrx-big-grey").style.opacity=0; - window.setTimeout(function(){ e("openwebrx-big-grey").style.display="none"; },1100); - audio_allowed = 1; +function iosPlayButtonClick() { + //On iOS, we can only start audio from a click or touch event. + audio_init(); + e("openwebrx-big-grey").style.opacity = 0; + window.setTimeout(function () { + e("openwebrx-big-grey").style.display = "none"; + }, 1100); + audio_allowed = 1; } -/* -window.setInterval(function(){ - sum=0; - for(i=0;i= (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); +}; -/*function email(what) -{ - //| http://stackoverflow.com/questions/617647/where-is-my-one-line-implementation-of-rot13-in-javascript-going-wrong - what=what.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);}); - window.location.href="mailto:"+what; -}*/ +var audio_debug_time_start = 0; +var audio_debug_time_last_start = 0; -var rt = function (s,n) {return s.replace(/[a-zA-Z]/g,function(c){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); } +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; + 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; + //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 "+ + // ((audio_buffer_current_count_debug*audio_buffer_size)/audio_debug_time_taken).toFixed(1)+" sps output"; -var audio_debug_time_start=0; -var audio_debug_time_last_start=0; + var audio_speed_value = audio_buffer_current_size_debug * kbps_mult / audio_debug_time_since_last_call; + progressbar_set(e("openwebrx-bar-audio-speed"), audio_speed_value / 500000, "Audio stream [" + (audio_speed_value / 1000).toFixed(0) + " kbps]", false); -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; - 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; - //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 "+ - // ((audio_buffer_current_count_debug*audio_buffer_size)/audio_debug_time_taken).toFixed(1)+" sps output"; + var audio_output_value = (audio_buffer_current_count_debug * audio_buffer_size) / audio_debug_time_taken; + var audio_max_rate = audio_context.sampleRate * 1.25; + var audio_min_rate = audio_context.sampleRate * .25; + progressbar_set(e("openwebrx-bar-audio-output"), audio_output_value / audio_max_rate, "Audio output [" + (audio_output_value / 1000).toFixed(1) + " ksps]", audio_output_value > audio_max_rate || audio_output_value < audio_min_rate); - var audio_speed_value=audio_buffer_current_size_debug*kbps_mult/audio_debug_time_since_last_call; - progressbar_set(e("openwebrx-bar-audio-speed"),audio_speed_value/500000,"Audio stream ["+(audio_speed_value/1000).toFixed(0)+" kbps]",false); - - var audio_output_value=(audio_buffer_current_count_debug*audio_buffer_size)/audio_debug_time_taken; - var audio_max_rate = audio_context.sampleRate * 1.25; - var audio_min_rate = audio_context.sampleRate * .25; - progressbar_set(e("openwebrx-bar-audio-output"),audio_output_value/audio_max_rate,"Audio output ["+(audio_output_value/1000).toFixed(1)+" ksps]",audio_output_value>audio_max_rate||audio_output_value0.5)?-90:90; - roty=0; - if(Math.random()>0.5) - { - 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 )" - .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); +function first_show_panel(panel) { + panel.style.transitionDuration = 0; + panel.style.transitionDelay = 0; + rotx = (Math.random() > 0.5) ? -90 : 90; + roty = 0; + if (Math.random() > 0.5) { + 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 )" + .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); } -function place_panels(function_apply) -{ - if(function_apply == undefined) function_apply = function(x){}; - var hoffset=0; //added this because the first panel should not have such great gap below - var left_col=[]; - var right_col=[]; - var plist=e("openwebrx-panels-container").children; - for(i=0;i= 0) - { - if(c.openwebrxHidden) - { - c.style.display="none"; - continue; - } - c.style.display="block"; - c.openwebrxPanelTransparent=(!!c.dataset.panelTransparent); - newSize=c.dataset.panelSize.split(","); - if (c.dataset.panelPos=="left") { left_col.push(c); } - else if(c.dataset.panelPos=="right") { right_col.push(c); } - c.style.width=newSize[0]+"px"; - //c.style.height=newSize[1]+"px"; - if(!c.openwebrxPanelTransparent) c.style.margin=panel_margin.toString()+"px"; - else c.style.marginLeft=panel_margin.toString()+"px"; - c.openwebrxPanelWidth=parseInt(newSize[0]); - c.openwebrxPanelHeight=parseInt(newSize[1]); - } - } +function place_panels(function_apply) { + if (function_apply === undefined) function_apply = function (x) { + }; + var hoffset = 0; //added this because the first panel should not have such great gap below + var left_col = []; + var right_col = []; + var plist = e("openwebrx-panels-container").children; + for (i = 0; i < plist.length; i++) { + c = plist[i]; + if (c.className.indexOf("openwebrx-panel") >= 0) { + if (c.openwebrxHidden) { + c.style.display = "none"; + continue; + } + c.style.display = "block"; + c.openwebrxPanelTransparent = (!!c.dataset.panelTransparent); + newSize = c.dataset.panelSize.split(","); + if (c.dataset.panelPos === "left") { + left_col.push(c); + } + else if (c.dataset.panelPos === "right") { + right_col.push(c); + } + c.style.width = newSize[0] + "px"; + //c.style.height=newSize[1]+"px"; + if (!c.openwebrxPanelTransparent) c.style.margin = panel_margin.toString() + "px"; + else c.style.marginLeft = panel_margin.toString() + "px"; + c.openwebrxPanelWidth = parseInt(newSize[0]); + c.openwebrxPanelHeight = parseInt(newSize[1]); + } + } - y=hoffset; //was y=0 before hoffset - while(left_col.length>0) - { - p=pop_bottommost_panel(left_col); - p.style.left="0px"; - p.style.bottom=y.toString()+"px"; - p.style.visibility="visible"; - y+=p.openwebrxPanelHeight+((p.openwebrxPanelTransparent)?0:3)*panel_margin; - if(function_apply) function_apply(p); + y = hoffset; //was y=0 before hoffset + while (left_col.length > 0) { + p = pop_bottommost_panel(left_col); + p.style.left = "0px"; + p.style.bottom = y.toString() + "px"; + p.style.visibility = "visible"; + y += p.openwebrxPanelHeight + ((p.openwebrxPanelTransparent) ? 0 : 3) * panel_margin; + if (function_apply) function_apply(p); //console.log(p.id, y, p.openwebrxPanelTransparent); - } - y=hoffset; - while(right_col.length>0) - { - p=pop_bottommost_panel(right_col); - p.style.right=(e("webrx-canvas-container").offsetWidth-e("webrx-canvas-container").clientWidth).toString()+"px"; //get scrollbar width - p.style.bottom=y.toString()+"px"; - p.style.visibility="visible"; - y+=p.openwebrxPanelHeight+((p.openwebrxPanelTransparent)?0:3)*panel_margin; - if(function_apply) function_apply(p); - } + } + y = hoffset; + while (right_col.length > 0) { + p = pop_bottommost_panel(right_col); + p.style.right = (e("webrx-canvas-container").offsetWidth - e("webrx-canvas-container").clientWidth).toString() + "px"; //get scrollbar width + p.style.bottom = y.toString() + "px"; + p.style.visibility = "visible"; + y += p.openwebrxPanelHeight + ((p.openwebrxPanelTransparent) ? 0 : 3) * panel_margin; + if (function_apply) function_apply(p); + } } -function progressbar_set(obj,val,text,over) -{ - if (val<0.05) val=0; - if (val>1) val=1; - var innerBar=null; - var innerText=null; - for(var i=0;i 1) val = 1; + var innerBar = null; + var innerText = null; + for (var i = 0; i < obj.children.length; i++) { + if (obj.children[i].className === "openwebrx-progressbar-text") innerText = obj.children[i]; + else if (obj.children[i].className === "openwebrx-progressbar-bar") innerBar = obj.children[i]; + } + if (innerBar == null) return; + //.h: function animate(object,style_name,unit,from,to,accel,time_ms,fps,to_exec) + animate(innerBar, "width", "px", innerBar.clientWidth, val * obj.clientWidth, 0.7, 700, 60); + //innerBar.style.width=(val*100).toFixed(0)+"%"; + innerBar.style.backgroundColor = (over) ? "#ff6262" : "#00aba6"; + if (innerText == null) return; + innerText.innerHTML = text; } -function demodulator_buttons_update() -{ - $(".openwebrx-demodulator-button").removeClass("highlighted"); - if(secondary_demod) { - $("#openwebrx-button-dig").addClass("highlighted"); - $('#openwebrx-secondary-demod-listbox').val(secondary_demod); - } else switch(demodulators[0].subtype) { - case "lsb": - case "usb": - case "cw": - if(demodulators[0].high_cut-demodulators[0].low_cut<300) - $("#openwebrx-button-cw").addClass("highlighted"); - else - { - if(demodulators[0].high_cut<0) - $("#openwebrx-button-lsb").addClass("highlighted"); - else if(demodulators[0].low_cut>0) - $("#openwebrx-button-usb").addClass("highlighted"); - else $("#openwebrx-button-lsb, #openwebrx-button-usb").addClass("highlighted"); - } - break; - default: +function demodulator_buttons_update() { + $(".openwebrx-demodulator-button").removeClass("highlighted"); + if (secondary_demod) { + $("#openwebrx-button-dig").addClass("highlighted"); + $('#openwebrx-secondary-demod-listbox').val(secondary_demod); + } else switch (demodulators[0].subtype) { + case "lsb": + case "usb": + case "cw": + if (demodulators[0].high_cut - demodulators[0].low_cut < 300) + $("#openwebrx-button-cw").addClass("highlighted"); + else { + if (demodulators[0].high_cut < 0) + $("#openwebrx-button-lsb").addClass("highlighted"); + else if (demodulators[0].low_cut > 0) + $("#openwebrx-button-usb").addClass("highlighted"); + else $("#openwebrx-button-lsb, #openwebrx-button-usb").addClass("highlighted"); + } + break; + default: var mod = demodulators[0].subtype; $("#openwebrx-button-" + mod).addClass("highlighted"); break; - } + } +} + +function demodulator_analog_replace_last() { + demodulator_analog_replace(last_analog_demodulator_subtype); } -function demodulator_analog_replace_last() { demodulator_analog_replace(last_analog_demodulator_subtype); } /* - _____ _ _ _ - | __ \(_) (_) | | - | | | |_ __ _ _ _ __ ___ ___ __| | ___ ___ + _____ _ _ _ + | __ \(_) (_) | | + | | | |_ __ _ _ _ __ ___ ___ __| | ___ ___ | | | | |/ _` | | '_ ` _ \ / _ \ / _` |/ _ \/ __| | |__| | | (_| | | | | | | | (_) | (_| | __/\__ \ |_____/|_|\__, |_|_| |_| |_|\___/ \__,_|\___||___/ - __/ | - |___/ + __/ | + |___/ */ secondary_demod = false; secondary_demod_offset_freq = 0; -function demodulator_digital_replace_last() -{ - demodulator_digital_replace(last_digital_demodulator_subtype); +function demodulator_digital_replace_last() { + demodulator_digital_replace(last_digital_demodulator_subtype); secondary_demod_listbox_update(); } -function demodulator_digital_replace(subtype) -{ - switch(subtype) - { - case "bpsk31": - case "rtty": - case "ft8": - case "jt65": - case "jt9": - case "ft4": - secondary_demod_start(subtype); - demodulator_analog_replace('usb', true); - break; - case "wspr": - secondary_demod_start(subtype); - demodulator_analog_replace('usb', true); - // WSPR only samples between 1400 and 1600 Hz - demodulators[0].low_cut = 1350; - demodulators[0].high_cut = 1650; - demodulators[0].set(); - break; - case "packet": - secondary_demod_start(subtype); - demodulator_analog_replace('nfm', true); - break; + +function demodulator_digital_replace(subtype) { + switch (subtype) { + case "bpsk31": + case "rtty": + case "ft8": + case "jt65": + case "jt9": + case "ft4": + secondary_demod_start(subtype); + demodulator_analog_replace('usb', true); + break; + case "wspr": + secondary_demod_start(subtype); + demodulator_analog_replace('usb', true); + // WSPR only samples between 1400 and 1600 Hz + demodulators[0].low_cut = 1350; + demodulators[0].high_cut = 1650; + demodulators[0].set(); + break; + case "packet": + secondary_demod_start(subtype); + demodulator_analog_replace('nfm', true); + break; } demodulator_buttons_update(); $('#openwebrx-panel-digimodes').attr('data-mode', subtype); toggle_panel("openwebrx-panel-digimodes", true); toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4'].indexOf(subtype) >= 0); - toggle_panel("openwebrx-panel-packet-message", subtype == "packet"); + toggle_panel("openwebrx-panel-packet-message", subtype === "packet"); } -function secondary_demod_create_canvas() -{ - var new_canvas = document.createElement("canvas"); - new_canvas.width=secondary_fft_size; - 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"; +function secondary_demod_create_canvas() { + var new_canvas = document.createElement("canvas"); + new_canvas.width = secondary_fft_size; + 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); + secondary_demod_current_canvas_actual_line = new_canvas.height - 1; + $(secondary_demod_canvas_container).children().last().before(new_canvas); return new_canvas; } -function secondary_demod_remove_canvases() -{ +function secondary_demod_remove_canvases() { $(secondary_demod_canvas_container).children("canvas").remove(); } -function secondary_demod_init_canvases() -{ +function secondary_demod_init_canvases() { secondary_demod_remove_canvases(); - secondary_demod_canvases=[]; + secondary_demod_canvases = []; secondary_demod_canvases.push(secondary_demod_create_canvas()); secondary_demod_canvases.push(secondary_demod_create_canvas()); - secondary_demod_canvases[0].openwebrx_top=-$(secondary_demod_canvas_container).height(); - secondary_demod_canvases[1].openwebrx_top=0; + secondary_demod_canvases[0].openwebrx_top = -$(secondary_demod_canvas_container).height(); + secondary_demod_canvases[1].openwebrx_top = 0; secondary_demod_canvases_update_top(); secondary_demod_current_canvas_context = secondary_demod_canvases[0].getContext("2d"); - 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_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 } -function secondary_demod_canvases_update_top() -{ - for(var i=0;i<2;i++) secondary_demod_canvases[i].style.top=secondary_demod_canvases[i].openwebrx_top+"px"; +function secondary_demod_canvases_update_top() { + for (var i = 0; i < 2; i++) secondary_demod_canvases[i].style.top = secondary_demod_canvases[i].openwebrx_top + "px"; } -function secondary_demod_swap_canvases() -{ +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_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"); - secondary_demod_current_canvas_actual_line=$(secondary_demod_canvas_container).height()-1; + secondary_demod_current_canvas_actual_line = $(secondary_demod_canvas_container).height() - 1; } -function secondary_demod_init() -{ +function secondary_demod_init() { $("#openwebrx-panel-digimodes")[0].openwebrxHidden = true; $("#openwebrx-panel-wsjt-message")[0].openwebrxHidden = true; $("#openwebrx-panel-packet-message")[0].openwebrxHidden = true; @@ -2865,90 +2673,91 @@ function secondary_demod_init() init_digital_removal_timer(); } -function secondary_demod_start(subtype) -{ +function secondary_demod_start(subtype) { secondary_demod_canvases_initialized = false; - ws.send(JSON.stringify({"type":"dspcontrol","params":{"secondary_mod":subtype}})); + ws.send(JSON.stringify({"type": "dspcontrol", "params": {"secondary_mod": 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_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}})); +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( y => (y)?"1":"0" ).join("")); +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((y) => { - var c=y.charCodeAt(0); - return (c == 10 || (c >= 32 && c <= 126)); - }).map((y) => { - if(y=="&") return "&"; - if(y=="<") return "<"; - if(y==">") return ">"; - if(y==" ") return " "; +function secondary_demod_push_data(x) { + x = Array.from(x).filter(function (y) { + var c = y.charCodeAt(0); + return (c === 10 || (c >= 32 && c <= 126)); + }).map(function (y) { + if (y === "&" + ) + return "&"; + if (y === "<") return "<"; + if (y === ">") return ">"; + if (y === " ") return " "; return y; - }).map((y) => { - if (y == "\n") return "
"; - return ""+y+""; + }).map(function (y) { + if (y === "\n" + ) + return "
"; + return "" + y + ""; }).join(""); $("#openwebrx-cursor-blink").before(x); } -function secondary_demod_data_clear() -{ +function secondary_demod_data_clear() { $("#openwebrx-cursor-blink").prevAll().remove(); } -function secondary_demod_close_window() -{ +function secondary_demod_close_window() { secondary_demod_stop(); toggle_panel("openwebrx-panel-digimodes", false); toggle_panel("openwebrx-panel-wsjt-message", false); toggle_panel("openwebrx-panel-packet-message", false); } -secondary_demod_fft_offset_db=30; //need to calculate that later +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; +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>>0)>>((3-i)*8))&0xff; - } + //Add line to waterfall image + var oneline_image = secondary_demod_current_canvas_context.createImageData(w, 1); + for (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; + } - //Draw image - secondary_demod_current_canvas_context.putImageData(oneline_image, 0, secondary_demod_current_canvas_actual_line--); - secondary_demod_canvases.map((x)=>{x.openwebrx_top += 1;}); + //Draw image + secondary_demod_current_canvas_context.putImageData(oneline_image, 0, secondary_demod_current_canvas_actual_line--); + secondary_demod_canvases.map(function (x) { + x.openwebrx_top += 1; + }) + ; secondary_demod_canvases_update_top(); - if(secondary_demod_current_canvas_actual_line<0) secondary_demod_swap_canvases(); + 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() -{ + +function secondary_demod_listbox_changed() { if (secondary_demod_listbox_updating) return; var sdm = $("#openwebrx-secondary-demod-listbox")[0].value; - if (sdm == "none") { + if (sdm === "none") { demodulator_analog_replace_last(); } else { demodulator_digital_replace(sdm); @@ -2956,100 +2765,99 @@ function secondary_demod_listbox_changed() update_dial_button(); } -function secondary_demod_listbox_update() -{ +function secondary_demod_listbox_update() { secondary_demod_listbox_updating = true; - $("#openwebrx-secondary-demod-listbox").val((secondary_demod)?secondary_demod:"none"); + $("#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; +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") + $("#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); + +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) - { + if (!secondary_demod_waiting_for_set) { secondary_demod_waiting_for_set = true; - window.setTimeout(()=>{ - ws.send(JSON.stringify({"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); + window.setTimeout(function () { + ws.send(JSON.stringify({ + "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 + ) + ; } 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"); +secondary_demod_mousedown = false; + +function secondary_demod_canvas_container_mousein() { + $("#openwebrx-digimode-select-channel").css("opacity", "0.7"); //.css("border-width", "1px"); } -function secondary_demod_canvas_container_mouseleave() -{ - $("#openwebrx-digimode-select-channel").css("opacity","0"); +function secondary_demod_canvas_container_mouseleave() { + $("#openwebrx-digimode-select-channel").css("opacity", "0"); } -function secondary_demod_canvas_container_mousemove(evt) -{ - if(secondary_demod_mousedown) secondary_demod_update_channel_freq_from_event(evt); +function secondary_demod_canvas_container_mousemove(evt) { + if (secondary_demod_mousedown) secondary_demod_update_channel_freq_from_event(evt); } -function secondary_demod_canvas_container_mousedown(evt) -{ - if(evt.which==1) secondary_demod_mousedown=true; +function secondary_demod_canvas_container_mousedown(evt) { + if (evt.which === 1) secondary_demod_mousedown = true; } -function secondary_demod_canvas_container_mouseup(evt) -{ - if(evt.which==1) secondary_demod_mousedown=false; +function secondary_demod_canvas_container_mouseup(evt) { + if (evt.which === 1) secondary_demod_mousedown = false; secondary_demod_update_channel_freq_from_event(evt); } -function secondary_demod_waterfall_set_zoom(low_cut, high_cut) -{ - if(!secondary_demod || !secondary_demod_canvases_initialized) return; - if(low_cut<0 && high_cut<0) - { +function secondary_demod_waterfall_set_zoom(low_cut, high_cut) { + if (!secondary_demod || !secondary_demod_canvases_initialized) return; + if (low_cut < 0 && high_cut < 0) { var hctmp = high_cut; var lctmp = low_cut; low_cut = -hctmp; low_cut = -lctmp; } - else if(low_cut<0 && high_cut>0) - { - high_cut=Math.max(Math.abs(high_cut), Math.abs(low_cut)); - low_cut=0; + else if (low_cut < 0 && high_cut > 0) { + high_cut = Math.max(Math.abs(high_cut), Math.abs(low_cut)); + low_cut = 0; } secondary_demod_low_cut = low_cut; secondary_demod_high_cut = high_cut; - var shown_bw = high_cut-low_cut; - secondary_demod_canvas_width = $(secondary_demod_canvas_container).width() * (if_samp_rate/2)/shown_bw; - secondary_demod_canvas_left = -secondary_demod_canvas_width*(low_cut/(if_samp_rate/2)); + var shown_bw = high_cut - low_cut; + secondary_demod_canvas_width = $(secondary_demod_canvas_container).width() * (if_samp_rate / 2) / shown_bw; + secondary_demod_canvas_left = -secondary_demod_canvas_width * (low_cut / (if_samp_rate / 2)); //console.log("setzoom", secondary_demod_canvas_width, secondary_demod_canvas_left, low_cut, high_cut); - secondary_demod_canvases.map((x)=>{$(x).css("left",secondary_demod_canvas_left+"px").css("width",secondary_demod_canvas_width+"px");}); + secondary_demod_canvases.map(function (x) { + $(x).css("left", secondary_demod_canvas_left + "px").css("width", secondary_demod_canvas_width + "px"); + }) + ; secondary_demod_update_channel_freq_from_event(); } function sdr_profile_changed() { value = $('#openwebrx-sdr-profiles-listbox').val(); - ws.send(JSON.stringify({ type:"selectprofile", params:{ profile:value }})); + ws.send(JSON.stringify({type: "selectprofile", params: {profile: value}})); }