diff --git a/README.md b/README.md index 80480c3..6a010a0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,20 @@ -# ws-midi +

ws-midi

> Send MIDI using WebSocket communication

Animated image of two terminals demonstrating the usage of ws-midi

+--- + + + +- [Usage](#usage) + - [Usage with ngrok](#usage-with-ngrok) +- [Requirements](#requirements) + + + +--- + ## Usage * Clone the repo @@ -13,6 +25,19 @@ * When it asks for an IP, that's your WAN IP (search "what's my IP" on Google) * The receiver will have a virtual MIDI device called "ws-midi" to use in MIDI-capable apps + +### Usage with ngrok + +To get the connection working over network where we don't have access to the network-settings, we can use a service like ngrok to tunnel the connection: + +* Setup account at ngrok +* Start ws-midi receiver on the remote host that should receive the signal +* Start ngrok with `ngrok http 5006` (the port used by ws-midi) on the remote host +* Start ws-midi send on the local host that should send the signal to the remote host + * Use the host url as provided by ngrok in this format: `wss://` (we don't need the port as this goes over HTTPS) + +This should then pipe the signal from a local host to the remote host and you should see the MIDI signals arriving there. + ## Requirements * node.js diff --git a/receive.js b/receive.js index 3c31a36..d4c1152 100644 --- a/receive.js +++ b/receive.js @@ -2,7 +2,10 @@ const term = require('terminal-kit').terminal; const midi = require('midi'); const WebSocket = require('ws'); const { VIRTUAL_MIDI_DEVICE_NAME, PORT } = require('./constants.js'); -let ip; + +function heartbeat() { + this.isAlive = true; +} module.exports = () => { term.clear(); @@ -45,12 +48,29 @@ module.exports = () => { const wss = new WebSocket.Server({ port: PORT }); + const interval = setInterval(function ping() { + wss.clients.forEach(function each(ws) { + if (ws.isAlive === false) return ws.terminate(); + + ws.isAlive = false; + ws.ping(); + }); + }, 10 * 1000); + + wss.on('close', function close() { + clearInterval(interval); + }); + wss.on('listening', function listening() { term.black.bgGreen(`websocket server listening on ${PORT}\n`); }); wss.on('connection', function connection(ws) { console.log('new connection'); + + ws.isAlive = true; + ws.on('error', console.error); + ws.on('pong', heartbeat); ws.on('message', function incoming(wsMessage) { const message = JSON.parse(wsMessage) diff --git a/send.js b/send.js index 2131cd9..cb22aaa 100644 --- a/send.js +++ b/send.js @@ -2,7 +2,7 @@ const term = require('terminal-kit').terminal; const midi = require('midi'); const WebSocket = require('ws'); const { VIRTUAL_MIDI_DEVICE_NAME, PORT } = require('./constants.js'); -let ip; +let host; module.exports = () => { // Set up a new input. @@ -37,20 +37,20 @@ module.exports = () => { } } - term.cyan(`please enter the IP of the recipient\n`); + term.cyan(`please enter the HOST of the recipient in the format ws://host[:port] or wss://host[:port]\n`); term.inputField((error, response) => { term.clear(); - ip = response; + host = response; - term.cyan(`opening websocket connection to ${ip}:${PORT}\n`); - const ws = new WebSocket(`ws://${ip}:${PORT}`); + term.cyan(`opening websocket connection to ${host}\n`); + const ws = new WebSocket(`${host}`); ws.on('open', () => { term.clear(); - term.cyan(`opened websocket connection to ${ip}:${PORT}\n\n`); + term.cyan(`opened websocket connection to ${host}\n\n`); - term.cyan(`please pick a midi input device to send to ${ip}:${PORT}\n`); + term.cyan(`please pick a midi input device to send to ${host}\n`); term.singleColumnMenu(inputDeviceNames, { cancelable: true, @@ -66,7 +66,7 @@ module.exports = () => { const midiInputDeviceId = response.selectedIndex; - term.cyan(`opened websocket connection to ${ip}:${PORT}\n\n`); + term.cyan(`opened websocket connection to ${host}\n\n`); term.cyan(`please pick a midi output device to route locally`);