prepare for osc input
This commit is contained in:
@ -15,6 +15,18 @@ console.log("Listening to: ws://localhost:3000. Open Topos.\n");
|
|||||||
// Listening to WebSocket messages
|
// Listening to WebSocket messages
|
||||||
const wss = new WebSocket.Server({ port: 3000 });
|
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
|
// Setting up for message broadcasting
|
||||||
wss.on("connection", function (ws) {
|
wss.on("connection", function (ws) {
|
||||||
console.log("> Client connected");
|
console.log("> Client connected");
|
||||||
|
|||||||
@ -180,6 +180,7 @@
|
|||||||
|
|
||||||
<p rel="noopener noreferrer" id="docs_patterns" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Patterns</p>
|
<p rel="noopener noreferrer" id="docs_patterns" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Patterns</p>
|
||||||
<p rel="noopener noreferrer" id="docs_midi" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">MIDI</p>
|
<p rel="noopener noreferrer" id="docs_midi" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">MIDI</p>
|
||||||
|
<p rel="noopener noreferrer" id="docs_osc" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">OSC</p>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
<details class="space-y-2" open=true>
|
<details class="space-y-2" open=true>
|
||||||
|
|||||||
15
src/API.ts
15
src/API.ts
@ -1,4 +1,5 @@
|
|||||||
import { EditorView } from "@codemirror/view";
|
import { EditorView } from "@codemirror/view";
|
||||||
|
import { sendToServer, type OSCMessage } from "./IO/OSC";
|
||||||
import { getAllScaleNotes, nearScales, seededRandom } from "zifferjs";
|
import { getAllScaleNotes, nearScales, seededRandom } from "zifferjs";
|
||||||
import {
|
import {
|
||||||
MidiCCEvent,
|
MidiCCEvent,
|
||||||
@ -2095,6 +2096,20 @@ export class UserAPI {
|
|||||||
}, real_duration * 1000);
|
}, real_duration * 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
// OSC Functions
|
||||||
|
// =============================================================
|
||||||
|
|
||||||
|
public osc = (address: string, port: number, ...args: any[]): void => {
|
||||||
|
sendToServer({
|
||||||
|
address: address,
|
||||||
|
port: port,
|
||||||
|
args: args,
|
||||||
|
timetag: Math.round(Date.now() + this.app.clock.deadline),
|
||||||
|
} as OSCMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Transport functions
|
// Transport functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import { linear_time } from "./documentation/time/linear_time";
|
|||||||
import { cyclical_time } from "./documentation/time/cyclical_time";
|
import { cyclical_time } from "./documentation/time/cyclical_time";
|
||||||
import { long_forms } from "./documentation/long_forms";
|
import { long_forms } from "./documentation/long_forms";
|
||||||
import { midi } from "./documentation/midi";
|
import { midi } from "./documentation/midi";
|
||||||
|
import { osc } from "./documentation/osc";
|
||||||
import { sound } from "./documentation/engine";
|
import { sound } from "./documentation/engine";
|
||||||
import { patterns } from "./documentation/patterns";
|
import { patterns } from "./documentation/patterns";
|
||||||
import { functions } from "./documentation/functions";
|
import { functions } from "./documentation/functions";
|
||||||
@ -92,6 +93,7 @@ export const documentation_factory = (application: Editor) => {
|
|||||||
patterns: patterns(application),
|
patterns: patterns(application),
|
||||||
ziffers: ziffers(application),
|
ziffers: ziffers(application),
|
||||||
midi: midi(application),
|
midi: midi(application),
|
||||||
|
osc: osc(application),
|
||||||
lfos: lfos(application),
|
lfos: lfos(application),
|
||||||
variables: variables(application),
|
variables: variables(application),
|
||||||
probabilities: probabilities(application),
|
probabilities: probabilities(application),
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export let socket = new WebSocket("ws://localhost:3000");
|
|
||||||
export interface OSCMessage {
|
export interface OSCMessage {
|
||||||
address: string;
|
address: string;
|
||||||
port: number;
|
port: number;
|
||||||
@ -6,44 +5,52 @@ export interface OSCMessage {
|
|||||||
timetag: number;
|
timetag: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send/receive messages from websocket
|
||||||
|
export let outputSocket = new WebSocket("ws://localhost:3000");
|
||||||
|
export let inputSocket = new WebSocket("ws://localhost:3001");
|
||||||
|
|
||||||
|
inputSocket.onmessage= function (event) {
|
||||||
|
console.log("Received: ", event.data);
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
socket.onopen = function (event) {
|
outputSocket.onopen = function (event) {
|
||||||
console.log("Connected to WebSocket Server");
|
console.log("Connected to WebSocket Server");
|
||||||
// Send an OSC-like message
|
// Send an OSC-like message
|
||||||
socket.send(
|
outputSocket.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
address: "/successful_connexion",
|
address: "/successful_connexion",
|
||||||
args: true,
|
args: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
socket.onerror = function (error) {
|
outputSocket.onerror = function (error) {
|
||||||
console.log("Websocket Error:", error);
|
console.log("Websocket Error:", error);
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = function (event) {
|
outputSocket.onmessage = function (event) {
|
||||||
console.log("Received: ", event.data);
|
console.log("Received: ", event.data);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function sendToServer(message: OSCMessage) {
|
export function sendToServer(message: OSCMessage) {
|
||||||
if (socket.readyState === WebSocket.OPEN) {
|
if (outputSocket.readyState === WebSocket.OPEN) {
|
||||||
socket.send(JSON.stringify(message));
|
outputSocket.send(JSON.stringify(message));
|
||||||
} else {
|
} else {
|
||||||
console.log("WebSocket is not open. Attempting to reconnect...");
|
console.log("WebSocket is not open. Attempting to reconnect...");
|
||||||
if (
|
if (
|
||||||
socket.readyState === WebSocket.CONNECTING ||
|
outputSocket.readyState === WebSocket.CONNECTING ||
|
||||||
socket.readyState === WebSocket.OPEN
|
outputSocket.readyState === WebSocket.OPEN
|
||||||
) {
|
) {
|
||||||
socket.close();
|
outputSocket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new WebSocket connection
|
// Create a new WebSocket connection
|
||||||
socket = new WebSocket("ws://localhost:3000");
|
outputSocket = new WebSocket("ws://localhost:3000");
|
||||||
|
|
||||||
// Send the message once the socket is open
|
// Send the message once the socket is open
|
||||||
socket.onopen = () => {
|
outputSocket.onopen = () => {
|
||||||
socket.send(JSON.stringify(message));
|
outputSocket.send(JSON.stringify(message));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -499,12 +499,12 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
"linear",
|
"linear",
|
||||||
"cyclic",
|
"cyclic",
|
||||||
"longform",
|
"longform",
|
||||||
// "sound",
|
|
||||||
"synths",
|
"synths",
|
||||||
"chaining",
|
"chaining",
|
||||||
"patterns",
|
"patterns",
|
||||||
"ziffers",
|
"ziffers",
|
||||||
"midi",
|
"midi",
|
||||||
|
"osc",
|
||||||
"functions",
|
"functions",
|
||||||
"lfos",
|
"lfos",
|
||||||
"probabilities",
|
"probabilities",
|
||||||
@ -520,7 +520,7 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
].forEach((e) => {
|
].forEach((e) => {
|
||||||
let name = `docs_` + e;
|
let name = `docs_` + e;
|
||||||
document.getElementById(name)!.addEventListener("click", async () => {
|
document.getElementById(name)!.addEventListener("click", async () => {
|
||||||
if (name !== "docs_samples") {
|
if (name !== "docs_sample_list") {
|
||||||
app.currentDocumentationPane = e;
|
app.currentDocumentationPane = e;
|
||||||
updateDocumentationContent(app, bindings);
|
updateDocumentationContent(app, bindings);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "./main";
|
import { type Editor } from "./main";
|
||||||
import { socket } from "./IO/OSC";
|
import { outputSocket, inputSocket } from "./IO/OSC";
|
||||||
|
|
||||||
const handleResize = (canvas: HTMLCanvasElement) => {
|
const handleResize = (canvas: HTMLCanvasElement) => {
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
@ -28,7 +28,8 @@ export const saveBeforeExit = (app: Editor): null => {
|
|||||||
app.currentFile().committed = app.view.state.doc.toString();
|
app.currentFile().committed = app.view.state.doc.toString();
|
||||||
app.settings.saveApplicationToLocalStorage(app.universes, app.settings);
|
app.settings.saveApplicationToLocalStorage(app.universes, app.settings);
|
||||||
// Close the websocket
|
// Close the websocket
|
||||||
socket.close();
|
inputSocket.close();
|
||||||
|
outputSocket.close();
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
42
src/documentation/osc.ts
Normal file
42
src/documentation/osc.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { type Editor } from "../main";
|
||||||
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
|
export const osc = (application: Editor): string => {
|
||||||
|
// @ts-ignore
|
||||||
|
const makeExample = makeExampleFactory(application);
|
||||||
|
return `
|
||||||
|
# Open Sound Control
|
||||||
|
|
||||||
|
Topos is a sandboxed web application. It cannot speak with your computer directly, or only through secure connexions. You can use the [Open Sound Control](https://en.wikipedia.org/wiki/Open_Sound_Control) protocol to send and receive data from your computer. This protocol is used by many softwares and hardware devices. You can use it to control your favorite DAW, your favorite synthesizer, your favorite robot, or anything really!
|
||||||
|
|
||||||
|
To use **OSC** with Topos, you will need to download the <ic>ToposServer</ic> by [following this link](https://github.com/Bubobubobubobubo/Topos). You can download everything as a zip file or clone the project if you know what you are doing. Here is a quick guide to get you started:
|
||||||
|
|
||||||
|
- 1) Download <ic>Topos</ic> and navigate to the <ic>ToposServer</ic> folder.
|
||||||
|
- 2) Install the dependencies using <ic>npm install</ic>.
|
||||||
|
- 3) Start the server using <ic>npm start</ic>.
|
||||||
|
- 4) Open the <ic>Topos</ic> application in your web browser.
|
||||||
|
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Once the server is loaded, you are ready to send an **OSC** message:
|
||||||
|
|
||||||
|
${makeExample(
|
||||||
|
"Sending a simple OSC message",
|
||||||
|
`
|
||||||
|
beat(1)::sound('cp').speed(2).vel(0.5).osc()
|
||||||
|
`, true
|
||||||
|
)}
|
||||||
|
|
||||||
|
This is a simple **OSC** message that will inherit all the properties of the sound. You can also send customized OSC messages using the <ic>osc()</ic> function:
|
||||||
|
|
||||||
|
${makeExample(
|
||||||
|
"Sending a customized OSC message",
|
||||||
|
`
|
||||||
|
// osc(address, port, ...message)
|
||||||
|
osc('/my/osc/address', 5000, 1, 2, 3)
|
||||||
|
`, true)}
|
||||||
|
|
||||||
|
`};
|
||||||
@ -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 { socket } from "./IO/OSC";
|
import { outputSocket } from "./IO/OSC";
|
||||||
import {
|
import {
|
||||||
initializeSelectedUniverse,
|
initializeSelectedUniverse,
|
||||||
AppSettings,
|
AppSettings,
|
||||||
@ -95,7 +95,7 @@ export class Editor {
|
|||||||
isPlaying: boolean = false;
|
isPlaying: boolean = false;
|
||||||
|
|
||||||
// OSC
|
// OSC
|
||||||
socket: WebSocket = socket
|
outputSocket: WebSocket = outputSocket
|
||||||
|
|
||||||
// Hydra
|
// Hydra
|
||||||
public hydra_backend: any;
|
public hydra_backend: any;
|
||||||
|
|||||||
Reference in New Issue
Block a user