forked from michaelpalumbo/allhands
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2312262
commit ad0ab79
Showing
355 changed files
with
55,629 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,61 @@ | ||
# wspd | ||
## wspd (websocket 4 puredata) | ||
|
||
**I highly recommend reading this document at https://github.com/michaelpalumbo/wspd/blob/master/README.md or opening [README.pdf](readme.pdf)** | ||
|
||
This app acts as a bridge between two computers over the web, enables very fast transmission of controller data between, for example, two puredata patches. | ||
|
||
Since first starting the code, it's become a lot more general than only being used for puredata, but I didn't bother changing the name of the repository! | ||
|
||
|
||
### Instructions | ||
1. install nodejs | ||
2. clone/download the wspd repository at https://github.com/michaelpalumbo/wspd | ||
3. Open terminal, cd into the folder 'wspd' (the rest of this readme assumes that you're working from this directory) | ||
4. verify nodejs is installed: | ||
|
||
```shell | ||
node -v | ||
``` | ||
5.. might need to install dependencies: | ||
|
||
```shell | ||
npm install | ||
``` | ||
### Test locally | ||
1. start the server | ||
|
||
```shell | ||
npm start server | ||
``` | ||
|
||
2.. open a 2nd terminal window, cd into wspd | ||
|
||
3.. start the client | ||
|
||
```shell | ||
npm start client localhost | ||
``` | ||
|
||
4.. open the tester.maxpat (or tester.pd) | ||
|
||
Click either of the toggles to confirm data is being sent from pd>nodejs>pd. You should be able to have both toggles clicked, this verifies bi-directionality. | ||
|
||
### Telematic setup | ||
1. whomever can configure their router with DMZ and port-forwarding should run the app in server mode. The diagram below assumes that Jen would be running the server (the code doesn't need to be modified if you choose to have Erin run the server instead) | ||
|
||
![](wspd_schema_v2.png) | ||
|
||
### OSC Syntax | ||
The nodejs app assumes that all incoming data on UDP follows the OSC format of an Address Pattern followed by Type Tag String. Examples: | ||
|
||
- /index 3 | ||
- /position 0.3 0.6 0.8 | ||
- /msg hello world | ||
|
||
If you do not supply an address pattern using the '/', the app will ignore the message. | ||
|
||
#### Other messages | ||
As of right now, the app accepts OSC over UDP, but it would be reasonable to update the script so that it could accept other data from other sources, such from serial ports, MIDI input, etc. | ||
|
||
#### Other remotes/web app | ||
The server can also host a web app, i.e. could be used to host a couple of controls on a web page for anyone to remotely control a patch on either of your machines, etc. The preliminary code is there, just figured I'd mention it if it was of interest at a later time. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
// this script runs at either side | ||
// it's function as either a server or client is determined by a cli arg | ||
console.log(process.argv[2] + ' mode') | ||
|
||
const mode = process.argv[2] | ||
if (mode === 'client' && !process.argv[3]){ | ||
console.log('error: client mode requires a 2nd argument to specify server IP address\nexample:\n\nnpm start client localhost') | ||
process.exit() | ||
} | ||
// ***** Local UDP Send & Receive Config ******* // | ||
let localReceivePort; | ||
let localSendPort; | ||
if(mode === 'server'){ | ||
localReceivePort = 7402 | ||
localSendPort = 7401 | ||
} else if (mode === 'client'){ | ||
localReceivePort = 7404 | ||
localSendPort = 7403 | ||
} | ||
|
||
// ***** Local UDP-Sender ******* // | ||
// this is used by either mode! | ||
function init(){ | ||
|
||
} | ||
|
||
|
||
|
||
// both modes require these libs | ||
const { Client, Server } = require('node-osc'); | ||
const WebSocket = require('ws'); | ||
let ws; // keep this here | ||
|
||
if (mode === "server"){ | ||
|
||
// run the serverconst WebSocket = require('ws'); | ||
const app = require('express')() | ||
const http = require('http').createServer(app);; | ||
|
||
let listenPort = (process.env.PORT || 8081) | ||
const wss = new WebSocket.Server({ 'server': http, clientTracking: true }); | ||
http.listen(listenPort, function(){ | ||
}) | ||
wss.on('connection', function connection(ws, req, client) { | ||
|
||
console.log('new connection established ') | ||
const localSend = new Client('127.0.0.1', localSendPort); | ||
console.log('Configure your local pd patch(es) to listen on UDP Port ' + localSendPort) | ||
|
||
const localReceive = new Server(localReceivePort, '0.0.0.0'); | ||
// once running, inform user | ||
localReceive.on('listening', () => { | ||
console.log('Configure your local pd patch(es) to send on UDP Port ' + localReceivePort) | ||
}) | ||
// handle message: | ||
localReceive.on('message', (msg) => { | ||
// validate correct OSC address pattern syntax | ||
// console.log(msg) | ||
if(msg[0].charAt(0) === '/'){ | ||
// get the address pattern | ||
ap = msg[0] | ||
// trim the address pattern | ||
msg.shift() | ||
// construct object to send over websocket | ||
message = { | ||
// cmd allows us to send other types of messages, ask Michael for more info if curious! | ||
cmd: 'OSC', | ||
date: new Date().toUTCString(), | ||
addressPattern: ap, | ||
// this is the data! | ||
typeTagString: msg | ||
} | ||
// inform user | ||
// console.log('sending to remote:\n', message) | ||
// package data for the web, send it! | ||
// if(ws){ | ||
ws.send(JSON.stringify(message)) | ||
// } | ||
|
||
} else { | ||
// if incoming OSC message does not have an address pattern, refuse to handle it | ||
console.log('error, OSC Message must lead with an addressPattern\n\ni.e. /bioData') | ||
} | ||
}); | ||
|
||
|
||
ws.on('message', function incoming(message) { | ||
msg = JSON.parse(message) | ||
// console.log(msg) | ||
|
||
switch (msg.cmd){ | ||
// in case you want to receive other data and route it elsewhere | ||
case 'OSC': | ||
localSend.send(msg.addressPattern, msg.typeTagString, (err) => { | ||
if (err) console.error(err); | ||
}); | ||
|
||
break; | ||
|
||
|
||
default: | ||
console.log('client sent message with unknown cmd: ' + msg) | ||
// ws.send('server received message but did not understand: ' + msg) | ||
break; | ||
|
||
|
||
|
||
} | ||
}); | ||
|
||
ws.on('close', function(code, reason) { | ||
|
||
}) | ||
}); | ||
// we can use this if we want to send to multiple clients! | ||
function broadcast(msg){ | ||
wss.clients.forEach(function each(client) { | ||
if (client.readyState === WebSocket.OPEN) { | ||
client.send(msg); | ||
} | ||
}); | ||
} | ||
|
||
|
||
|
||
|
||
|
||
} else if (mode === 'client'){ | ||
const localSend = new Client('127.0.0.1', localSendPort); | ||
console.log('Configure your local pd patch(es) to listen on UDP Port ' + localSendPort) | ||
// run the app in client mode | ||
// ***** Websocket ******* // | ||
// WebSocket that will automatically attempt to reconnect if the connection is closed, or if the remote server goes down | ||
const ReconnectingWebSocket = require('reconnecting-websocket'); | ||
const serverIP = process.argv[3] | ||
const serverPort = '8081'; | ||
const serverWSAddress = `ws://${serverIP}:${serverPort}`; | ||
// options for the reconnecting websocket | ||
const rwsOptions = { | ||
// make rws use the webSocket module implementation | ||
WebSocket: WebSocket, | ||
// ms to try reconnecting: | ||
connectionTimeout: 1000, | ||
//debug:true, | ||
} | ||
|
||
// create a websocket | ||
// console.log(`attempting to connect to server at ${serverWSAddress}`) | ||
ws = new ReconnectingWebSocket(serverWSAddress, [], rwsOptions); | ||
|
||
// if the server responds with an error | ||
ws.addEventListener('error', () => { | ||
console.log(`connection error: ${serverIP}`); | ||
}); | ||
// on successful connection to server: | ||
ws.addEventListener('open', () => { | ||
console.log (`connected to server at ${serverWSAddress}`) | ||
}); | ||
// on close: | ||
ws.addEventListener('close', () => { | ||
console.log("server connection closed"); | ||
}); | ||
// handle messages | ||
ws.addEventListener('message', (data) => { | ||
let msg = JSON.parse(data.data); | ||
// console.log(msg) | ||
switch (msg.cmd){ | ||
// in case you want to receive other data and route it elsewhere | ||
case 'OSC': | ||
// send formatted OSC message locally (i.e. a pd patch) | ||
localSend.send(msg.addressPattern, msg.typeTagString, (err) => { | ||
if (err) console.error(err); | ||
}); | ||
break; | ||
|
||
default: | ||
// inform user that unknown message commang used | ||
console.log('client sent message with unknown cmd: ' + msg) | ||
break; | ||
} | ||
}); | ||
|
||
// ***** Local UDP-Receiver ******* // | ||
// this is used by either mode! | ||
let localReceivePort; | ||
if(mode === 'server'){ | ||
localReceivePort = 7402 | ||
} else if (mode === 'client'){ | ||
localReceivePort = 7404 | ||
} | ||
const localReceive = new Server(localReceivePort, '0.0.0.0'); | ||
// once running, inform user | ||
localReceive.on('listening', () => { | ||
console.log('Configure your local pd patch(es) to send on UDP Port ' + localReceivePort) | ||
}) | ||
// handle message: | ||
localReceive.on('message', (msg) => { | ||
// validate correct OSC address pattern syntax | ||
// console.log(msg) | ||
if(msg[0].charAt(0) === '/'){ | ||
// get the address pattern | ||
ap = msg[0] | ||
// trim the address pattern | ||
msg.shift() | ||
// construct object to send over websocket | ||
message = { | ||
// cmd allows us to send other types of messages, ask Michael for more info if curious! | ||
cmd: 'OSC', | ||
date: new Date().toUTCString(), | ||
addressPattern: ap, | ||
// this is the data! | ||
typeTagString: msg | ||
} | ||
// inform user | ||
// console.log('sending to remote:\n', message) | ||
// package data for the web, send it! | ||
// if(ws){ | ||
ws.send(JSON.stringify(message)) | ||
// } | ||
|
||
} else { | ||
// if incoming OSC message does not have an address pattern, refuse to handle it | ||
console.log('error, OSC Message must lead with an addressPattern\n\ni.e. /bioData') | ||
} | ||
}); | ||
|
||
} else { | ||
// app needs to know what mode to run in | ||
console.log('error! first argument must be either \'client\' or \'server\'') | ||
// stop node process | ||
process.exit() | ||
} | ||
|
||
|
||
|
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
const WebSocket = require('ws'); | ||
const { Client, Server } = require('node-osc'); | ||
let ip = process.argv[2] | ||
|
||
if(!ip){ | ||
console.log('error! Server IP not provided as first argument\n\ni.e. node client.js localhost') | ||
process.exit() | ||
} | ||
const ws = new WebSocket('ws://' + ip + ':8081'); | ||
|
||
ws.on('open', function open() { | ||
// ws.send(['something']); | ||
}); | ||
|
||
ws.on('message', function incoming(data) { | ||
console.log(data); | ||
}); | ||
|
||
ws.on('error', (err) => { | ||
console.log(err.message) | ||
}); | ||
|
||
|
||
|
||
/// UDP | ||
// TODO add a udpSend (from the client.js) on port 7400 | ||
// NOTE that it shouldn't run if 'local' cli arg given | ||
// const udpSend = new Client('127.0.0.1', 3333); | ||
const udpReceive = new Server(7400, '0.0.0.0'); | ||
|
||
udpReceive.on('listening', () => { | ||
console.log('OSC Server is listening.') | ||
}) | ||
|
||
let data = { | ||
index: null, | ||
heartSignal: null, | ||
bpm: null, | ||
bpmChange: null, | ||
bvpa: null, | ||
gsr: null, | ||
gsrLoPass: null, | ||
} | ||
udpReceive.on('message', (msg) => { | ||
msg.shift() | ||
data.index = msg[0] | ||
data.heartSignal = msg[1] | ||
let output = JSON.stringify(data) | ||
console.log('sending to remote: ', data) | ||
ws.send(output) | ||
console.log('data from 7400', msg[0], msg[5]) | ||
let array = [ msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6] ] | ||
console.log(array) | ||
// ws.send(array) | ||
}); |
Oops, something went wrong.