FFT is shown on the additional panel
This commit is contained in:
parent
5cc93a03e7
commit
0357c8b3ed
@ -79,7 +79,8 @@ ppm = 0
|
|||||||
audio_compression="adpcm" #valid values: "adpcm", "none"
|
audio_compression="adpcm" #valid values: "adpcm", "none"
|
||||||
fft_compression="adpcm" #valid values: "adpcm", "none"
|
fft_compression="adpcm" #valid values: "adpcm", "none"
|
||||||
|
|
||||||
enable_digimodes=True #If set to True, it will take more CPU per client
|
digimodes_enable=True #Decoding digimodes come with higher CPU usage.
|
||||||
|
digimodes_fft_size=1024
|
||||||
|
|
||||||
start_rtl_thread=True
|
start_rtl_thread=True
|
||||||
|
|
||||||
|
4
csdr.py
4
csdr.py
@ -198,6 +198,10 @@ class dsp:
|
|||||||
def get_secondary_demodulator(self):
|
def get_secondary_demodulator(self):
|
||||||
return self.secondary_demodulator
|
return self.secondary_demodulator
|
||||||
|
|
||||||
|
def set_secondary_fft_size(self,secondary_fft_size):
|
||||||
|
#to change this, restart is required
|
||||||
|
self.secondary_fft_size=secondary_fft_size
|
||||||
|
|
||||||
def set_audio_compression(self,what):
|
def set_audio_compression(self,what):
|
||||||
self.audio_compression = what
|
self.audio_compression = what
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
var waterfall_min_level_default=%[WATERFALL_MIN_LEVEL];
|
var waterfall_min_level_default=%[WATERFALL_MIN_LEVEL];
|
||||||
var waterfall_max_level_default=%[WATERFALL_MAX_LEVEL];
|
var waterfall_max_level_default=%[WATERFALL_MAX_LEVEL];
|
||||||
var waterfall_auto_level_margin=%[WATERFALL_AUTO_LEVEL_MARGIN];
|
var waterfall_auto_level_margin=%[WATERFALL_AUTO_LEVEL_MARGIN];
|
||||||
var server_enable_digimodes=%[ENABLE_DIGIMODES];
|
var server_enable_digimodes=%[DIGIMODES_ENABLE];
|
||||||
</script>
|
</script>
|
||||||
<script src="sdr.js"></script>
|
<script src="sdr.js"></script>
|
||||||
<script src="openwebrx.js"></script>
|
<script src="openwebrx.js"></script>
|
||||||
|
@ -823,6 +823,13 @@ img.openwebrx-mirror-img
|
|||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#openwebrx-digimode-canvas-container canvas
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-secondary-demod-listbox
|
#openwebrx-secondary-demod-listbox
|
||||||
@ -911,6 +918,7 @@ img.openwebrx-mirror-img
|
|||||||
{
|
{
|
||||||
perspective: 700px;
|
perspective: 700px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-digimode-content .part
|
#openwebrx-digimode-content .part
|
||||||
{
|
{
|
||||||
animation: new-digimode-data-3d 100ms;
|
animation: new-digimode-data-3d 100ms;
|
||||||
|
@ -51,6 +51,7 @@ var audio_compression="none";
|
|||||||
var waterfall_setup_done=0;
|
var waterfall_setup_done=0;
|
||||||
var waterfall_queue = [];
|
var waterfall_queue = [];
|
||||||
var waterfall_timer;
|
var waterfall_timer;
|
||||||
|
var secondary_fft_size;
|
||||||
|
|
||||||
/*function fade(something,from,to,time_ms,fps)
|
/*function fade(something,from,to,time_ms,fps)
|
||||||
{
|
{
|
||||||
@ -1158,7 +1159,7 @@ function on_ws_recv(evt)
|
|||||||
else if(first3Chars=="FFT")
|
else if(first3Chars=="FFT")
|
||||||
{
|
{
|
||||||
//alert("Yupee! Doing FFT");
|
//alert("Yupee! Doing FFT");
|
||||||
if(first4Chars=="FFTS") console.log("FFTS");
|
//if(first4Chars=="FFTS") console.log("FFTS");
|
||||||
if(fft_compression=="none") waterfall_add_queue(new Float32Array(evt.data,4));
|
if(fft_compression=="none") waterfall_add_queue(new Float32Array(evt.data,4));
|
||||||
else if(fft_compression="adpcm")
|
else if(fft_compression="adpcm")
|
||||||
{
|
{
|
||||||
@ -1167,14 +1168,14 @@ function on_ws_recv(evt)
|
|||||||
var waterfall_i16=fft_codec.decode(new Uint8Array(evt.data,4));
|
var waterfall_i16=fft_codec.decode(new Uint8Array(evt.data,4));
|
||||||
var waterfall_f32=new Float32Array(waterfall_i16.length-COMPRESS_FFT_PAD_N);
|
var waterfall_f32=new Float32Array(waterfall_i16.length-COMPRESS_FFT_PAD_N);
|
||||||
for(var i=0;i<waterfall_i16.length;i++) waterfall_f32[i]=waterfall_i16[i+COMPRESS_FFT_PAD_N]/100;
|
for(var i=0;i<waterfall_i16.length;i++) waterfall_f32[i]=waterfall_i16[i+COMPRESS_FFT_PAD_N]/100;
|
||||||
if(first4Chars=="FFTS");// secondary_demod_waterfall_add_queue(waterfall_f32); //TODO digimodes
|
if(first4Chars=="FFTS") secondary_demod_waterfall_add_queue(waterfall_f32); //TODO digimodes
|
||||||
else waterfall_add_queue(waterfall_f32);
|
else waterfall_add_queue(waterfall_f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(first3Chars=="DAT")
|
else if(first3Chars=="DAT")
|
||||||
{
|
{
|
||||||
secondary_demod_push_binary_data(new Uint8Array(evt.data,4))
|
secondary_demod_push_binary_data(new Uint8Array(evt.data,4))
|
||||||
console.log("DAT");
|
//console.log("DAT");
|
||||||
}
|
}
|
||||||
else if(first3Chars=="MSG")
|
else if(first3Chars=="MSG")
|
||||||
{
|
{
|
||||||
@ -1200,6 +1201,12 @@ function on_ws_recv(evt)
|
|||||||
case "fft_size":
|
case "fft_size":
|
||||||
fft_size=parseInt(param[1]);
|
fft_size=parseInt(param[1]);
|
||||||
break;
|
break;
|
||||||
|
case "secondary_fft_size":
|
||||||
|
secondary_fft_size=parseInt(param[1]);
|
||||||
|
break;
|
||||||
|
case "secondary_setup":
|
||||||
|
secondary_demod_init_canvases();
|
||||||
|
break;
|
||||||
case "fft_fps":
|
case "fft_fps":
|
||||||
fft_fps=parseInt(param[1]);
|
fft_fps=parseInt(param[1]);
|
||||||
break;
|
break;
|
||||||
@ -1544,7 +1551,7 @@ function parsehash()
|
|||||||
{
|
{
|
||||||
h.substring(1).split(",").forEach(function(x){
|
h.substring(1).split(",").forEach(function(x){
|
||||||
harr=x.split("=");
|
harr=x.split("=");
|
||||||
console.log(harr);
|
//console.log(harr);
|
||||||
if(harr[0]=="mute") toggleMute();
|
if(harr[0]=="mute") toggleMute();
|
||||||
else if(harr[0]=="mod") starting_mod = harr[1];
|
else if(harr[0]=="mod") starting_mod = harr[1];
|
||||||
else if(harr[0]=="sql")
|
else if(harr[0]=="sql")
|
||||||
@ -2225,13 +2232,61 @@ function demodulator_digital_replace(subtype)
|
|||||||
toggle_panel("openwebrx-panel-digimodes", true);
|
toggle_panel("openwebrx-panel-digimodes", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
canvas_actual_line=new_canvas.height-1;
|
||||||
|
$(secondary_demod_canvas_container).append(new_canvas);
|
||||||
|
return new_canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
function secondary_demod_remove_canvases()
|
||||||
|
{
|
||||||
|
$(secondary_demod_canvas_container).children().remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function secondary_demod_init_canvases()
|
||||||
|
{
|
||||||
|
secondary_demod_remove_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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
secondary_demod_canvases[0+!secondary_demod_current_canvas_index].style.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;
|
||||||
|
}
|
||||||
|
|
||||||
function secondary_demod_init()
|
function secondary_demod_init()
|
||||||
{
|
{
|
||||||
$("#openwebrx-panel-digimodes")[0].openwebrxHidden = true;
|
$("#openwebrx-panel-digimodes")[0].openwebrxHidden = true;
|
||||||
|
secondary_demod_canvas_container = $("#openwebrx-digimode-canvas-container")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondary_demod_start(subtype)
|
function secondary_demod_start(subtype)
|
||||||
{
|
{
|
||||||
|
secondary_demod_canvases_initialized = false;
|
||||||
ws.send("SET secondary_mod="+subtype);
|
ws.send("SET secondary_mod="+subtype);
|
||||||
secondary_demod = subtype;
|
secondary_demod = subtype;
|
||||||
}
|
}
|
||||||
@ -2246,11 +2301,12 @@ function secondary_demod_stop()
|
|||||||
ws.send("SET secondary_mod=off");
|
ws.send("SET secondary_mod=off");
|
||||||
secondary_demod = false;
|
secondary_demod = false;
|
||||||
secondary_demod_waterfall_queue = [];
|
secondary_demod_waterfall_queue = [];
|
||||||
|
secondary_demod_remove_canvases();
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondary_demod_waterfall_add_queue(x)
|
function secondary_demod_waterfall_add_queue(x)
|
||||||
{
|
{
|
||||||
secondary_demod_waterfall_queue.push(what);
|
secondary_demod_waterfall_queue.push(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondary_demod_push_binary_data(x)
|
function secondary_demod_push_binary_data(x)
|
||||||
@ -2274,14 +2330,33 @@ function secondary_demod_close_window()
|
|||||||
toggle_panel("openwebrx-panel-digimodes", false);
|
toggle_panel("openwebrx-panel-digimodes", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondary_demod_waterfall_add(x)
|
function secondary_demod_waterfall_add(data)
|
||||||
{
|
{
|
||||||
|
if(!secondary_demod) return;
|
||||||
|
var w=secondary_fft_size;
|
||||||
|
|
||||||
|
//Add line to waterfall image
|
||||||
|
var oneline_image = secondary_demod_current_canvas_context.createImageData(w,1);
|
||||||
|
for(x=0;x<w;x++)
|
||||||
|
{
|
||||||
|
var color=waterfall_mkcolor(data[x]+30);
|
||||||
|
for(i=0;i<4;i++) oneline_image.data[x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw image
|
||||||
|
console.log(oneline_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;});
|
||||||
|
secondary_demod_canvases_update_top();
|
||||||
|
if(secondary_demod_current_canvas_actual_line<0) secondary_demod_swap_canvases();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var secondary_demod_canvases_initialized = false;
|
||||||
|
|
||||||
function secondary_demod_waterfall_dequeue()
|
function secondary_demod_waterfall_dequeue()
|
||||||
{
|
{
|
||||||
if(!secondary_demod) return;
|
if(!secondary_demod || !secondary_demod_canvases_initialized) return;
|
||||||
if(secondary_demod_waterfall_queue.length) secondary_demod_waterfall_add(waterfall_queue.shift());
|
if(secondary_demod_waterfall_queue.length) secondary_demod_waterfall_add(secondary_demod_waterfall_queue.shift());
|
||||||
if(secondary_demod_waterfall_queue.length>Math.max(fft_fps/2,20)) //in case of fft overflow
|
if(secondary_demod_waterfall_queue.length>Math.max(fft_fps/2,20)) //in case of fft overflow
|
||||||
{
|
{
|
||||||
console.log("secondary waterfall overflow, queue length:", secondary_demod_waterfall_queue.length);
|
console.log("secondary waterfall overflow, queue length:", secondary_demod_waterfall_queue.length);
|
||||||
|
10
openwebrx.py
10
openwebrx.py
@ -466,6 +466,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
dsp.set_format_conversion(cfg.format_conversion)
|
dsp.set_format_conversion(cfg.format_conversion)
|
||||||
dsp.set_offset_freq(0)
|
dsp.set_offset_freq(0)
|
||||||
dsp.set_bpf(-4000,4000)
|
dsp.set_bpf(-4000,4000)
|
||||||
|
dsp.set_secondary_fft_size(cfg.digimodes_fft_size)
|
||||||
dsp.nc_port=cfg.iq_server_port
|
dsp.nc_port=cfg.iq_server_port
|
||||||
apply_csdr_cfg_to_dsp(dsp)
|
apply_csdr_cfg_to_dsp(dsp)
|
||||||
myclient.dsp=dsp
|
myclient.dsp=dsp
|
||||||
@ -531,7 +532,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
secondary_demod_data=dsp.read_secondary_demod(1)
|
secondary_demod_data=dsp.read_secondary_demod(1)
|
||||||
myclient.loopstat=423
|
myclient.loopstat=423
|
||||||
if len(secondary_demod_data) == 0: break
|
if len(secondary_demod_data) == 0: break
|
||||||
print "len(secondary_demod_data)", len(secondary_demod_data), secondary_demod_data #TODO digimodes
|
# print "len(secondary_demod_data)", len(secondary_demod_data), secondary_demod_data #TODO digimodes
|
||||||
rxws.send(self, secondary_demod_data, "DAT ")
|
rxws.send(self, secondary_demod_data, "DAT ")
|
||||||
except: break
|
except: break
|
||||||
|
|
||||||
@ -579,7 +580,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
myclient.loopstat=550
|
myclient.loopstat=550
|
||||||
dsp.start()
|
dsp.start()
|
||||||
dsp_initialized=True
|
dsp_initialized=True
|
||||||
elif param_name=="secondary_mod" and cfg.enable_digimodes:
|
elif param_name=="secondary_mod" and cfg.digimodes_enable:
|
||||||
if (dsp.get_secondary_demodulator() != param_value):
|
if (dsp.get_secondary_demodulator() != param_value):
|
||||||
if dsp_initialized: dsp.stop()
|
if dsp_initialized: dsp.stop()
|
||||||
if param_value == "off":
|
if param_value == "off":
|
||||||
@ -588,8 +589,9 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
else:
|
else:
|
||||||
dsp.set_secondary_demodulator(param_value)
|
dsp.set_secondary_demodulator(param_value)
|
||||||
do_secondary_demod = True
|
do_secondary_demod = True
|
||||||
|
rxws.send(self, "MSG secondary_fft_size={0} secondary_setup".format(cfg.digimodes_fft_size))
|
||||||
if dsp_initialized: dsp.start()
|
if dsp_initialized: dsp.start()
|
||||||
elif param_name=="secondary_offset_freq" and 0 <= int(param_value) <= dsp.if_samp_rate()/2 and cfg.enable_digimodes:
|
elif param_name=="secondary_offset_freq" and 0 <= int(param_value) <= dsp.if_samp_rate()/2 and cfg.digimodes_enable:
|
||||||
dsp.set_secondary_offset_freq(int(param_value))
|
dsp.set_secondary_offset_freq(int(param_value))
|
||||||
else:
|
else:
|
||||||
print "[openwebrx-httpd:ws] invalid parameter"
|
print "[openwebrx-httpd:ws] invalid parameter"
|
||||||
@ -684,7 +686,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
("%[WATERFALL_MIN_LEVEL]",str(cfg.waterfall_min_level)),
|
("%[WATERFALL_MIN_LEVEL]",str(cfg.waterfall_min_level)),
|
||||||
("%[WATERFALL_MAX_LEVEL]",str(cfg.waterfall_max_level)),
|
("%[WATERFALL_MAX_LEVEL]",str(cfg.waterfall_max_level)),
|
||||||
("%[WATERFALL_AUTO_LEVEL_MARGIN]","[%d,%d]"%cfg.waterfall_auto_level_margin),
|
("%[WATERFALL_AUTO_LEVEL_MARGIN]","[%d,%d]"%cfg.waterfall_auto_level_margin),
|
||||||
("%[ENABLE_DIGIMODES]",("true" if cfg.enable_digimodes else "false"))
|
("%[DIGIMODES_ENABLE]",("true" if cfg.digimodes_enable else "false"))
|
||||||
)
|
)
|
||||||
for rule in replace_dictionary:
|
for rule in replace_dictionary:
|
||||||
while data.find(rule[0])!=-1:
|
while data.find(rule[0])!=-1:
|
||||||
|
Loading…
Reference in New Issue
Block a user