
index.jsというプログラムはHTTPサーバとして動作し、 接続が要求された時にあなたのWebブラウザにindex.htmlファイルを送ります。
index.js
16 var http = require('http');
17 var fs = require('fs');
18 var index = fs.readFileSync(__dirname + '/index.html');
19 var app = http.createServer(function(req, res) {
20 res.writeHead(200, {'Content-Type' : 'text/html'});
21 res.end(index);
22 })
23 .listen(3000);
index.htmlファイルは、ウォーターフォール画面を表示したりオーディオ信号を受信して再生するためのJavaScriptのコードを含んでいます。
index.html
<!doctype html>
<html>
<head>
<style>
* { margin: 0; padding: 0; box-sizing : border-box; }
body { font: 13px Helvetica, Arial; }
form { background: # 000; padding: 3px; position: fixed; bottom: 0; width: 100% ; }
form input { border: 0; padding: 10px; width: 80% ; margin-right : .5% ; }
form button { width: 15% ; background: rgb(143, 188, 143); border: none; padding: 10px; }
#messages{list-style-type : none; margin : 0; padding : 0; }
#messages li{padding : 5px 10px; }
#messages li : nth-child(odd){background : #eee; }
#messages {margin-bottom : 40px }
#messages {font-size : 2em }
#btn1 {position : fixed; top : 10px; left : 10px; font-size : 2em; background-color: darkseagreen }
#btn2 {position : fixed; top : 10px; left : 60px; font-size : 2em; background-color: darkseagreen }
#btn3 {position : fixed; top : 10px; left : 150px; font-size : 2em; background-color: cornsilk }
#btn4 {position : fixed; top : 10px; left : 230px; font-size : 2em; background-color: cornsilk }
#btn5 {position : fixed; top : 10px; left : 310px; font-size : 2em; background-color: paleturquoise }
#btn6 {position : fixed; top : 10px; left : 390px; font-size : 2em; background-color: paleturquoise }
#btn7 {position : fixed; top : 10px; left : 470px; font-size : 2em; background-color: thistle }
#btn8 {position : fixed; top : 10px; left : 550px; font-size : 2em; background-color: thistle }
#mycanvas0 {position : fixed; top : 70px; left : 10px; font-size : 2em }
#mycanvas1 {position : fixed; top : 90px; left : 10px; font-size : 2em }
#mycanvas2 {position : fixed; top : 620px; left : 10px; font-size : 2em }
</style>
</head>
<body>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script src='/socket.io/socket.io.js'></script>
<button id="btn1"><font size="5">CQ</font></button>
<button id="btn2"><font size="5">QRZ?</font></button>
<button id="btn3"><font size="5">VFO+</font></button>
<button id="btn4"><font size="5">VFO-</font></button>
<button id="btn5"><font size="5">BFO+</font></button>
<button id="btn6"><font size="5">BFO-</font></button>
<button id="btn7"><font size="5">BFO+</font></button>
<button id="btn8"><font size="5">BFO-</font></button>
<div id="messages"></div>
<form action="">
<input id="m" autocomplete="off"/><button>Send</button>
</form>
<canvas id="mycanvas0" width="512" height= "20" style="background:white;"></canvas>
<canvas id="mycanvas1" width="512" height="512" style="background:white;"></canvas>
<canvas id="mycanvas2" width="280" height= "60" style="background:cornsilk;"></canvas>
<script>
function colormap(charcode) { // 0x00~0xff
var tmp = charcode / 255.0; // 0.0~1.0
var val;
var r, g, b;
if (tmp < 0.50) {
r = 0.0;
} else if (tmp > 0.75) {
r = 1.0;
} else {
r = 4.0 * tmp - 2.0;
}
if (tmp < 0.25) {
g = 4.0 * tmp;
} else if (tmp > 0.75) {
g = -4.0 * tmp + 4.0;
} else {
g = 1.0;
}
if (tmp < 0.25) {
b = 1.0;
} else if (tmp > 0.50) {
b = 0.0;
} else {
b = -4.0 * tmp + 2.0;
}
rgb[1] = 255.0 * g;
rgb[0] = 255.0 * r;
rgb[2] = 255.0 * b;
}
function waterFall(myarray) {
ctx1.putImageData(imgData1, 0, 1);
imgData1 = ctx1.getImageData(0, 0, 512, 512);
for (j = 0; j < 512; j++) {
colormap(myarray[j]);
imgData1.data[0 + j * 4] = rgb[0];
imgData1.data[1 + j * 4] = rgb[1];
imgData1.data[2 + j * 4] = rgb[2];
imgData1.data[3 + j * 4] = 255;
}
}
function showBpf(ctx0, imgData0, bfo) {
var cwmarker0 = Math.floor( bfo[0] / (16000 / 2048) );
var cwmarker1 = Math.floor( bfo[1] / (16000 / 2048) );
console.log('bfo = ', bfo);
for (i = 0; i < 20; i++) {
for (j = 0; j < 512; j++) {
var r, g, b, a;
if(j == cwmarker0 || j == cwmarker1) {
r = 0; g = 0; b = 0;
} else if ( j >= cwmarker0-20 && j <= cwmarker0+20 && i > 10) {
r = 135; g = 206; b= 235;
} else if ( j >= cwmarker1-20 && j <= cwmarker1+20 && i > 10) {
r = 216; g = 191; b= 216;
} else {
r = 255; g = 255; b= 255;
}
imgData0.data[0 + j * 4 + i * imgData0.width * 4] = r;
imgData0.data[1 + j * 4 + i * imgData0.width * 4] = g;
imgData0.data[2 + j * 4 + i * imgData0.width * 4] = b;
imgData0.data[3 + j * 4 + i * imgData0.width * 4] = 255;
}
}
ctx0.putImageData(imgData0, 0, 0);
}
function onClick(e) {
var rect = e.target.getBoundingClientRect();
var mx = e.clientX - rect.left;
var my = e.clientY - rect.top;
console.log('mouse clicked: ', mx, my);
socket.emit('message77', mx);
}
function playAudioStream(ctx, audio_f32) {
var audio_buf = ctx.createBuffer(1, audio_f32.length, 16000);
var audio_src = ctx.createBufferSource();
var current_time = ctx.currentTime;
audio_buf.getChannelData(0).set(audio_f32);
audio_src.buffer = audio_buf;
audio_src.connect(ctx.destination);
if (current_time < scheduled_time) {
audio_src.start(scheduled_time);
scheduled_time += audio_buf.duration;
} else {
audio_src.start(current_time);
scheduled_time = current_time + audio_buf.duration;
}
}
// main
var socket = io();
var myarray = new Array();
var canvas0, canvas1, canvas2;
var ctx0, ctx1;
var imgData0, imgData1;
var rgb = new Array(3);
canvas0 = document.getElementById('mycanvas0');
canvas1 = document.getElementById('mycanvas1');
ctx0 = canvas0.getContext('2d');
ctx1 = canvas1.getContext('2d');
canvas1.addEventListener('click', onClick, false);
imgData0 = ctx0.createImageData(512, 20);
imgData1 = ctx1.createImageData(512, 512);
var stage = new createjs.Stage("mycanvas2");
var t = new createjs.Text("IC-7410", "26px serif", "DarkRed");
t.x = 10;
t.y = 10;
stage.addChild(t);
stage.update();
var bfo = [1000.0, 2000.0];
showBpf(ctx0, imgData0, bfo);
for (i = 0; i < 512; i++) {
for (j = 0; j < 512; j++) {
imgData1.data[0 + j * 4 + i * imgData1.width * 4] = j % 256;
imgData1.data[1 + j * 4 + i * imgData1.width * 4] = i % 256;
imgData1.data[2 + j * 4 + i * imgData1.width * 4] = 128;
imgData1.data[3 + j * 4 + i * imgData1.width * 4] = 255;
}
}
ctx1.putImageData(imgData1, 0, 0);
var audioCtx = new AudioContext;
var scheduled_time = 0;
socket.on('your message', function(msg) {
$('#messages').append($('<div>').text(msg));
window.scrollTo(0, document.body.scrollHeight);
});
socket.on('waterfall', function(data) {
waterFall(data);
});
socket.on('sound' , function(data) {
playAudioStream(audioCtx, new Float32Array(data));
});
socket.on('freqmsg', function(msg) {
t.text = msg;
stage.update();
});
$('#btn1').click(function() { socket.emit('message1'); console.log('message1'); });
$('#btn2').click(function() { socket.emit('message2'); console.log('message2'); });
$('#btn3').click(function() { socket.emit('message3'); console.log('message3'); });
$('#btn4').click(function() { socket.emit('message4'); console.log('message4'); });
$('#btn5').click(function() { socket.emit('message5'); bfo[0]+=100; showBpf(ctx0, imgData0, bfo);});
$('#btn6').click(function() { socket.emit('message6'); bfo[0]-=100; showBpf(ctx0, imgData0, bfo);});
$('#btn7').click(function() { socket.emit('message7'); bfo[1]+=100; showBpf(ctx0, imgData0, bfo);});
$('#btn8').click(function() { socket.emit('message8'); bfo[1]-=100; showBpf(ctx0, imgData0, bfo);});
$('form').submit(function() {
socket.emit('your message', $('#m').val());
$('#m').val('');
return false;
});
</script>
</body>
</html>