improvements on osc input

This commit is contained in:
2023-12-04 18:23:38 +01:00
parent cc963ac54f
commit e68ac4fcac
8 changed files with 164 additions and 116 deletions

33
ToposServer/OSCtoTopos.js Normal file
View File

@ -0,0 +1,33 @@
const WebSocket = require("ws");
const osc = require("osc");
const cleanIncomingOSC = (oscMsg) => {
let data = oscMsg.args;
// Remove information about type of data
data = data.map((item) => {
return item.value;
})
return {data: data, address: oscMsg.address};
}
// ==============================================
// Receiving and forwarding OSC UDP messages
// Create an osc.js UDP Port listening on port 57121.
console.log("> OSC Input: 127.0.0.1:30000");
const wss = new WebSocket.Server({ port: 3001 });
var udpPort = new osc.UDPPort({
localAddress: "0.0.0.0",
localPort: 30000,
metadata: true
});
udpPort.on("message", function (oscMsg, timeTag, info) {
console.log(`> Incoming OSC to ${oscMsg.address}:`, oscMsg.args.map(
(item) => {return item.value})
);
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(cleanIncomingOSC(oscMsg)));
}
});
});
udpPort.open();

81
ToposServer/ToposToOSC.js Normal file
View File

@ -0,0 +1,81 @@
const WebSocket = require("ws");
const osc = require("osc");
// Listening to WebSocket messages
const wss = new WebSocket.Server({ port: 3000 });
// Setting up for message broadcasting
wss.on("connection", function (ws) {
console.log("> Client connected");
ws.on("message", function (data) {
try {
const message = JSON.parse(data);
sendOscMessage(
formatAndTypeMessage(message),
message.address,
message.port
);
console.log(`> Message sent to ${message.address}:${message.port}: ${JSON.stringify(message.args)}`)
} catch (error) {
console.error("> Error processing message:", error);
}
});
});
wss.on("error", function (error) {
console.error("> Server error:", error);
})
wss.on("close", function () {
// Close the websocket server
wss.close();
console.log("> Closing websocket server")
});
let udpPort = new osc.UDPPort({
localAddress: "0.0.0.0",
localPort: 3000,
metadata: true,
remoteAddress: "0.0.0.0",
remotePort: 57120,
});
udpPort.on("error", function (error) {
console.error("> UDP Port error:", error);
});
udpPort.on("ready", function () {
//console.log(`> UDP Receive: ${udpPort.options.localPort}`);
console.log("> WebSocket server: 127.0.0.1:3000");
});
udpPort.open();
function sendOscMessage(message, address, port) {
try {
udpPort.options.remotePort = port
message.address = address;
udpPort.send(message);
} catch (error) {
console.error("> Error sending OSC message:", error);
}
}
const formatAndTypeMessage = (message) => {
let newMessage = {};
delete message.args['address'];
delete message.args['port'];
newMessage.address = message.address;
newMessage.timestamp = osc.timeTag(message.timetag);
args = [...Object.entries(message.args)].flat().map((arg) => {
if (typeof arg === 'string')
return {type: 's', value: arg};
if (typeof arg === 'number')
return {type: 'f', value: arg};
if (typeof arg === 'boolean')
return value ? {type: 's', value: 1} : {type: 's', value: 0};
})
newMessage.args = args
return newMessage;
}

14
ToposServer/banner.js Normal file
View File

@ -0,0 +1,14 @@
var pjson = require('./package.json');
let banner = `
┏┳┓ ┏┓┏┓┏┓
┃ ┏┓┏┓┏┓┏ ┃┃┗┓┃
┻ ┗┛┣┛┗┛┛ ┗┛┗┛┗┛
${pjson.version}\n`
function greet() {
console.log(banner)
}
module.exports = {
greet: greet
}

View File

@ -1,114 +1,9 @@
const WebSocket = require("ws"); const WebSocket = require("ws");
const osc = require("osc"); const osc = require("osc");
var pjson = require('./package.json');
let banner = ` require('./banner').greet();
┏┳┓ ┏┓┏┓┏┓ // Topos to OSC
┃ ┏┓┏┓┏┓┏ ┃┃┗┓┃ require('./ToposToOSC')
┻ ┗┛┣┛┗┛┛ ┗┛┗┛┗┛ // OSC to Topos
require("./OSCtoTopos")
${pjson.version}\n`
console.log(banner)
console.log("Listening to: ws://localhost:3000. Open Topos.\n");
// Listening to WebSocket messages
const wss = new WebSocket.Server({ port: 3000 });
// Sending WebSocket messages
const inputWss = new WebSocket.Server({ port: 3001 });
inputWss.on("connection", function (ws) {
inputWss.clients.forEach(function each(client) {
// Send message to all clients except sender
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send("New client connected");
}
})
});
// Setting up for message broadcasting
wss.on("connection", function (ws) {
console.log("> Client connected");
ws.on("message", function (data) {
try {
const message = JSON.parse(data);
sendOscMessage(
formatAndTypeMessage(message),
message.address,
message.port
);
console.log(`> Message sent to ${message.address}:${message.port}: ${JSON.stringify(message.args)}`)
} catch (error) {
console.error("> Error processing message:", error);
}
});
});
wss.on("error", function (error) {
console.error("> Server error:", error);
})
wss.on("close", function () {
// Close the websocket server
wss.close();
console.log("> Closing websocket server")
});
// Setting up for OSC messages
let udpPort = new osc.UDPPort({
localAddress: "0.0.0.0",
localPort: 3000,
metadata: true,
remoteAddress: "0.0.0.0",
remotePort: 57120,
});
udpPort.on("error", function (error) {
console.error("> UDP Port error:", error);
});
udpPort.on("ready", function () {
console.log(`> UDP Port opened on port ${udpPort.options.localPort}`);
});
udpPort.open();
function sendOscMessage(message, address, port) {
try {
udpPort.options.remotePort = port
message.address = address;
udpPort.send(message);
} catch (error) {
console.error("> Error sending OSC message:", error);
}
}
const formatAndTypeMessage = (message) => {
let newMessage = {};
delete message.args['address'];
delete message.args['port'];
newMessage.address = message.address;
newMessage.timestamp = osc.timeTag(message.timetag);
args = [...Object.entries(message.args)].flat().map((arg) => {
if (typeof arg === 'string')
return {type: 's', value: arg};
if (typeof arg === 'number')
return {type: 'f', value: arg};
if (typeof arg === 'boolean')
return value ? {type: 's', value: 1} : {type: 's', value: 0};
})
newMessage.args = args
return newMessage;
}
// console.log(formatAndTypeMessage({
// address: '/baba',
// port: 2000,
// args: { s: 'fhardkick', dur: 0.5, port: 2000, address: 'baba' },
// timetag: 1701696184583
// }))

