node-osc 11.1.0 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +11 -0
- package/.github/workflows/bump-version.yml +2 -0
- package/.github/workflows/nodejs.yml +3 -0
- package/LICENSE +201 -165
- package/README.md +135 -42
- package/dist/lib/Bundle.js +66 -0
- package/dist/lib/Client.js +137 -22
- package/dist/lib/Message.js +87 -1
- package/dist/lib/Server.js +117 -6
- package/dist/lib/index.js +3 -0
- package/dist/lib/internal/decode.js +4 -4
- package/{lib/internal/osc.mjs → dist/lib/osc.js} +94 -23
- package/dist/test/lib/osc.js +395 -0
- package/dist/test/test-client.js +152 -0
- package/dist/test/test-e2e.js +9 -3
- package/dist/test/test-encode-decode.js +849 -0
- package/dist/test/test-error-handling.js +116 -0
- package/dist/test/test-osc-internal.js +399 -41
- package/dist/test/test-promises.js +250 -0
- package/dist/test/test-types.js +42 -0
- package/dist/test/util.js +15 -8
- package/docs/API.md +477 -0
- package/docs/GUIDE.md +605 -0
- package/examples/README.md +119 -0
- package/examples/async-await.mjs +57 -0
- package/examples/bundle-example.mjs +92 -0
- package/examples/client.js +22 -5
- package/examples/error-handling.mjs +152 -0
- package/examples/esm.mjs +21 -0
- package/examples/server.js +16 -0
- package/jsdoc.json +16 -0
- package/lib/Bundle.mjs +66 -0
- package/lib/Client.mjs +137 -22
- package/lib/Message.mjs +87 -1
- package/lib/Server.mjs +117 -6
- package/lib/index.mjs +1 -0
- package/lib/internal/decode.mjs +4 -4
- package/{dist/lib/internal/osc.js → lib/osc.mjs} +71 -7
- package/package.json +12 -10
- package/rollup.config.mjs +48 -37
- package/scripts/generate-docs.mjs +229 -0
- package/test/fixtures/types/test-cjs-types.ts +19 -0
- package/test/fixtures/types/test-esm-types.ts +35 -0
- package/test/fixtures/types/tsconfig-cjs.test.json +17 -0
- package/test/fixtures/types/tsconfig-esm.test.json +17 -0
- package/test/test-bundle.mjs +0 -1
- package/test/test-client.mjs +152 -0
- package/test/test-e2e.mjs +9 -3
- package/test/test-encode-decode.mjs +847 -0
- package/test/test-error-handling.mjs +115 -0
- package/test/test-osc-internal.mjs +400 -42
- package/test/test-promises.mjs +249 -0
- package/test/test-types.mjs +39 -0
- package/test/util.mjs +15 -8
- package/tsconfig.json +45 -0
- package/types/Bundle.d.mts +70 -0
- package/types/Bundle.d.mts.map +1 -0
- package/types/Client.d.mts +101 -0
- package/types/Client.d.mts.map +1 -0
- package/types/Message.d.mts +84 -0
- package/types/Message.d.mts.map +1 -0
- package/types/Server.d.mts +98 -0
- package/types/Server.d.mts.map +1 -0
- package/types/index.d.mts +6 -0
- package/types/index.d.mts.map +1 -0
- package/types/internal/decode.d.mts +4 -0
- package/types/internal/decode.d.mts.map +1 -0
- package/types/osc.d.mts +66 -0
- package/types/osc.d.mts.map +1 -0
package/dist/lib/Server.js
CHANGED
|
@@ -4,14 +4,84 @@ var node_dgram = require('node:dgram');
|
|
|
4
4
|
var node_events = require('node:events');
|
|
5
5
|
var decode = require('#decode');
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* OSC Server for receiving messages and bundles over UDP.
|
|
9
|
+
*
|
|
10
|
+
* Emits the following events:
|
|
11
|
+
* - 'listening': Emitted when the server starts listening
|
|
12
|
+
* - 'message': Emitted when an OSC message is received (receives msg array and rinfo object)
|
|
13
|
+
* - 'bundle': Emitted when an OSC bundle is received (receives bundle object and rinfo object)
|
|
14
|
+
* - 'error': Emitted when a socket error or decoding error occurs (receives error and rinfo)
|
|
15
|
+
* - Address-specific events: Emitted for each message address (e.g., '/test')
|
|
16
|
+
*
|
|
17
|
+
* @class
|
|
18
|
+
* @extends EventEmitter
|
|
19
|
+
*
|
|
20
|
+
* @fires Server#listening
|
|
21
|
+
* @fires Server#message
|
|
22
|
+
* @fires Server#bundle
|
|
23
|
+
* @fires Server#error
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Create and listen for messages
|
|
27
|
+
* const server = new Server(3333, '0.0.0.0', () => {
|
|
28
|
+
* console.log('Server is listening');
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* server.on('message', (msg, rinfo) => {
|
|
32
|
+
* console.log('Message:', msg);
|
|
33
|
+
* console.log('From:', rinfo.address, rinfo.port);
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Using async/await with events.once
|
|
38
|
+
* import { once } from 'node:events';
|
|
39
|
+
*
|
|
40
|
+
* const server = new Server(3333, '0.0.0.0');
|
|
41
|
+
* await once(server, 'listening');
|
|
42
|
+
*
|
|
43
|
+
* server.on('message', (msg) => {
|
|
44
|
+
* console.log('Message:', msg);
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Listen for specific OSC addresses
|
|
49
|
+
* server.on('/note', (msg) => {
|
|
50
|
+
* const [address, pitch, velocity] = msg;
|
|
51
|
+
* console.log(`Note: ${pitch}, Velocity: ${velocity}`);
|
|
52
|
+
* });
|
|
53
|
+
*/
|
|
7
54
|
class Server extends node_events.EventEmitter {
|
|
55
|
+
/**
|
|
56
|
+
* Create an OSC Server.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} port - The port to listen on.
|
|
59
|
+
* @param {string} [host='127.0.0.1'] - The host address to bind to. Use '0.0.0.0' to listen on all interfaces.
|
|
60
|
+
* @param {Function} [cb] - Optional callback function called when server starts listening.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Basic server
|
|
64
|
+
* const server = new Server(3333);
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Server on all interfaces with callback
|
|
68
|
+
* const server = new Server(3333, '0.0.0.0', () => {
|
|
69
|
+
* console.log('Server started');
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Host parameter can be omitted, callback as second parameter
|
|
74
|
+
* const server = new Server(3333, () => {
|
|
75
|
+
* console.log('Server started on 127.0.0.1');
|
|
76
|
+
* });
|
|
77
|
+
*/
|
|
8
78
|
constructor(port, host='127.0.0.1', cb) {
|
|
9
79
|
super();
|
|
10
80
|
if (typeof host === 'function') {
|
|
11
81
|
cb = host;
|
|
12
82
|
host = '127.0.0.1';
|
|
13
83
|
}
|
|
14
|
-
|
|
84
|
+
|
|
15
85
|
let decoded;
|
|
16
86
|
this.port = port;
|
|
17
87
|
this.host = host;
|
|
@@ -20,10 +90,20 @@ class Server extends node_events.EventEmitter {
|
|
|
20
90
|
reuseAddr: true
|
|
21
91
|
});
|
|
22
92
|
this._sock.bind(port, host);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
93
|
+
|
|
94
|
+
// Support both callback and promise-based listening
|
|
95
|
+
if (cb) {
|
|
96
|
+
this._sock.on('listening', () => {
|
|
97
|
+
this.emit('listening');
|
|
98
|
+
cb();
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
// For promise support, still emit the event but don't require a callback
|
|
102
|
+
this._sock.on('listening', () => {
|
|
103
|
+
this.emit('listening');
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
27
107
|
this._sock.on('message', (msg, rinfo) => {
|
|
28
108
|
try {
|
|
29
109
|
decoded = decode(msg);
|
|
@@ -41,9 +121,40 @@ class Server extends node_events.EventEmitter {
|
|
|
41
121
|
this.emit(decoded[0], decoded, rinfo);
|
|
42
122
|
}
|
|
43
123
|
});
|
|
124
|
+
|
|
125
|
+
this._sock.on('error', (err) => {
|
|
126
|
+
this.emit('error', err);
|
|
127
|
+
});
|
|
44
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Close the server socket.
|
|
131
|
+
*
|
|
132
|
+
* This method can be used with either a callback or as a Promise.
|
|
133
|
+
*
|
|
134
|
+
* @param {Function} [cb] - Optional callback function called when socket is closed.
|
|
135
|
+
* @returns {Promise<void>|undefined} Returns a Promise if no callback is provided.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* // With callback
|
|
139
|
+
* server.close((err) => {
|
|
140
|
+
* if (err) console.error(err);
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* // With async/await
|
|
145
|
+
* await server.close();
|
|
146
|
+
*/
|
|
45
147
|
close(cb) {
|
|
46
|
-
|
|
148
|
+
if (cb) {
|
|
149
|
+
this._sock.close(cb);
|
|
150
|
+
} else {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
this._sock.close((err) => {
|
|
153
|
+
if (err) reject(err);
|
|
154
|
+
else resolve();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
47
158
|
}
|
|
48
159
|
}
|
|
49
160
|
|
package/dist/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var Message = require('./Message.js');
|
|
|
4
4
|
var Bundle = require('./Bundle.js');
|
|
5
5
|
var Server = require('./Server.js');
|
|
6
6
|
var Client = require('./Client.js');
|
|
7
|
+
var osc = require('./osc.js');
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
|
|
@@ -11,3 +12,5 @@ exports.Message = Message;
|
|
|
11
12
|
exports.Bundle = Bundle;
|
|
12
13
|
exports.Server = Server;
|
|
13
14
|
exports.Client = Client;
|
|
15
|
+
exports.decode = osc.decode;
|
|
16
|
+
exports.encode = osc.encode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var osc = require('../osc.js');
|
|
4
4
|
|
|
5
5
|
function sanitizeMessage(decoded) {
|
|
6
6
|
const message = [];
|
|
@@ -19,8 +19,8 @@ function sanitizeBundle(decoded) {
|
|
|
19
19
|
return decoded;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function
|
|
23
|
-
const decoded =
|
|
22
|
+
function decodeAndSanitize(data, customDecode = osc.decode) {
|
|
23
|
+
const decoded = customDecode(data);
|
|
24
24
|
if (decoded.oscType === 'bundle') {
|
|
25
25
|
return sanitizeBundle(decoded);
|
|
26
26
|
}
|
|
@@ -32,4 +32,4 @@ function decode(data, customFromBuffer = _osc.fromBuffer) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
module.exports =
|
|
35
|
+
module.exports = decodeAndSanitize;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_buffer = require('node:buffer');
|
|
4
|
+
|
|
1
5
|
// OSC 1.0 Protocol Implementation
|
|
2
6
|
// Based on http://opensoundcontrol.org/spec-1_0
|
|
3
7
|
|
|
4
|
-
// Helper functions for OSC encoding/decoding
|
|
5
8
|
|
|
6
9
|
function padString(str) {
|
|
7
10
|
const nullTerminated = str + '\0';
|
|
@@ -21,7 +24,7 @@ function readString(buffer, offset) {
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
function writeInt32(value) {
|
|
24
|
-
const buffer = Buffer.alloc(4);
|
|
27
|
+
const buffer = node_buffer.Buffer.alloc(4);
|
|
25
28
|
buffer.writeInt32BE(value, 0);
|
|
26
29
|
return buffer;
|
|
27
30
|
}
|
|
@@ -32,7 +35,7 @@ function readInt32(buffer, offset) {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
function writeFloat32(value) {
|
|
35
|
-
const buffer = Buffer.alloc(4);
|
|
38
|
+
const buffer = node_buffer.Buffer.alloc(4);
|
|
36
39
|
buffer.writeFloatBE(value, 0);
|
|
37
40
|
return buffer;
|
|
38
41
|
}
|
|
@@ -46,8 +49,8 @@ function writeBlob(value) {
|
|
|
46
49
|
const length = value.length;
|
|
47
50
|
const lengthBuffer = writeInt32(length);
|
|
48
51
|
const padding = 4 - (length % 4);
|
|
49
|
-
const paddingBuffer = Buffer.alloc(padding === 4 ? 0 : padding);
|
|
50
|
-
return Buffer.concat([lengthBuffer, value, paddingBuffer]);
|
|
52
|
+
const paddingBuffer = node_buffer.Buffer.alloc(padding === 4 ? 0 : padding);
|
|
53
|
+
return node_buffer.Buffer.concat([lengthBuffer, value, paddingBuffer]);
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
function readBlob(buffer, offset) {
|
|
@@ -62,7 +65,7 @@ function readBlob(buffer, offset) {
|
|
|
62
65
|
function writeTimeTag(value) {
|
|
63
66
|
// For now, treat timetag as a double (8 bytes)
|
|
64
67
|
// OSC timetag is 64-bit: 32-bit seconds since 1900, 32-bit fractional
|
|
65
|
-
const buffer = Buffer.alloc(8);
|
|
68
|
+
const buffer = node_buffer.Buffer.alloc(8);
|
|
66
69
|
if (typeof value === 'number') {
|
|
67
70
|
// Convert to OSC timetag format
|
|
68
71
|
const seconds = Math.floor(value);
|
|
@@ -97,9 +100,9 @@ function readTimeTag(buffer, offset) {
|
|
|
97
100
|
|
|
98
101
|
function writeMidi(value) {
|
|
99
102
|
// MIDI message is 4 bytes: port id, status byte, data1, data2
|
|
100
|
-
const buffer = Buffer.alloc(4);
|
|
103
|
+
const buffer = node_buffer.Buffer.alloc(4);
|
|
101
104
|
|
|
102
|
-
if (Buffer.isBuffer(value)) {
|
|
105
|
+
if (node_buffer.Buffer.isBuffer(value)) {
|
|
103
106
|
if (value.length !== 4) {
|
|
104
107
|
throw new Error('MIDI message must be exactly 4 bytes');
|
|
105
108
|
}
|
|
@@ -138,7 +141,7 @@ function encodeArgument(arg) {
|
|
|
138
141
|
return { tag: 'f', data: writeFloat32(arg.value) };
|
|
139
142
|
case 's':
|
|
140
143
|
case 'string':
|
|
141
|
-
return { tag: 's', data: Buffer.from(padString(arg.value)) };
|
|
144
|
+
return { tag: 's', data: node_buffer.Buffer.from(padString(arg.value)) };
|
|
142
145
|
case 'b':
|
|
143
146
|
case 'blob':
|
|
144
147
|
return { tag: 'b', data: writeBlob(arg.value) };
|
|
@@ -147,8 +150,11 @@ function encodeArgument(arg) {
|
|
|
147
150
|
// For doubles, use float for now (OSC 1.0 doesn't have double)
|
|
148
151
|
return { tag: 'f', data: writeFloat32(arg.value) };
|
|
149
152
|
case 'T':
|
|
153
|
+
return { tag: 'T', data: node_buffer.Buffer.alloc(0) };
|
|
154
|
+
case 'F':
|
|
155
|
+
return { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
|
150
156
|
case 'boolean':
|
|
151
|
-
return arg.value ? { tag: 'T', data: Buffer.alloc(0) } : { tag: 'F', data: Buffer.alloc(0) };
|
|
157
|
+
return arg.value ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
|
152
158
|
case 'm':
|
|
153
159
|
case 'midi':
|
|
154
160
|
return { tag: 'm', data: writeMidi(arg.value) };
|
|
@@ -166,11 +172,11 @@ function encodeArgument(arg) {
|
|
|
166
172
|
return { tag: 'f', data: writeFloat32(arg) };
|
|
167
173
|
}
|
|
168
174
|
case 'string':
|
|
169
|
-
return { tag: 's', data: Buffer.from(padString(arg)) };
|
|
175
|
+
return { tag: 's', data: node_buffer.Buffer.from(padString(arg)) };
|
|
170
176
|
case 'boolean':
|
|
171
|
-
return arg ? { tag: 'T', data: Buffer.alloc(0) } : { tag: 'F', data: Buffer.alloc(0) };
|
|
177
|
+
return arg ? { tag: 'T', data: node_buffer.Buffer.alloc(0) } : { tag: 'F', data: node_buffer.Buffer.alloc(0) };
|
|
172
178
|
default:
|
|
173
|
-
if (Buffer.isBuffer(arg)) {
|
|
179
|
+
if (node_buffer.Buffer.isBuffer(arg)) {
|
|
174
180
|
return { tag: 'b', data: writeBlob(arg) };
|
|
175
181
|
}
|
|
176
182
|
throw new Error(`Don't know how to encode argument: ${arg}`);
|
|
@@ -200,7 +206,37 @@ function decodeArgument(tag, buffer, offset) {
|
|
|
200
206
|
}
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Encode an OSC message or bundle to a Buffer.
|
|
211
|
+
*
|
|
212
|
+
* This low-level function converts OSC messages and bundles into binary format
|
|
213
|
+
* for transmission or storage. Useful for sending OSC over custom transports
|
|
214
|
+
* (WebSocket, TCP, HTTP), storing to files, or implementing custom OSC routers.
|
|
215
|
+
*
|
|
216
|
+
* @param {Object} message - OSC message or bundle object with oscType property
|
|
217
|
+
* @returns {Buffer} The encoded OSC data ready for transmission
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* // Encode a message
|
|
221
|
+
* import { Message, encode } from 'node-osc';
|
|
222
|
+
*
|
|
223
|
+
* const message = new Message('/oscillator/frequency', 440);
|
|
224
|
+
* const buffer = encode(message);
|
|
225
|
+
* console.log('Encoded bytes:', buffer.length);
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* // Encode a bundle
|
|
229
|
+
* import { Bundle, encode } from 'node-osc';
|
|
230
|
+
*
|
|
231
|
+
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
|
232
|
+
* const buffer = encode(bundle);
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* // Send over WebSocket
|
|
236
|
+
* const buffer = encode(message);
|
|
237
|
+
* websocket.send(buffer);
|
|
238
|
+
*/
|
|
239
|
+
function encode(message) {
|
|
204
240
|
if (message.oscType === 'bundle') {
|
|
205
241
|
return encodeBundleToBuffer(message);
|
|
206
242
|
} else {
|
|
@@ -215,15 +251,15 @@ function encodeMessageToBuffer(message) {
|
|
|
215
251
|
// Arguments (encoded according to type tags)
|
|
216
252
|
|
|
217
253
|
const address = padString(message.address);
|
|
218
|
-
const addressBuffer = Buffer.from(address);
|
|
254
|
+
const addressBuffer = node_buffer.Buffer.from(address);
|
|
219
255
|
|
|
220
256
|
const encodedArgs = message.args.map(encodeArgument);
|
|
221
257
|
const typeTags = ',' + encodedArgs.map(arg => arg.tag).join('');
|
|
222
|
-
const typeTagsBuffer = Buffer.from(padString(typeTags));
|
|
258
|
+
const typeTagsBuffer = node_buffer.Buffer.from(padString(typeTags));
|
|
223
259
|
|
|
224
260
|
const argumentBuffers = encodedArgs.map(arg => arg.data);
|
|
225
261
|
|
|
226
|
-
return Buffer.concat([addressBuffer, typeTagsBuffer, ...argumentBuffers]);
|
|
262
|
+
return node_buffer.Buffer.concat([addressBuffer, typeTagsBuffer, ...argumentBuffers]);
|
|
227
263
|
}
|
|
228
264
|
|
|
229
265
|
function encodeBundleToBuffer(bundle) {
|
|
@@ -233,7 +269,7 @@ function encodeBundleToBuffer(bundle) {
|
|
|
233
269
|
// Elements (each prefixed with size)
|
|
234
270
|
|
|
235
271
|
const bundleString = padString('#bundle');
|
|
236
|
-
const bundleStringBuffer = Buffer.from(bundleString);
|
|
272
|
+
const bundleStringBuffer = node_buffer.Buffer.from(bundleString);
|
|
237
273
|
|
|
238
274
|
const timetagBuffer = writeTimeTag(bundle.timetag);
|
|
239
275
|
|
|
@@ -245,13 +281,45 @@ function encodeBundleToBuffer(bundle) {
|
|
|
245
281
|
elementBuffer = encodeMessageToBuffer(element);
|
|
246
282
|
}
|
|
247
283
|
const sizeBuffer = writeInt32(elementBuffer.length);
|
|
248
|
-
return Buffer.concat([sizeBuffer, elementBuffer]);
|
|
284
|
+
return node_buffer.Buffer.concat([sizeBuffer, elementBuffer]);
|
|
249
285
|
});
|
|
250
286
|
|
|
251
|
-
return Buffer.concat([bundleStringBuffer, timetagBuffer, ...elementBuffers]);
|
|
287
|
+
return node_buffer.Buffer.concat([bundleStringBuffer, timetagBuffer, ...elementBuffers]);
|
|
252
288
|
}
|
|
253
289
|
|
|
254
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Decode a Buffer containing OSC data into a message or bundle object.
|
|
292
|
+
*
|
|
293
|
+
* This low-level function parses binary OSC data back into JavaScript objects.
|
|
294
|
+
* Useful for receiving OSC over custom transports, reading from files,
|
|
295
|
+
* or implementing custom OSC routers.
|
|
296
|
+
*
|
|
297
|
+
* @param {Buffer} buffer - The Buffer containing OSC data
|
|
298
|
+
* @returns {Object} The decoded OSC message or bundle. Messages have
|
|
299
|
+
* {oscType: 'message', address: string, args: Array}, bundles have
|
|
300
|
+
* {oscType: 'bundle', timetag: number, elements: Array}
|
|
301
|
+
* @throws {Error} If the buffer contains malformed OSC data
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* // Decode received data
|
|
305
|
+
* import { decode } from 'node-osc';
|
|
306
|
+
*
|
|
307
|
+
* const decoded = decode(buffer);
|
|
308
|
+
* if (decoded.oscType === 'message') {
|
|
309
|
+
* console.log('Address:', decoded.address);
|
|
310
|
+
* console.log('Arguments:', decoded.args);
|
|
311
|
+
* }
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* // Round-trip encode/decode
|
|
315
|
+
* import { Message, encode, decode } from 'node-osc';
|
|
316
|
+
*
|
|
317
|
+
* const original = new Message('/test', 42, 'hello');
|
|
318
|
+
* const buffer = encode(original);
|
|
319
|
+
* const decoded = decode(buffer);
|
|
320
|
+
* console.log(decoded.address); // '/test'
|
|
321
|
+
*/
|
|
322
|
+
function decode(buffer) {
|
|
255
323
|
// Check if it's a bundle or message
|
|
256
324
|
if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === '#bundle\0') {
|
|
257
325
|
return decodeBundleFromBuffer(buffer);
|
|
@@ -311,7 +379,7 @@ function decodeBundleFromBuffer(buffer) {
|
|
|
311
379
|
|
|
312
380
|
// Read element data
|
|
313
381
|
const elementBuffer = buffer.subarray(offset, offset + size);
|
|
314
|
-
const element =
|
|
382
|
+
const element = decode(elementBuffer);
|
|
315
383
|
elements.push(element);
|
|
316
384
|
offset += size;
|
|
317
385
|
}
|
|
@@ -321,4 +389,7 @@ function decodeBundleFromBuffer(buffer) {
|
|
|
321
389
|
timetag,
|
|
322
390
|
elements
|
|
323
391
|
};
|
|
324
|
-
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
exports.decode = decode;
|
|
395
|
+
exports.encode = encode;
|