mirror of
https://github.com/jwetzell/osc-js.git
synced 2026-07-26 10:28:46 +00:00
add bundleFromBuffer and bundleToBuffer
This commit is contained in:
+11
-4
@@ -1,7 +1,14 @@
|
||||
export type OSCType = 's' | 'i' | 'f' | 'b' | 'T' | 'F';
|
||||
export type OSCType = 's' | 'i' | 'f' | 'b' | 'T' | 'F' | 't';
|
||||
export type OSCArg = {
|
||||
type: OSCType;
|
||||
value: string | number | Buffer | boolean;
|
||||
value: string | number | Buffer | boolean | OSCTimeTag;
|
||||
};
|
||||
|
||||
export type OSCTimeTag = [number, number];
|
||||
|
||||
export type OSCBundle = {
|
||||
timeTag: OSCTimeTag;
|
||||
contents: (OSCBundle | OSCMessage)[];
|
||||
};
|
||||
|
||||
export type OSCMessage = {
|
||||
@@ -10,6 +17,6 @@ export type OSCMessage = {
|
||||
};
|
||||
|
||||
export type OSCTypeConverter = {
|
||||
toBuffer: (value: string | number | Buffer | boolean) => Buffer | undefined;
|
||||
fromBuffer: (buffer: Buffer) => [string | number | Buffer | boolean | undefined, Buffer];
|
||||
toBuffer: (value: string | number | Buffer | boolean | OSCTimeTag) => Buffer | undefined;
|
||||
fromBuffer: (buffer: Buffer) => [string | number | Buffer | boolean | OSCTimeTag | undefined, Buffer];
|
||||
};
|
||||
|
||||
+128
-1
@@ -1,4 +1,4 @@
|
||||
import { OSCType, OSCArg, OSCMessage, OSCTypeConverter } from './models';
|
||||
import { OSCType, OSCArg, OSCMessage, OSCTypeConverter, OSCBundle, OSCTimeTag } from './models';
|
||||
|
||||
const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = {
|
||||
s: {
|
||||
@@ -111,6 +111,46 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = {
|
||||
return [false, buffer];
|
||||
},
|
||||
},
|
||||
t: {
|
||||
toBuffer: (timetag) => {
|
||||
if (!Array.isArray(timetag)) {
|
||||
throw new TypeError('osc type t toBuffer called with non array value');
|
||||
}
|
||||
|
||||
if (timetag.length != 2) {
|
||||
throw new TypeError('osc type t array should have exactly 2 elements');
|
||||
}
|
||||
|
||||
const seconds = timetag[0];
|
||||
if (typeof seconds !== 'number') {
|
||||
throw new TypeError('osc type t seconds part should be a number');
|
||||
}
|
||||
|
||||
const fractional = timetag[1];
|
||||
if (typeof fractional !== 'number') {
|
||||
throw new TypeError('osc type t fractional part should be a number');
|
||||
}
|
||||
|
||||
const secondsBuffer = oscTypeConverterMap.i.toBuffer(seconds);
|
||||
const fractionalBuffer = oscTypeConverterMap.i.toBuffer(fractional);
|
||||
|
||||
if (secondsBuffer && fractionalBuffer) {
|
||||
return Buffer.concat([secondsBuffer, fractionalBuffer]);
|
||||
}
|
||||
},
|
||||
fromBuffer: (buffer) => {
|
||||
if (buffer.length < 8) {
|
||||
throw new Error('osc time tag must be greater than 8 bytes');
|
||||
}
|
||||
const [seconds, bytesAfterSeconds] = oscTypeConverterMap.i.fromBuffer(buffer);
|
||||
const [fractional, bytesAfterFractional] = oscTypeConverterMap.i.fromBuffer(bytesAfterSeconds);
|
||||
if (typeof seconds === 'number' && typeof fractional === 'number') {
|
||||
const timeTag: OSCTimeTag = [seconds, fractional];
|
||||
return [timeTag, bytesAfterFractional];
|
||||
}
|
||||
return [undefined, bytesAfterFractional];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function argsToBuffer(args: OSCArg[]) {
|
||||
@@ -186,3 +226,90 @@ export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function bundleFromBuffer(bytes: Buffer): OSCBundle | undefined {
|
||||
if (bytes.length < 8) {
|
||||
throw new Error('bundle has to be at least 20 bytes');
|
||||
}
|
||||
|
||||
if (bytes.subarray(0, 7).toString('ascii') !== '#bundle') {
|
||||
throw new Error('bundle must start with #bundle');
|
||||
}
|
||||
|
||||
const [bundleHeader, bytesAfterHeader] = oscTypeConverterMap.s.fromBuffer(bytes);
|
||||
let [timeTag, bytesAfterTimeTag] = oscTypeConverterMap.t.fromBuffer(bytesAfterHeader);
|
||||
|
||||
if (!Array.isArray(timeTag)) {
|
||||
throw new Error('problem getting bundle time tag');
|
||||
}
|
||||
|
||||
const bundleContents = [];
|
||||
|
||||
let endOfBundle = false;
|
||||
|
||||
let [contentSize, remainingBytes] = oscTypeConverterMap.i.fromBuffer(bytesAfterTimeTag);
|
||||
if (typeof contentSize === 'number') {
|
||||
while (!endOfBundle) {
|
||||
if (remainingBytes.length < contentSize) {
|
||||
throw new Error('bundle does not contain enough data');
|
||||
}
|
||||
|
||||
const bundleContentBytes = remainingBytes.subarray(0, contentSize);
|
||||
console.log(bundleContentBytes);
|
||||
|
||||
if (bundleContentBytes[0] === 35) {
|
||||
// # character indicating contents is a bundle
|
||||
const content = bundleFromBuffer(bundleContentBytes);
|
||||
if (content) {
|
||||
bundleContents.push(content);
|
||||
}
|
||||
} else if (bundleContentBytes[0] === 47) {
|
||||
const content = messageFromBuffer(bundleContentBytes);
|
||||
if (content) {
|
||||
bundleContents.push(content);
|
||||
}
|
||||
} else {
|
||||
throw new Error('bundle contents does not look like a OSC message or bundle');
|
||||
}
|
||||
|
||||
remainingBytes = remainingBytes.subarray(contentSize);
|
||||
if (remainingBytes.length === 0) {
|
||||
endOfBundle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
timeTag,
|
||||
contents: bundleContents,
|
||||
};
|
||||
}
|
||||
|
||||
export function bundleToBuffer(bundle: OSCBundle): Buffer {
|
||||
const headerBuffer = oscTypeConverterMap.s.toBuffer('#bundle');
|
||||
|
||||
if (headerBuffer === undefined) {
|
||||
throw new Error('problem encoding buffer header');
|
||||
}
|
||||
|
||||
const timeTagBuffer = oscTypeConverterMap.t.toBuffer(bundle.timeTag);
|
||||
|
||||
if (timeTagBuffer === undefined) {
|
||||
throw new Error('problem encoding buffer time tag');
|
||||
}
|
||||
|
||||
const contentsBuffers: Buffer[] = [];
|
||||
|
||||
bundle.contents.forEach((bundleContent) => {
|
||||
if ('address' in bundleContent) {
|
||||
const contentBuffer = messageToBuffer(bundleContent);
|
||||
const contentSizeBuffer = oscTypeConverterMap.i.toBuffer(contentBuffer.length);
|
||||
|
||||
if (contentBuffer && contentSizeBuffer) {
|
||||
contentsBuffers.push(Buffer.concat([contentSizeBuffer, contentBuffer]));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Buffer.concat([headerBuffer, timeTagBuffer, ...contentsBuffers]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user