View File

@ -1,5 +1,5 @@
import { EditorView } from "@codemirror/view"; import { EditorView } from "@codemirror/view";
import { sendToServer, type OSCMessage } from "./IO/OSC"; import { sendToServer, type OSCMessage, oscMessages } from "./IO/OSC";
import { getAllScaleNotes, nearScales, seededRandom } from "zifferjs"; import { getAllScaleNotes, nearScales, seededRandom } from "zifferjs";
import { import {
MidiCCEvent, MidiCCEvent,
@ -2109,6 +2109,18 @@ export class UserAPI {
} as OSCMessage); } as OSCMessage);
} }
public getOSC = (address?: string): any[] => {
/**
* Give access to incoming OSC messages. If no address is specified, returns the raw oscMessages array. If an address is specified, returns only the messages who contain the address and filter the address itself.
*/
if (address) {
let messages = oscMessages.filter((msg) => msg.address === address);
messages = messages.map((msg) => msg.data);
return messages
} else {
return oscMessages;
}
}
// ============================================================= // =============================================================
// Transport functions // Transport functions

View File

@ -9,9 +9,18 @@ export interface OSCMessage {
export let outputSocket = new WebSocket("ws://localhost:3000"); export let outputSocket = new WebSocket("ws://localhost:3000");
export let inputSocket = new WebSocket("ws://localhost:3001"); export let inputSocket = new WebSocket("ws://localhost:3001");
inputSocket.onmessage= function (event) { // Queue of 1000 last messages
console.log("Received: ", event.data); export let oscMessages : any[] = [];
}
inputSocket.addEventListener('message', (event) => {
let data = JSON.parse(event.data);
if (oscMessages.length > 1000) {
oscMessages.shift();
}
oscMessages.push(data);
});
// @ts-ignore // @ts-ignore
outputSocket.onopen = function (event) { outputSocket.onopen = function (event) {
@ -20,7 +29,7 @@ outputSocket.onopen = function (event) {
outputSocket.send( outputSocket.send(
JSON.stringify({ JSON.stringify({
address: "/successful_connexion", address: "/successful_connexion",
args: true, port: 3000, args: {}
}) })
); );

View File

@ -16,9 +16,12 @@ To use **OSC** with Topos, you will need to download the <ic>ToposServer</ic> by
- 3) Start the server using <ic>npm start</ic>. - 3) Start the server using <ic>npm start</ic>.
- 4) Open the <ic>Topos</ic> application in your web browser. - 4) Open the <ic>Topos</ic> application in your web browser.
This server can be used both for **OSC** _input_ and _output_.
## Input ## Input
Send an **OSC** message to the server at the address <ic>localhost:30000</ic>. You will receive your message in Topos as an Array containing the address and data of your message.
## Output ## Output
Once the server is loaded, you are ready to send an **OSC** message: Once the server is loaded, you are ready to send an **OSC** message:

View File

@ -4,7 +4,7 @@ import { scriptBlinkers } from "./Visuals/Blinkers";
import { javascript } from "@codemirror/lang-javascript"; import { javascript } from "@codemirror/lang-javascript";
import { markdown } from "@codemirror/lang-markdown"; import { markdown } from "@codemirror/lang-markdown";
import { Extension } from "@codemirror/state"; import { Extension } from "@codemirror/state";
import { outputSocket } from "./IO/OSC"; import { outputSocket, oscMessages } from "./IO/OSC";
import { import {
initializeSelectedUniverse, initializeSelectedUniverse,
AppSettings, AppSettings,
@ -206,6 +206,7 @@ export class Editor {
// Loading universe from URL (if needed) // Loading universe from URL (if needed)
loadUniverserFromUrl(this); loadUniverserFromUrl(this);
} }
private getBuffer(type: string): any { private getBuffer(type: string): any {