Files
midi-tools/src/core/midi-task.ts
T
zemion 06e095a2eb
Verify / verify (push) Canceled after 0s
Release MIDI Tools 0.2.0
2026-09-02 09:14:48 +02:00

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",
};
}