mirror of
https://github.com/jwetzell/osc-js.git
synced 2026-08-09 09:13:41 +00:00
149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
import { OSCMessage, OSCArg, OSCType } from './models';
|
|
import { oscTypeConverterMap } from './osc-types';
|
|
|
|
function argsToBuffer(args: OSCArg[]) {
|
|
const argBuffers: Uint8Array[] = [];
|
|
let argBuffersTotalLength = 0;
|
|
|
|
for (let index = 0; index < args.length; index += 1) {
|
|
const arg = args[index];
|
|
const typeConverter = oscTypeConverterMap[arg.type];
|
|
if (typeConverter === undefined) {
|
|
throw new TypeError('unknown type '.concat(arg.type));
|
|
}
|
|
|
|
const buffer = typeConverter.toBuffer(arg.value);
|
|
if (buffer !== undefined) {
|
|
argBuffers.push(buffer);
|
|
argBuffersTotalLength += buffer.length;
|
|
}
|
|
}
|
|
const buffer = new Uint8Array(argBuffersTotalLength);
|
|
let offset = 0;
|
|
argBuffers.forEach((argBuffer) => {
|
|
buffer.set(argBuffer, offset);
|
|
offset += argBuffer.length;
|
|
});
|
|
return buffer;
|
|
}
|
|
|
|
export function messageToBuffer(message: OSCMessage): Uint8Array {
|
|
if (!message.address.startsWith('/')) {
|
|
throw new Error('osc message must start with a /');
|
|
}
|
|
|
|
const addressBuffer = oscTypeConverterMap.s.toBuffer(message.address);
|
|
if (addressBuffer === undefined) {
|
|
throw new Error('problem encoding address');
|
|
}
|
|
|
|
let typeString = ',';
|
|
|
|
const flatOSCArgs: OSCArg[] = [];
|
|
|
|
message.args.forEach((oscArg) => {
|
|
if (Array.isArray(oscArg)) {
|
|
typeString += '[';
|
|
oscArg.forEach((oscArg) => {
|
|
typeString += oscArg.type;
|
|
flatOSCArgs.push(oscArg);
|
|
});
|
|
typeString += ']';
|
|
} else {
|
|
typeString += oscArg.type;
|
|
flatOSCArgs.push(oscArg);
|
|
}
|
|
});
|
|
|
|
const typesBuffer = oscTypeConverterMap.s.toBuffer(typeString);
|
|
if (typesBuffer === undefined) {
|
|
throw new Error('problem encoding types');
|
|
}
|
|
const argsBuffer = argsToBuffer(flatOSCArgs);
|
|
const buffer = new Uint8Array(addressBuffer.length + typesBuffer.length + argsBuffer.length);
|
|
buffer.set(addressBuffer, 0);
|
|
buffer.set(typesBuffer, addressBuffer.length);
|
|
buffer.set(argsBuffer, addressBuffer.length + typesBuffer.length);
|
|
return buffer;
|
|
}
|
|
|
|
export function messageFromBuffer(bytes: Uint8Array): [OSCMessage | undefined, Uint8Array | undefined] {
|
|
if (bytes[0] !== 47) {
|
|
throw new Error('osc message must start with a /');
|
|
}
|
|
|
|
const oscArgs: (OSCArg | OSCArg[])[] = [];
|
|
|
|
const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes);
|
|
if (typeof address === 'string') {
|
|
if (bytesAfterAddress.length === 0) {
|
|
// NOTE(jwetzell): OSC 1.0 spec says that messages without a type string should be allowed
|
|
return [
|
|
{
|
|
address,
|
|
args: [],
|
|
},
|
|
bytesAfterAddress,
|
|
];
|
|
}
|
|
|
|
const [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress);
|
|
if (typeof typeString === 'string') {
|
|
if (!typeString.startsWith(',')) {
|
|
throw new Error('osc type string must start with a ,');
|
|
}
|
|
let argsBuffer = bytesAfterType;
|
|
let oscArrayArg: OSCArg[] = [];
|
|
let insideArgArray = false;
|
|
for (let index = 1; index < typeString.length; index++) {
|
|
const argType = typeString.charAt(index) as OSCType;
|
|
|
|
if (argType === '[') {
|
|
if (insideArgArray) {
|
|
throw new Error('osc arg array opened without closing previous arg array');
|
|
}
|
|
oscArrayArg = [];
|
|
insideArgArray = true;
|
|
continue;
|
|
}
|
|
|
|
if (argType === ']') {
|
|
if (!insideArgArray) {
|
|
throw new Error('osc arg array closed without opening arg array');
|
|
}
|
|
oscArgs.push(oscArrayArg);
|
|
oscArrayArg = [];
|
|
insideArgArray = false;
|
|
continue;
|
|
}
|
|
|
|
const oscTypeConverter = oscTypeConverterMap[argType];
|
|
if (oscTypeConverter === undefined) {
|
|
throw new Error('unknown OSC type');
|
|
}
|
|
const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer);
|
|
if (value !== undefined) {
|
|
const arg: OSCArg = {
|
|
type: argType,
|
|
value: value,
|
|
};
|
|
if (insideArgArray) {
|
|
oscArrayArg.push(arg);
|
|
} else {
|
|
oscArgs.push(arg);
|
|
}
|
|
}
|
|
argsBuffer = remainingBytes;
|
|
}
|
|
return [
|
|
{
|
|
address,
|
|
args: oscArgs,
|
|
},
|
|
argsBuffer,
|
|
];
|
|
}
|
|
}
|
|
return [undefined, undefined];
|
|
}
|