wavey-wind/server.js

318 lines
7.1 KiB
JavaScript
Raw Normal View History

// Which port do I send OSC messages to? (SupperCollider, ...)
const OSCPORT = 57120;
// Which port do I listen to (for visuals, calibration)
const PORT = 6676
// Do we have a problem, shall we debug?
2022-05-07 15:30:55 +02:00
const DEBUG = {
osc: true,
2022-05-07 16:27:19 +02:00
udp: false,
midi: true
2022-05-07 15:30:55 +02:00
}
2022-05-07 15:30:55 +02:00
// MIDI out
2022-05-07 15:36:34 +02:00
const MIDI = true
2022-05-27 12:34:22 +02:00
// Serial baud rate
const BAUDRATE = 115200
const express = require('express')
const http = require('http')
const WebSocket = require('ws')
2021-08-11 14:39:34 +02:00
const osc = require('osc')
2022-03-03 11:11:38 +01:00
const readline = require('readline')
const fs = require('fs')
2022-05-07 15:38:21 +02:00
const midi = require('midi')
2022-04-23 16:34:38 +02:00
2022-04-23 15:38:50 +02:00
2022-05-27 12:34:22 +02:00
// Seznam povezanih tty naprav
const tty = process.argv.splice(2)
2022-03-05 13:16:43 +01:00
let eulerRotation = [0, 0, 0]
const include_files = [
2021-08-14 15:15:16 +02:00
'/anim.js',
'/control.js',
'/osctl.js',
'/test.js',
'/node_modules/three/build/three.min.js',
'/node_modules/nouislider/distribute/nouislider.min.js',
'/node_modules/nouislider/distribute/nouislider.min.css',
'/node_modules/osc/dist/osc-browser.js'
];
const app = express();
const server = http.Server(app);
2022-05-27 12:34:22 +02:00
// Odprti serijski OSC linki
let serijskePovezave = {}
2021-08-14 15:15:16 +02:00
2022-05-07 15:57:15 +02:00
let mo = null
if (MIDI) {
// Midi port
2022-05-07 15:57:15 +02:00
mo = new midi.Output()
//mo.getPortCount()
//mo.getPortName(0)
//mo.openPort(0)
mo.openVirtualPort("kegel")
}
2022-04-23 16:13:34 +02:00
2022-05-27 12:34:22 +02:00
function openSerial(ttyAddr) {
console.log('opening ', ttyAddr, BAUDRATE)
2022-03-03 21:51:02 +01:00
2022-05-27 12:34:22 +02:00
serijskePovezave[ttyAddr] = new osc.SerialPort({
devicePath: ttyAddr,
bitrate: BAUDRATE,
2022-03-03 21:51:02 +01:00
autoOpen: true,
useSLIP: true
2021-08-14 15:15:16 +02:00
})
2022-05-27 12:34:22 +02:00
const scon = serijskePovezave[ttyAddr]
2021-08-14 15:15:16 +02:00
scon.on('open', e => {
2022-05-27 12:34:22 +02:00
console.log(`serial connection ${ttyAddr} opened`)
//console.log(scon)
2021-08-14 15:15:16 +02:00
})
scon.on('error', e => {
2022-05-27 12:34:22 +02:00
console.error(`tty ${ttyAddr} error`, e)
//scon.close()
2021-08-14 15:15:16 +02:00
})
scon.on('close', e => {
2022-05-27 12:34:22 +02:00
console.warn(`serial connection ${ttyAddr} closed, restarting in 1 second`)
setTimeout(() => { openSerial(ttyAddr) }, 1000)
2021-08-14 15:15:16 +02:00
})
// Arduino OSC gre v web
2022-03-03 21:51:02 +01:00
scon.on('message', msg => {
2022-05-27 12:34:22 +02:00
const index = Object.keys(serijskePovezave).indexOf(ttyAddr)
const prepend = `/ww/${index}`
// Debug incoming serial osc
2022-05-07 15:30:55 +02:00
if (DEBUG.osc) {
2022-05-27 12:34:22 +02:00
console.log('osc SERIAL msg', msg, ttyAddr, prepend)
2022-01-01 22:10:59 +01:00
}
2022-05-27 12:34:22 +02:00
sendAll(msg, null, null, osclients, prepend)
2021-08-14 15:15:16 +02:00
})
2022-04-23 15:33:54 +02:00
scon.open()
2021-08-14 15:15:16 +02:00
if (scon._closeCode) {
scon = null
2022-05-27 12:34:22 +02:00
console.log('restarting serial connection ', ttyAddr)
2021-08-14 15:15:16 +02:00
setTimeout(openSerial, 1000)
}
}
2022-05-27 12:34:22 +02:00
if (tty.length > 0) {
tty.forEach((ttyAddr) => {
openSerial(ttyAddr);
});
2022-03-03 21:51:02 +01:00
}
2021-08-11 14:39:34 +02:00
app.get('/', (req, res) => {
2017-10-06 23:20:52 +02:00
res.sendFile(__dirname + '/index.html');
});
2021-08-11 14:39:34 +02:00
app.get('/ctl', (req, res) => {
2017-10-06 23:20:52 +02:00
res.sendFile(__dirname + '/control.html');
});
2021-08-12 18:10:19 +02:00
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/test.html');
});
// Hydra inclusion
app.get('/hydra', function(req, res) {
res.sendFile(__dirname + '/hydra-osc-main/index.html');
});
app.get('/lib/osc.min.js', function(req, res) {
res.sendFile(__dirname + '/hydra-osc-main/lib/osc.min.js');
});
let settings = {};
app.get('/settings', function(req, res) {
res.send(settings);
2017-10-06 23:20:52 +02:00
});
include_files.map(function(file) {
app.get(file, function(req, res){
res.sendFile(__dirname + file);
});
2017-10-06 23:20:52 +02:00
});
server.listen(PORT, () => console.log('listening on *:' + PORT))
2017-10-06 23:20:52 +02:00
// Websocket init
const wss = new WebSocket.Server({ server })
2017-10-06 23:20:52 +02:00
2022-03-04 20:57:24 +01:00
// Relay multicast to websockets
// @TODO still sends to supercollider? Do we need two sockets?
/*
2022-03-04 20:57:24 +01:00
var dgram = require('dgram');
var sss = dgram.createSocket('udp4');
sss.on('listening', () => {
sss.addMembership('224.0.1.9');
})
sss.bind(6696, '224.0.1.9');
*/
2022-03-04 20:57:24 +01:00
const scudp = new osc.UDPPort({
remotePort: OSCPORT
2022-03-05 15:18:01 +01:00
//socket: sss
})
2022-03-04 20:57:24 +01:00
scudp.on('open', () => {
console.log("UDP to OSC open")
})
2022-03-04 20:57:24 +01:00
scudp.on('message', (msg) => {
2022-05-07 15:30:55 +02:00
if (DEBUG.udp) {
2022-03-05 15:18:01 +01:00
console.log('got UDP msg', msg);
}
osclients.forEach( client => {
if (client) {
//console.log("sending", msg, info)
client.send(msg)
}
})
})
scudp.on('error', (e) => {
console.log('UDP OSC error!', e)
})
scudp.open()
2022-03-05 12:44:07 +01:00
function eulerFromQuaternion(quaternion) {
// Quaternion to matrix.
const w = quaternion[0], x = quaternion[1], y = quaternion[2], z = quaternion[3];
const x2 = x + x, y2 = y + y, z2 = z + z;
const xx = x * x2, xy = x * y2, xz = x * z2;
const yy = y * y2, yz = y * z2, zz = z * z2;
const wx = w * x2, wy = w * y2, wz = w * z2;
const matrix = [
1 - ( yy + zz ), xy + wz, xz - wy, 0,
xy - wz, 1 - ( xx + zz ), yz + wx, 0,
xz + wy, yz - wx, 1 - ( xx + yy ), 0,
0, 0, 0, 1
];
// Matrix to euler
function clamp( value, min, max ) {
return Math.max( min, Math.min( max, value ) );
}
const m11 = matrix[ 0 ], m12 = matrix[ 4 ], m13 = matrix[ 8 ];
const m21 = matrix[ 1 ], m22 = matrix[ 5 ], m23 = matrix[ 9 ];
const m31 = matrix[ 2 ], m32 = matrix[ 6 ], m33 = matrix[ 10 ];
var euler = [ 0, 0, 0 ];
euler[1] = Math.asin( clamp( m13, - 1, 1 ) );
if ( Math.abs( m13 ) < 0.9999999 ) {
euler[0] = Math.atan2( - m23, m33 );
euler[2] = Math.atan2( - m12, m11 );
} else {
euler[0] = Math.atan2( m32, m22 );
euler[2] = 0;
}
return euler;
}
2022-05-27 12:34:22 +02:00
const sendAll = (msg, info, oscWS, osclients, prepend = '') => {
// Reset euler rotation to 0
if (msg.address == '/keys') {
if (msg.args[0] && msg.args[1] && msg.args[2] && msg.args[3]) {
eulerRotation = [0, 0, 0]
}
}
2022-03-05 12:44:07 +01:00
// Convert quaternion diff to euler angle diff
if (msg.address == '/quaternionDiff') {
const euler = eulerFromQuaternion(msg.args, 'XYZ');
sendAll({
address: '/eulerDiff',
args: euler
2022-05-27 12:34:22 +02:00
}, info, oscWS, osclients, prepend)
2022-03-05 13:16:43 +01:00
eulerRotation[0] += euler[0]
eulerRotation[1] += euler[1]
eulerRotation[2] += euler[2]
sendAll({
address: '/euler',
args: eulerRotation
2022-05-27 12:34:22 +02:00
}, info, oscWS, osclients, prepend)
2022-03-05 12:44:07 +01:00
}
2022-05-27 12:34:22 +02:00
// Add prepend
let sendMsg = {
address: `${prepend}${msg.address}`,
args: msg.args
}
// OSC relay
2021-08-14 15:15:16 +02:00
osclients.forEach( client => {
if (client && oscWS != client) {
2022-05-27 12:34:22 +02:00
// console.log("OSC RELAY", sendMsg, info, prepend)
client.send(sendMsg)
2021-08-11 14:39:34 +02:00
}
})
if (scudp) {
2022-05-07 15:30:55 +02:00
if (DEBUG.udp) {
2022-03-05 15:18:01 +01:00
console.log("UDP SEND", msg)
}
2022-05-27 12:34:22 +02:00
scudp.send(sendMsg)
}
2021-08-11 14:39:34 +02:00
}
let osclients = []
2017-10-06 23:20:52 +02:00
2021-08-11 14:39:34 +02:00
wss.on('connection', function (ws) {
2022-05-07 16:27:19 +02:00
console.log('new client connection', ws._socket.remoteAddress)
let oscWS = new osc.WebSocketPort({
2022-05-07 16:27:19 +02:00
socket: ws
2021-08-11 14:39:34 +02:00
});
2021-08-14 15:15:16 +02:00
// Vsi OSC sem grejo naprej na kliente OSC
2022-05-07 16:27:19 +02:00
oscWS.on('message', ({ address, args}, info) => {
console.log('fasal sem', address, args)
if (MIDI) {
if (address == '/midi') {
if (DEBUG.midi) {
console.log('midi SEND', args)
}
mo.send(args)
}
}
2021-08-14 15:15:16 +02:00
sendAll({ address, args}, info, oscWS, osclients)
})
oscWS.on('error', error => {
console.warn('Ignoring invalid OSC')
console.warn(error)
oscWS.close()
osclients = osclients.filter(ws => ws !== oscWS)
})
2021-08-14 15:15:16 +02:00
osclients.push(oscWS)
oscWS.on('close', () => {
2022-05-07 16:27:19 +02:00
console.log('closing socket', oscWS.socket.remoteAddress)
osclients = osclients.filter(ws => ws !== oscWS)
})
})
2022-03-03 21:51:02 +01:00
2022-04-23 16:13:34 +02:00
// Zapri midi
2022-05-07 15:38:21 +02:00
/*
if (MIDI && mo) {
mo.closePort()
}
2022-05-07 15:38:21 +02:00
*/