Release MIDI Tools 0.2.0
Verify / verify (push) Canceled after 0s

This commit is contained in:
2026-09-02 09:14:48 +02:00
parent 4b51a6d903
commit 06e095a2eb
40 changed files with 1581 additions and 126 deletions
+63
View File
@@ -1,4 +1,5 @@
import { expect, test } from "@playwright/test";
import { Buffer } from "node:buffer";
for (const path of ["/", "/deep/nested/midi/"]) {
test(`inspects and edits MIDI locally at ${path}`, async ({ page }) => {
@@ -26,6 +27,40 @@ for (const path of ["/", "/deep/nested/midi/"]) {
});
}
test("parses and exports through the MIDI worker", async ({ page }) => {
await page.goto("/");
await page.getByLabel("Open MIDI file").setInputFiles({
name: "worker.mid",
mimeType: "audio/midi",
buffer: midiFixture(),
});
await expect(page.getByRole("status")).toContainText("Parsed type 0 MIDI");
const pending = page.waitForEvent("download");
await page.getByRole("button", { name: "Download MIDI" }).click();
expect((await pending).suggestedFilename()).toBe("worker.mid");
await expect(page.getByRole("status")).toContainText(
"MIDI export generated in the worker",
);
});
test("edits a paired note and inspects a local SoundFont", async ({ page }) => {
await page.goto("/");
await page.getByRole("button", { name: "Select first note" }).click();
await page.getByLabel("Pitch (0127)").fill("61");
await page.getByLabel("Velocity").fill("77");
await page.getByRole("button", { name: "Apply note edit" }).click();
await expect(page.getByRole("status")).toContainText("note updated");
await page.getByLabel("Open SoundFont file").setInputFiles({
name: "fixture.sf2",
mimeType: "audio/x-soundfont",
buffer: soundFontFixture(),
});
await expect(page.getByRole("status")).toContainText(
"Inspected the local SoundFont structure",
);
await expect(page.getByText("Fixture bank", { exact: true })).toBeVisible();
});
test("keeps the installed MIDI application available offline", async ({
page,
context,
@@ -45,3 +80,31 @@ test("keeps the installed MIDI application available offline", async ({
await context.setOffline(false);
}
});
function midiFixture(): Buffer {
return Buffer.from([
0x4d, 0x54, 0x68, 0x64, 0, 0, 0, 6, 0, 0, 0, 1, 1, 0xe0, 0x4d, 0x54, 0x72,
0x6b, 0, 0, 0, 12, 0, 0x90, 60, 100, 0x83, 0x60, 60, 0, 0, 0xff, 0x2f, 0,
]);
}
function soundFontFixture(): Buffer {
const chunk = (id: string, data: Buffer) => {
const output = Buffer.alloc(8 + data.length + (data.length & 1));
output.write(id, 0, "ascii");
output.writeUInt32LE(data.length, 4);
data.copy(output, 8);
return output;
};
const list = (id: string, ...children: Buffer[]) =>
chunk("LIST", Buffer.concat([Buffer.from(id, "ascii"), ...children]));
const body = Buffer.concat([
Buffer.from("sfbk", "ascii"),
list("INFO", chunk("INAM", Buffer.from("Fixture bank\0"))),
list("pdta", chunk("phdr", Buffer.alloc(76))),
]);
const output = Buffer.alloc(8);
output.write("RIFF", 0, "ascii");
output.writeUInt32LE(body.length, 4);
return Buffer.concat([output, body]);
}