92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import {
|
|
constantTempoMidi,
|
|
cropMidi,
|
|
deleteNote,
|
|
editNote,
|
|
dropChannel,
|
|
encodeMidi,
|
|
exportMidiCsv,
|
|
exportMidiJson,
|
|
parseMidi,
|
|
quantizeMidi,
|
|
remapChannel,
|
|
transposeMidi,
|
|
type MidiDocument,
|
|
} from "./midi";
|
|
|
|
export type MidiOperation =
|
|
| { kind: "transpose"; semitones: number }
|
|
| { kind: "quantize"; grid: number }
|
|
| { kind: "tempo"; bpm: number }
|
|
| { kind: "crop"; start: number; end: number }
|
|
| { kind: "remap-channel"; from: number; to: number }
|
|
| { kind: "drop-channel"; channel: number }
|
|
| {
|
|
kind: "edit-note";
|
|
onOrder: number;
|
|
note: number;
|
|
velocity: number;
|
|
startTick: number;
|
|
endTick: number;
|
|
}
|
|
| { kind: "delete-note"; onOrder: number };
|
|
|
|
export type MidiTask =
|
|
| { kind: "parse"; name: string; bytes: ArrayBuffer }
|
|
| { kind: "operation"; document: MidiDocument; operation: MidiOperation }
|
|
| {
|
|
kind: "export";
|
|
document: MidiDocument;
|
|
format: "midi" | "csv" | "json";
|
|
};
|
|
|
|
export type MidiTaskResult =
|
|
| { kind: "document"; document: MidiDocument }
|
|
| { kind: "bytes"; bytes: ArrayBuffer; mimeType: string }
|
|
| { kind: "text"; text: string; mimeType: string };
|
|
|
|
/** Pure task entry point shared by the module worker and test fallback. */
|
|
export function executeMidiTask(task: MidiTask): MidiTaskResult {
|
|
if (task.kind === "parse")
|
|
return {
|
|
kind: "document",
|
|
document: parseMidi(task.name, new Uint8Array(task.bytes)),
|
|
};
|
|
if (task.kind === "operation") {
|
|
const { document, operation } = task;
|
|
const next =
|
|
operation.kind === "transpose"
|
|
? transposeMidi(document, operation.semitones)
|
|
: operation.kind === "quantize"
|
|
? quantizeMidi(document, operation.grid)
|
|
: operation.kind === "tempo"
|
|
? constantTempoMidi(document, operation.bpm)
|
|
: operation.kind === "crop"
|
|
? cropMidi(document, operation.start, operation.end)
|
|
: operation.kind === "remap-channel"
|
|
? remapChannel(document, operation.from, operation.to)
|
|
: operation.kind === "drop-channel"
|
|
? dropChannel(document, operation.channel)
|
|
: operation.kind === "edit-note"
|
|
? editNote(document, operation.onOrder, operation)
|
|
: deleteNote(document, operation.onOrder);
|
|
return { kind: "document", document: next };
|
|
}
|
|
if (task.format === "midi") {
|
|
const bytes = encodeMidi(task.document);
|
|
return {
|
|
kind: "bytes",
|
|
bytes: Uint8Array.from(bytes).buffer,
|
|
mimeType: "audio/midi",
|
|
};
|
|
}
|
|
return {
|
|
kind: "text",
|
|
text:
|
|
task.format === "csv"
|
|
? exportMidiCsv(task.document)
|
|
: exportMidiJson(task.document),
|
|
mimeType: task.format === "csv" ? "text/csv" : "application/json",
|
|
};
|
|
}
|