Files
osc-js/src/osc.ts
T

148 lines
4.5 KiB
TypeScript

import { OSCType, OSCArg, OSCMessage, OSCTypeConverter } from './models';
const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = {
s: {
toBuffer: (string) => {
if (typeof string === 'string') {
let oscString = `${string}\u0000`;
const padSize = 4 - (oscString.length % 4);
if (padSize < 4) {
oscString = oscString.padEnd(oscString.length + padSize, '\u0000');
}
return Buffer.from(oscString, 'ascii');
}
throw new Error('osc type s toBuffer called with non string value');
},
fromString: (string: string) => string,
fromBuffer: (bytes: Buffer) => {
let stringEnd = 0;
let stringPaddingEnd = 0;
for (let index = 0; index < bytes.length; index++) {
if(bytes[index] === 0){
stringEnd = index;
stringPaddingEnd = index + 1;
const stringPadding = 4-(stringEnd+1) % 4;
if(stringPadding < 4){
stringPaddingEnd += stringPadding;
}
break;
}
}
return [bytes.toString('ascii', 0, stringEnd), bytes.subarray(stringPaddingEnd)]
}
},
f: {
toBuffer: (number) => {
if (typeof number === 'number') {
const buffer = Buffer.alloc(4);
buffer.writeFloatBE(number);
return buffer;
}
throw new Error('osc type f toBuffer called with non number value');
},
fromString: (string: string) => Number.parseFloat(string),
},
i: {
toBuffer: (number) => {
if (typeof number === 'number') {
const buffer = Buffer.alloc(4);
buffer.writeInt32BE(number);
return buffer;
}
throw new Error('osc type i toBuffer called with non number value');
},
fromString: (string: string) => Number.parseInt(string, 10),
},
b: {
toBuffer: (data) => {
if (Buffer.isBuffer(data)) {
const sizeBuffer = oscTypeConverterMap.i.toBuffer(data.length);
if (sizeBuffer) {
const padSize = 4 - (data.length % 4);
const padBuffer = Buffer.from(Array(padSize).fill(0));
return Buffer.concat([sizeBuffer, data, padBuffer]);
}
}
throw new Error('osc type b toBuffer called with non Buffer value');
},
fromString: (string: string) => Buffer.from(string, 'hex'),
},
T: {
toBuffer: () => {
return Buffer.alloc(0)
},
fromString: (string: string) => true
},
F: {
toBuffer: () => {
return Buffer.alloc(0)
},
fromString: (string: string) => false
}
};
function argsToBuffer(args: OSCArg[]) {
const argBuffers: Buffer[] = [];
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
const typeConverter = oscTypeConverterMap[arg.type];
if (typeConverter === undefined) {
throw new Error('osc type error: unknown type '.concat(arg.type));
}
if (typeConverter.fromString === undefined) {
throw new Error('osc type error: no string converter for type '.concat(arg.type));
}
const buffer = typeConverter.toBuffer(arg.value);
if (buffer !== undefined) {
argBuffers.push(buffer);
}
}
return Buffer.concat(argBuffers);
}
export function messageToBuffer(message: OSCMessage) {
const addressBuffer = oscTypeConverterMap.s.toBuffer(message.address);
if (addressBuffer === undefined) {
throw new Error('problem encoding address');
}
const typeString = message.args.map((arg) => arg.type).join('');
const typesBuffer = oscTypeConverterMap.s.toBuffer(`,${typeString}`);
if (typesBuffer === undefined) {
throw new Error('problem encoding types');
}
const argsBuffer = argsToBuffer(message.args);
return Buffer.concat([addressBuffer, typesBuffer, argsBuffer]);
}
export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined {
if(bytes[0] !== 47){
throw new Error('osc message must start with a /')
}
const oscArgs: OSCArg[] = []
if(oscTypeConverterMap.s.fromBuffer) {
const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes)
if(typeof address === 'string'){
console.log(`address: ${address}`)
console.log(`bytesAfterAddresss: ${bytesAfterAddress}`)
let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress)
console.log(`typeString: ${typeString}`)
console.log(`bytesAfterType: ${bytesAfterType}`)
if(typeof typeString === 'string'){
if(!typeString.startsWith(',')){
throw new Error('osc type string must start with a ,')
}
}
}
}
return
}