add FI panadapter

This commit is contained in:
F4HTB 2020-11-10 03:11:31 +00:00
parent a09c3afc90
commit dd833d6b54
17 changed files with 434 additions and 1 deletions

179
UHRR
View File

@ -16,6 +16,9 @@ import datetime
import configparser
import sys
import Hamlib
from rtlsdr import RtlSdr
import numpy as np
import math
############ Global variables ##################################
CTRX=None
@ -23,6 +26,154 @@ config = configparser.ConfigParser()
config.read('UHRR.conf')
e="No"
############ Generate and send FFT from RTLSDR ##############
is_rtlsdr_present = True
try:
sdr = RtlSdr()
sdr.sample_rate = int(config['PANADAPTER']['sample_rate']) # Hz
sdr.center_freq = int(config['PANADAPTER']['center_freq']) # Hz
sdr.freq_correction = int(config['PANADAPTER']['freq_correction']) # PPM
sdr.gain = int(config['PANADAPTER']['gain']) #or 'auto'
FFTSIZE=2048
nbBuffer=24
nbsamples=nbBuffer/2*FFTSIZE
ptime=nbsamples/int(config['PANADAPTER']['sample_rate'])
except:
is_rtlsdr_present = False
AudioPanaHandlerClients = []
class loadFFTdata(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.get_log_power_spectrum_w = np.empty(FFTSIZE)
for i in range(FFTSIZE):
self.get_log_power_spectrum_w[i] = 0.5 * (1. - math.cos((2 * math.pi * i) / (FFTSIZE - 1)))
def run(self):
while True:
time.sleep(0.2)
self.getFFT_data()
def get_log_power_spectrum(self,data):
pulse = 10
rejected_count = 0
power_spectrum = np.zeros(FFTSIZE)
db_adjust = 20. * math.log10(FFTSIZE * 2 ** 15)
# Time-domain analysis: Often we have long normal signals interrupted
# by huge wide-band pulses that degrade our power spectrum average.
# We find the "normal" signal level, by computing the median of the
# absolute value. We only do this for the first buffer of a chunk,
# using the median for the remaining buffers in the chunk.
# A "noise pulse" is a signal level greater than some threshold
# times the median. When such a pulse is found, we skip the current
# buffer. It would be better to blank out just the pulse, but that
# would be more costly in CPU time.
# Find the median abs value of first buffer to use for this chunk.
td_median = np.median(np.abs(data[:FFTSIZE]))
# Calculate our current threshold relative to measured median.
td_threshold = pulse * td_median
nbuf_taken = 0 # Actual number of buffers accumulated
for ic in range(nbBuffer-1):
start=ic * int(FFTSIZE/2)
end=start+FFTSIZE
td_segment = data[start:end]
# remove the 0hz spike
td_segment = np.subtract(td_segment, np.average(td_segment))
td_max = np.amax(np.abs(td_segment)) # Do we have a noise pulse?
if td_max < td_threshold: # No, get pwr spectrum etc.
# EXPERIMENTAL TAPERfd
td_segment *= self.get_log_power_spectrum_w
fd_spectrum = np.fft.fft(td_segment)
# Frequency-domain:
# Rotate array to place 0 freq. in center. (It was at left.)
fd_spectrum_rot = np.fft.fftshift(fd_spectrum)
# Compute the real-valued squared magnitude (ie power) and
# accumulate into pwr_acc.
# fastest way to sum |z|**2 ??
nbuf_taken += 1
power_spectrum = power_spectrum + \
np.real(fd_spectrum_rot * fd_spectrum_rot.conj())
else: # Yes, abort buffer.
rejected_count += 1
# if DEBUG: print "REJECT! %d" % self.rejected_count
if nbuf_taken > 0:
power_spectrum = power_spectrum / nbuf_taken # normalize the sum.
else:
power_spectrum = np.ones(FFTSIZE) # if no good buffers!
# Convert to dB. Note log(0) = "-inf" in Numpy. It can happen if ADC
# isn't working right. Numpy issues a warning.
log_power_spectrum = 10. * np.log10(power_spectrum)
return log_power_spectrum - db_adjust # max poss. signal = 0 dB
def getFFT_data(self):
samples = sdr.read_samples(nbsamples)
samples = np.imag(samples) + 1j * np.real(samples)
max_pow = 0
min_pow = 0
power = self.get_log_power_spectrum(samples)
power += 60
# search whole data set for maximum and minimum value
for dat in power:
if dat > max_pow:
max_pow = dat
elif dat < min_pow:
min_pow = dat
asciilist=""
for dat in power:
try:
asciilist+=(chr(self.FFTmymap(dat, min_pow, max_pow, 0, 125)))
except (RuntimeError, TypeError, NameError):
asciilist+=chr(0)
pass
for c in AudioPanaHandlerClients:
c.fftframes.append(asciilist)
def FFTmymap(self, x, in_min, in_max, out_min, out_max):
ret=int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
return ret
class panFFTHandler(tornado.websocket.WebSocketHandler):
@tornado.gen.coroutine
def sendFFT(self):
global ptime
try:
while len(self.fftframes)>0:
for i in range(8):
yield self.write_message(self.fftframes[0][i*256:(i+1)*256])
yield self.write_message("NewLine")
del self.fftframes[0]
except:
return None
tornado.ioloop.IOLoop.instance().add_timeout(datetime.timedelta(seconds=ptime), self.sendFFT)
def open(self):
global is_rtlsdr_present
print('new connection on FFT socket, is_rtlsdr_present = '+str(is_rtlsdr_present))
if self not in AudioPanaHandlerClients:
AudioPanaHandlerClients.append(self)
self.fftframes = []
if is_rtlsdr_present:
self.sendFFT()
def on_close(self):
print('connection closed for FFT socket')
############ websocket for send RX audio from TRX ##############
flagWavstart = False
AudioRXHandlerClients = []
@ -289,6 +440,8 @@ class ControlTRX(tornado.websocket.WebSocketHandler):
self.sendPTINFOS()
CTRX.setPower(1)
print('new connection on ControlTRX socket.')
if(is_rtlsdr_present):
self.write_message("panfft")
@tornado.gen.coroutine
def on_message(self, data) :
@ -416,7 +569,28 @@ class ConfigHandler(tornado.web.RequestHandler):
self.write("""<option value=\"True\">\"True\"</option>""")
self.write("""<option value=\"False\">\"False\"</option>""")
self.write("""</select><br/><br/>""")
self.write("""[PANADAPTER]<br/><br/>""")
self.write("""PANADAPTER FI frequency (hz):<input type="text" name="PANADAPTER.center_freq" value="""+config['PANADAPTER']['center_freq']+"""><br/><br/>""")
self.write("""HAMLIB radio rate (samples/s):<select name="PANADAPTER.sample_rate">""")
if(config['PANADAPTER']['sample_rate']!="null"):
self.write("""<option value="""+config['PANADAPTER']['sample_rate']+""" selected>"""+config['PANADAPTER']['sample_rate']+"""</option>""")
self.write("""<option value=3200000>3200000</option>""")
self.write("""<option value=2880000>2880000</option>""")
self.write("""<option value=2400000>2400000</option>""")
self.write("""<option value=1800000>1800000</option>""")
self.write("""<option value=1440000>1440000</option>""")
self.write("""<option value=1200000>1200000</option>""")
self.write("""<option value=1020000>1020000</option>""")
self.write("""<option value=960000>960000</option>""")
self.write("""<option value=250000>250000</option>""")
self.write("""</select><br/><br/>""")
self.write("""PANADAPTER frequency correction (ppm):<input type="text" name="PANADAPTER.freq_correction" value="""+config['PANADAPTER']['freq_correction']+"""><br/><br/>""")
self.write("""PANADAPTER initial gain:<input type="text" name="PANADAPTER.gain" value="""+config['PANADAPTER']['gain']+"""><br/><br/>""")
self.write("""<input type="submit" value="Save & Restart server"><br/><br/></form>Possible problem:"""+e+"""</html>""")
def post(self):
@ -437,6 +611,10 @@ class ConfigHandler(tornado.web.RequestHandler):
if __name__ == "__main__":
try:
if is_rtlsdr_present:
threadFFT = loadFFTdata()
threadFFT.start()
threadloadWavdata = loadWavdata()
threadloadWavdata.start()
@ -454,6 +632,7 @@ if __name__ == "__main__":
(r'/audioRX', AudioRXHandler),
(r'/audioTX', AudioTXHandler),
(r'/CTRX', ControlTRX),
(r'/panFFT', panFFTHandler),
(r'/CONFIG', ConfigHandler),
(r'/', MainHandler),
(r'/(.*)', tornado.web.StaticFileHandler, { 'path' : './www' })

View File

@ -19,3 +19,9 @@ rig_model = FT817
trxautopower = True
rig_rate = 38400
[PANADAPTER]
sample_rate = 250000
center_freq = 68330000
freq_correction = 1
gain = 100

12
www/controls.js vendored
View File

@ -113,9 +113,19 @@ function powertogle()
poweron = false;
button_unlight_all("div-filtershortcut");
button_unlight_all("div-mode_menu");
document.getElementById("div-panfft").style.display = "none";
if (typeof panfft !== 'undefined') {panfft.close();}
}
}
window.addEventListener('beforeunload', function (e) {
if(poweron)e.preventDefault();
if (typeof panfft !== 'undefined') {
panfft.close();
e.returnValue = '';
}
});
function check_connected() {
setTimeout(function () {
if (wsAudioRX.readyState === WebSocket.OPEN && wsAudioTX.readyState === WebSocket.OPEN && wsControlTRX.readyState === WebSocket.OPEN){document.getElementById("ombre-body").style.display = "none";document.getElementById("pop-upspinner").style.display = "none";}
@ -378,12 +388,12 @@ function ControlTRX_start(){
var SignalLevel=0;
function wsControlTRXcrtol( msg ){
console.log(String(msg.data));
words = String(msg.data).split(':');
if(words[0] == "PONG"){showlatency();}
else if(words[0] == "getFreq"){showTRXfreq(words[1]);}
else if(words[0] == "getMode"){showTRXmode(words[1]);}
else if(words[0] == "getSignalLevel"){SignalLevel=words[1];drawRXSmeter();}
else if(words[0] == "panfft"){document.getElementById("div-panfft").style.display = "block";}
}
function ControlTRX_stop()

BIN
www/img/panfft.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -163,6 +163,7 @@
<label id="callsign"></label>
<div id="div-conf"><a href="/CONFIG" target="_UHRRconfig"><img src="img/config.png"></a></div>
<div id="div-panfft"><a onclick="panfft = window.open( this.href, 'UHRRpanfft', 'width=1000, height=1000, menubar=no, toolbar=no, location=no, resizable=yes, scrollbars=no, status=no, dependent=yes'); return false;" href="/panfft.html" target="_UHRRpanfft"><img src="img/panfft.png"></a></div>
<canvas id="canRXsmeter" width=250 height=50 ></canvas>

64
www/panfft.css Normal file
View File

@ -0,0 +1,64 @@
body {
color: white;
font:normal bold 14px tahoma;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding:0px;
margin:0px;
}
#div-sp
{
position:relative;
width:100%;
height:45%;
padding:0px;
margin:0px;
}
#cansp{
width:100%;
height:100%;
float:center;
background-color:black;
}
#div-wf
{
position:relative;
width:100%;
height:45%;
padding:0px;
margin:0px;
}
#canwf{
width:100%;
height:100%;
background:#00007f;
background-color:bleu;
}
#div-ctrl
{
background-color:#171717;
position:relative;
width:100%;
height:10%;
padding:0px;
margin:0px;
}
#div-scoketscontrols > img
{
margin-right:5px;
width:25px;
height:25px;
}

22
www/panfft.html Normal file
View File

@ -0,0 +1,22 @@
<html>
<head>
<meta charset="UTF-8">
<title>FFT Universal Hamradio Remote by F4HTB</title>
<link rel="stylesheet" type="text/css" href="panfft.css">
</head>
<body onload="bodyload();">
<div id="div-princ">
<div id="div-sp">
<canvas id="cansp" width=2048 height=256></canvas>
</div>
<div id="div-wf">
<canvas id="canwf" width=2048 height=256></canvas>
</div>
<div id="div-ctrl">
aaa
<div id="div-scoketscontrols"><img src="img/critsred.png">wsFFT</div>
</div>
</div>
<script src="panfft.js"></script>
</body>
</html>

135
www/panfft.js Normal file
View File

@ -0,0 +1,135 @@
const canvas_width=2048;
const canvas_height=256;
var wshFFT = "";
function bodyload(){
initFFT();
startFFT();
}
function startFFT(){
document.getElementById("div-scoketscontrols").innerHTML='<img src="img/critsgrey.png">wsFFT';
wshFFT = new WebSocket( 'wss://' + window.location.href.split( '/' )[2] + '/panFFT' );
wshFFT.onopen = appendwshFFTOpen;
wshFFT.onmessage = showFFT;
wshFFT.onerror = appendwshFFTError;
wshFFT.onclose = appendwshFFTclose;
}
function appendwshFFTclose(){
document.getElementById("div-scoketscontrols").innerHTML='<img src="img/critsred.png">wsFFT';
}
function appendwshFFTOpen(){
document.getElementById("div-scoketscontrols").innerHTML='<img src="img/critsgreen.png">wsFFT';
}
function appendwshFFTError(err){
document.getElementById("div-scoketscontrols").innerHTML='<img src="img/critsred.png">wsFFT';
wshFFT.close();
startFFT();
}
function stopFFT(){
wshFFT.close();
initFFT();
}
function initFFT(){
initCanvas("cansp");
initCanvas("canwf");
}
var globmsg = "";
function showFFT( msg ){
if(msg.data != "NewLine"){globmsg += msg.data;}
else{
if(globmsg.length == canvas_width){
let FFTdata = [];
FFTdata = globmsg.split('');
FFTdata.forEach((item, index) => { FFTdata[index]= (item.charCodeAt(0))<< 1; }) // FFTdata[index]= Math.round(item.charCodeAt(0))*2; })
SetImageDataWF(FFTdata);
SetImageDataSP(FFTdata);
}
console.log(globmsg.length);
console.log(canvas_width);
globmsg="";
}
}
const canvasSP = document.getElementById("cansp"),ctxSP = canvasSP.getContext("2d");// imgObjSP = ctxSP.createImageData(canvasSP.width, canvas_height);
const midle = canvas_width*2;
function SetImageDataSP(datas) {
imgObjSP = new ImageData(canvasSP.width, canvas_height);
let i = 0;
for(let Line = 0; Line < canvas_height; Line++){
i = 4*(Line * canvas_width);
y = canvas_height - Line;
for (let px = 0; px < canvas_width; px++) {
if(y <= datas[px]){
//imgObjSP.data[i] = 0; // red
imgObjSP.data[++i] = 215; // green
imgObjSP.data[++i] = 233; // blue
imgObjSP.data[++i] = 255; // alpha
++i;
}
else{i += 4 ;}
}
i -= midle ;
//imgObjSP.data[i] = 0; // red
imgObjSP.data[++i] = 255; // green
imgObjSP.data[++i] = 0; // blue
imgObjSP.data[++i] = 255; // alpha
}
ctxSP.putImageData(imgObjSP, 0, 0);
}
const canvasWF = document.getElementById("canwf"),ctxWF = canvasWF.getContext("2d"),imgObjWF = ctxWF.createImageData(canvasWF.width, 1);
//const colMap = [[0,0,0,255],[40,0,0,255],[56,0,4,255],[61,0,9,255],[64,0,12,255],[66,0,14,255],[69,0,17,255],[73,0,20,255],[74,0,22,255],[78,0,25,255],[79,0,27,255],[83,0,30,255],[85,0,31,255],[86,0,33,255],[90,0,36,255],[91,0,38,255],[93,0,39,255],[95,0,41,255],[96,0,43,255],[100,0,46,255],[102,0,47,255],[103,0,49,255],[105,0,51,255],[107,0,52,255],[108,0,54,255],[110,0,55,255],[112,0,57,255],[112,0,57,255],[113,0,58,255],[115,0,60,255],[117,0,62,255],[119,0,63,255],[120,0,65,255],[122,0,66,255],[124,0,68,255],[125,0,70,255],[127,0,71,255],[129,0,73,255],[129,0,73,255],[130,0,74,255],[132,0,76,255],[134,0,78,255],[136,0,79,255],[137,0,81,255],[139,0,82,255],[141,0,84,255],[142,0,86,255],[144,0,87,255],[146,0,89,255],[147,0,90,255],[149,0,92,255],[151,0,94,255],[151,0,94,255],[153,0,95,255],[154,0,97,255],[156,0,98,255],[158,0,100,255],[159,0,102,255],[161,0,103,255],[163,0,105,255],[164,0,106,255],[166,0,108,255],[168,0,109,255],[170,0,111,255],[171,0,113,255],[173,0,114,255],[175,0,116,255],[176,0,117,255],[178,0,119,255],[180,0,121,255],[180,0,121,255],[181,0,122,255],[183,0,124,255],[185,0,125,255],[187,0,127,255],[188,0,129,255],[190,0,130,255],[192,0,132,255],[193,0,133,255],[195,0,135,255],[197,0,137,255],[198,0,138,255],[200,0,140,255],[202,0,141,255],[204,0,143,255],[204,0,143,255],[205,0,145,255],[207,0,146,255],[209,0,148,255],[210,0,149,255],[212,0,151,255],[214,0,153,255],[215,0,154,255],[217,0,156,255],[219,0,157,255],[221,0,159,255],[222,0,160,255],[222,0,160,255],[224,0,162,255],[226,0,164,255],[227,0,165,255],[229,0,167,255],[231,0,168,255],[232,0,170,255],[234,0,172,255],[236,0,173,255],[238,0,175,255],[238,0,175,255],[239,0,176,255],[241,0,178,255],[243,0,180,255],[244,0,181,255],[246,0,183,255],[248,2,184,255],[249,4,186,255],[249,4,186,255],[249,4,186,255],[251,6,188,255],[251,6,188,255],[253,9,189,255],[253,9,189,255],[255,11,191,255],[255,11,191,255],[255,13,192,255],[255,13,192,255],[255,13,192,255],[255,16,194,255],[255,18,196,255],[255,20,197,255],[255,20,197,255],[255,23,199,255],[255,25,200,255],[255,27,202,255],[255,30,204,255],[255,32,205,255],[255,34,207,255],[255,37,208,255],[255,37,208,255],[255,39,210,255],[255,41,211,255],[255,44,213,255],[255,46,215,255],[255,48,216,255],[255,51,218,255],[255,53,219,255],[255,53,219,255],[255,55,221,255],[255,57,223,255],[255,60,224,255],[255,62,226,255],[255,64,227,255],[255,67,229,255],[255,67,229,255],[255,69,231,255],[255,71,232,255],[255,74,234,255],[255,76,235,255],[255,78,237,255],[255,81,239,255],[255,81,239,255],[255,83,240,255],[255,85,242,255],[255,88,243,255],[255,90,245,255],[255,92,247,255],[255,95,248,255],[255,95,248,255],[255,97,250,255],[255,99,251,255],[255,102,253,255],[255,104,255,255],[255,106,255,255],[255,106,255,255],[255,108,255,255],[255,111,255,255],[255,113,255,255],[255,115,255,255],[255,115,255,255],[255,118,255,255],[255,120,255,255],[255,122,255,255],[255,122,255,255],[255,125,255,255],[255,127,255,255],[255,129,255,255],[255,129,255,255],[255,132,255,255],[255,134,255,255],[255,136,255,255],[255,136,255,255],[255,139,255,255],[255,141,255,255],[255,143,255,255],[255,143,255,255],[255,146,255,255],[255,148,255,255],[255,150,255,255],[255,150,255,255],[255,153,255,255],[255,155,255,255],[255,155,255,255],[255,157,255,255],[255,159,255,255],[255,159,255,255],[255,162,255,255],[255,164,255,255],[255,164,255,255],[255,166,255,255],[255,169,255,255],[255,171,255,255],[255,171,255,255],[255,173,255,255],[255,176,255,255],[255,176,255,255],[255,178,255,255],[255,180,255,255],[255,180,255,255],[255,183,255,255],[255,185,255,255],[255,185,255,255],[255,187,255,255],[255,190,255,255],[255,190,255,255],[255,192,255,255],[255,194,255,255],[255,197,255,255],[255,197,255,255],[255,199,255,255],[255,201,255,255],[255,204,255,255],[255,204,255,255],[255,206,255,255],[255,208,255,255],[255,210,255,255],[255,210,255,255],[255,213,255,255],[255,215,255,255],[255,217,255,255],[255,217,255,255],[255,220,255,255],[255,222,255,255],[255,224,255,255],[255,227,255,255],[255,229,255,255],[255,229,255,255],[255,231,255,255],[255,234,255,255],[255,236,255,255],[255,238,255,255],[255,241,255,255],[255,243,255,255],[255,243,255,255],[255,245,255,255],[255,248,255,255],[255,250,255,255],[255,255,255,255]];
const colMap = [[0,0,127,255],[0,0,131,255],[0,0,135,255],[0,0,139,255],[0,0,143,255],[0,0,147,255],[0,0,151,255],[0,0,155,255],[0,0,159,255],[0,0,163,255],[0,0,167,255],[0,0,171,255],[0,0,175,255],[0,0,179,255],[0,0,183,255],[0,0,187,255],[0,0,191,255],[0,0,195,255],[0,0,199,255],[0,0,203,255],[0,0,207,255],[0,0,211,255],[0,0,215,255],[0,0,219,255],[0,0,223,255],[0,0,227,255],[0,0,231,255],[0,0,235,255],[0,0,239,255],[0,0,243,255],[0,0,247,255],[0,0,251,255],[0,0,255,255],[0,4,255,255],[0,8,255,255],[0,12,255,255],[0,16,255,255],[0,20,255,255],[0,24,255,255],[0,28,255,255],[0,32,255,255],[0,36,255,255],[0,40,255,255],[0,44,255,255],[0,48,255,255],[0,52,255,255],[0,56,255,255],[0,60,255,255],[0,64,255,255],[0,68,255,255],[0,72,255,255],[0,76,255,255],[0,80,255,255],[0,84,255,255],[0,88,255,255],[0,92,255,255],[0,96,255,255],[0,100,255,255],[0,104,255,255],[0,108,255,255],[0,112,255,255],[0,116,255,255],[0,120,255,255],[0,124,255,255],[0,128,255,255],[0,132,255,255],[0,136,255,255],[0,140,255,255],[0,144,255,255],[0,148,255,255],[0,152,255,255],[0,156,255,255],[0,160,255,255],[0,164,255,255],[0,168,255,255],[0,172,255,255],[0,176,255,255],[0,180,255,255],[0,184,255,255],[0,188,255,255],[0,192,255,255],[0,196,255,255],[0,200,255,255],[0,204,255,255],[0,208,255,255],[0,212,255,255],[0,216,255,255],[0,220,255,255],[0,224,255,255],[0,228,255,255],[0,232,255,255],[0,236,255,255],[0,240,255,255],[0,244,255,255],[0,248,255,255],[0,252,255,255],[1,255,253,255],[5,255,249,255],[9,255,245,255],[13,255,241,255],[17,255,237,255],[21,255,233,255],[25,255,229,255],[29,255,225,255],[33,255,221,255],[37,255,217,255],[41,255,213,255],[45,255,209,255],[49,255,205,255],[53,255,201,255],[57,255,197,255],[61,255,193,255],[65,255,189,255],[69,255,185,255],[73,255,181,255],[77,255,177,255],[81,255,173,255],[85,255,169,255],[89,255,165,255],[93,255,161,255],[97,255,157,255],[101,255,153,255],[105,255,149,255],[109,255,145,255],[113,255,141,255],[117,255,137,255],[121,255,133,255],[125,255,129,255],[129,255,125,255],[133,255,121,255],[137,255,117,255],[141,255,113,255],[145,255,109,255],[149,255,105,255],[153,255,101,255],[157,255,97,255],[161,255,93,255],[165,255,89,255],[169,255,85,255],[173,255,81,255],[177,255,77,255],[181,255,73,255],[185,255,69,255],[189,255,65,255],[193,255,61,255],[197,255,57,255],[201,255,53,255],[205,255,49,255],[209,255,45,255],[213,255,41,255],[217,255,37,255],[221,255,33,255],[225,255,29,255],[229,255,25,255],[233,255,21,255],[237,255,17,255],[241,255,13,255],[245,255,9,255],[249,255,5,255],[253,255,1,255],[255,252,0,255],[255,248,0,255],[255,244,0,255],[255,240,0,255],[255,236,0,255],[255,232,0,255],[255,228,0,255],[255,224,0,255],[255,220,0,255],[255,216,0,255],[255,212,0,255],[255,208,0,255],[255,204,0,255],[255,200,0,255],[255,196,0,255],[255,192,0,255],[255,188,0,255],[255,184,0,255],[255,180,0,255],[255,176,0,255],[255,172,0,255],[255,168,0,255],[255,164,0,255],[255,160,0,255],[255,156,0,255],[255,152,0,255],[255,148,0,255],[255,144,0,255],[255,140,0,255],[255,136,0,255],[255,132,0,255],[255,128,0,255],[255,124,0,255],[255,120,0,255],[255,116,0,255],[255,112,0,255],[255,108,0,255],[255,104,0,255],[255,100,0,255],[255,96,0,255],[255,92,0,255],[255,88,0,255],[255,84,0,255],[255,80,0,255],[255,76,0,255],[255,72,0,255],[255,68,0,255],[255,64,0,255],[255,60,0,255],[255,56,0,255],[255,52,0,255],[255,48,0,255],[255,44,0,255],[255,40,0,255],[255,36,0,255],[255,32,0,255],[255,28,0,255],[255,24,0,255],[255,20,0,255],[255,16,0,255],[255,12,0,255],[255,8,0,255],[255,4,0,255],[255,0,0,255],[251,0,0,255],[247,0,0,255],[243,0,0,255],[239,0,0,255],[235,0,0,255],[231,0,0,255],[227,0,0,255],[223,0,0,255],[219,0,0,255],[215,0,0,255],[211,0,0,255],[207,0,0,255],[203,0,0,255],[199,0,0,255],[195,0,0,255],[191,0,0,255],[187,0,0,255],[183,0,0,255],[179,0,0,255],[175,0,0,255],[171,0,0,255],[167,0,0,255],[163,0,0,255],[159,0,0,255],[155,0,0,255],[151,0,0,255],[147,0,0,255],[143,0,0,255],[139,0,0,255],[135,0,0,255],[131,0,0,255],[127,0,0,255]];
function SetImageDataWF(datas) {
console.log("aaa");
var canvasBuffer = document.createElement("canvas");
canvasBuffer.width = canvas_width;
canvasBuffer.height = canvas_height;
var ctxBuffer = canvasBuffer.getContext("2d");
ctxBuffer.clearRect(0,0,canvas_width,canvas_height); //clear buffer
ctxBuffer.drawImage(canvasWF,0,0); //store display data in buffer
ctxWF.clearRect(0,0,canvas_width,canvas_height); //clear display
ctxWF.drawImage(canvasBuffer,0,1); //copy buffer to display
var px=0;
var i=0;
for (px = 0; px < canvas_width; px++) {
i = 4*px;
// let rgba = colMap[datas[px]]; // lookup color rgba values
imgObjWF.data[i] = colMap[datas[px]][0]; // red
imgObjWF.data[i+1] = colMap[datas[px]][1]; // green
imgObjWF.data[i+2] = colMap[datas[px]][2]; // blue
imgObjWF.data[i+3] = colMap[datas[px]][3]; // alpha
}
imgObjWF.data[midle] = 0;
imgObjWF.data[midle+1] = 255;
imgObjWF.data[midle+2] = 0;
imgObjWF.data[midle+3] = 255;
ctxWF.putImageData(imgObjWF, 0, 0);
}
function initCanvas(cvsIDwf) {
var canvas = document.getElementById(cvsIDwf);
var ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas_width, canvas_height);
}

View File

@ -285,6 +285,22 @@ overflow: hidden;
height:25px;
}
#div-panfft
{
position:absolute;
left: 1750px;
top:55px;
width: 580px;
display: none;
}
#div-panfft > a > img
{
margin-right:5px;
width:25px;
height:25px;
}
#div-latencymeter
{
font:normal bold 25px tahoma;