mirror of
https://github.com/jwetzell/osc-js.git
synced 2026-08-06 15:53:46 +00:00
118 lines
3.6 KiB
TypeScript
118 lines
3.6 KiB
TypeScript
import { messageFromBuffer, messageToBuffer } from './message';
|
|
import { OSCBundle } from './models';
|
|
import { oscTypeConverterMap } from './osc-types';
|
|
|
|
export function bundleFromBuffer(bytes: Uint8Array): [OSCBundle | undefined, Uint8Array | undefined] {
|
|
if (bytes.length < 20) {
|
|
throw new Error('bundle has to be at least 20 bytes');
|
|
}
|
|
|
|
if (new TextDecoder().decode(bytes.subarray(0, 7)) !== '#bundle') {
|
|
throw new Error('bundle must start with #bundle');
|
|
}
|
|
|
|
const [bundleHeader, bytesAfterHeader] = oscTypeConverterMap.s.fromBuffer(bytes);
|
|
const [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);
|
|
let remainingBytes = bytesAfterTimeTag;
|
|
|
|
while (!endOfBundle) {
|
|
const [contentSize, bytesAfterContentSize] = oscTypeConverterMap.i.fromBuffer(remainingBytes);
|
|
|
|
if (typeof contentSize !== 'number') {
|
|
throw new Error('problem decoding content size');
|
|
}
|
|
|
|
remainingBytes = bytesAfterContentSize;
|
|
|
|
if (remainingBytes.length < contentSize) {
|
|
throw new Error('bundle does not contain enough data');
|
|
}
|
|
|
|
const bundleContentBytes = bytesAfterContentSize.subarray(0, contentSize);
|
|
|
|
if (bundleContentBytes[0] === 35) {
|
|
// # character indicating contents is a bundle
|
|
const [content, bytesAfterContent] = bundleFromBuffer(bundleContentBytes);
|
|
if (content) {
|
|
bundleContents.push(content);
|
|
}
|
|
} else if (bundleContentBytes[0] === 47) {
|
|
const [content, bytesAfterContent] = messageFromBuffer(bundleContentBytes);
|
|
if (content && content !== undefined) {
|
|
bundleContents.push(content);
|
|
}
|
|
} else {
|
|
throw new Error('bundle contents does not look like a OSC message or bundle');
|
|
}
|
|
|
|
remainingBytes = bytesAfterContentSize.subarray(contentSize);
|
|
if (remainingBytes.length === 0) {
|
|
endOfBundle = true;
|
|
}
|
|
}
|
|
|
|
return [
|
|
{
|
|
timeTag,
|
|
contents: bundleContents,
|
|
},
|
|
remainingBytes,
|
|
];
|
|
}
|
|
|
|
export function bundleToBuffer(bundle: OSCBundle): Uint8Array {
|
|
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: Uint8Array[] = [];
|
|
|
|
let contentsBuffersTotalLength = 0;
|
|
|
|
bundle.contents.forEach((bundleContent) => {
|
|
if ('address' in bundleContent) {
|
|
const contentBuffer = messageToBuffer(bundleContent);
|
|
const contentSizeBuffer = oscTypeConverterMap.i.toBuffer(contentBuffer.length);
|
|
|
|
if (contentBuffer && contentSizeBuffer) {
|
|
const buffer = new Uint8Array(contentSizeBuffer.length + contentBuffer.length);
|
|
buffer.set(contentSizeBuffer, 0);
|
|
buffer.set(contentBuffer, contentSizeBuffer.length);
|
|
contentsBuffers.push(buffer);
|
|
contentsBuffersTotalLength += buffer.length;
|
|
}
|
|
}
|
|
});
|
|
|
|
const buffer = new Uint8Array(headerBuffer.length + timeTagBuffer.length + contentsBuffersTotalLength);
|
|
let offset = 0;
|
|
buffer.set(headerBuffer, offset);
|
|
offset += headerBuffer.length;
|
|
buffer.set(timeTagBuffer, offset);
|
|
offset += timeTagBuffer.length;
|
|
contentsBuffers.forEach((contentBuffer) => {
|
|
buffer.set(contentBuffer, offset);
|
|
offset += contentBuffer.length;
|
|
});
|
|
|
|
return buffer;
|
|
}
|