@holzchopf/flp-file
Version:
Reads and writes FL Studio project and state files.
108 lines (107 loc) • 3.28 kB
JavaScript
import { ArrayBufferStream, joinArrayBuffers } from "@holzchopf/array-buffer-stream";
import { FLPEvent } from "./flp-event";
import { FLPFileFormat } from "./flp-file-format";
/**
* Class representing a chunk in an FLPFile.
*/
export class FLPChunk {
constructor(type) {
this.type = type;
}
}
/**
* Specific class for the header chunk.
*/
export class FLPHeaderChunk extends FLPChunk {
/**
* Name of file format.
*/
get formatName() {
return FLPFileFormat.name(this.format);
}
getBinary() {
const stream = new ArrayBufferStream(new ArrayBuffer(6));
stream.writeUint16(this.format, true);
stream.writeUint16(this.channelCnt, true);
stream.writeUint16(this.ppq, true);
return stream.buffer;
}
setBinary(buffer) {
const stream = new ArrayBufferStream(buffer);
this.format = stream.readUint16(true);
this.channelCnt = stream.readUint16(true);
this.ppq = stream.readUint16(true);
}
constructor() {
super('FLhd');
/**
* Numeric file format identifier.
*/
this.format = -1;
/**
* Number of channels.
*/
this.channelCnt = 0;
/**
* Project PPQ.
*/
this.ppq = 96;
}
}
/**
* Specific class for the data chunk.
*/
export class FLPDataChunk extends FLPChunk {
getBinary() {
const buffers = [];
this.events.forEach((event) => {
const type = event.type;
const bytes = event.getBinary();
// size is pre-defined for primitives
let size = event.maxByteLength;
if (size) {
// total size is 1 (type) + event.size
const stream = new ArrayBufferStream(new ArrayBuffer(1 + bytes.byteLength));
stream.writeUint8(type);
stream.writeBytes(bytes);
buffers.push(stream.buffer);
}
else {
// total size is 1 (type) + max 16 (LEB128) + event.size
const stream = new ArrayBufferStream(new ArrayBuffer(1 + 16 + bytes.byteLength));
stream.writeUint8(type);
stream.writeUleb128(bytes.byteLength);
stream.writeBytes(bytes);
// only push used buffer
buffers.push(stream.buffer.slice(0, stream.cursor));
}
});
// concatenate all those ArrayBuffers
return joinArrayBuffers(buffers);
}
setBinary(buffer) {
const stream = new ArrayBufferStream(buffer);
this.events = [];
while (!stream.eof()) {
const type = stream.readUint8();
const event = new FLPEvent(type);
// size is pre-defined for primitives
let size = event.maxByteLength;
if (size) {
event.setBinary(stream.readBytes(size));
}
else {
size = stream.readUleb128();
event.setBinary(stream.readBytes(size));
}
this.events.push(event);
}
}
constructor() {
super('FLdt');
/**
* FLPEvents in this chunk.
*/
this.events = [];
}
}