Show length on a staff under each fingering chart.
AppImage release / appimage (push) Successful in 50s
AppImage release / appimage (push) Successful in 50s
Dragging no longer selects text. The line box resizes, rests and spaces can be added, and Save PNG writes the row. Each chart keeps the foot at the top, and the treble staff shows the pitch with a notehead, stem, flags, and dots. Version 0.2.1. Co-authored-by: catpersonisme <catpersonisme@gmail.com>
This commit is contained in:
11 files changed
+997
-177
No files matched your search
@@ -0,0 +1,55 @@
|
||||
import type { LineNote } from "@/lib/line";
|
||||
import { chartPixelHeight } from "@/lib/notation";
|
||||
|
||||
export const PNG_CHART_WIDTH = 88;
|
||||
const GAP = 18;
|
||||
const PAD = 28;
|
||||
|
||||
export { chartPixelHeight };
|
||||
|
||||
/** A quarter space is about one chart wide. Longer spaces take more room. */
|
||||
export function spacePixelWidth(quarters: number, chartWidth: number): number {
|
||||
return Math.max(Math.round(chartWidth * 0.45), Math.round(chartWidth * Math.max(quarters, 0)));
|
||||
}
|
||||
|
||||
export type PngItem = {
|
||||
kind: LineNote["kind"];
|
||||
caption: string;
|
||||
glyphWidth: number;
|
||||
glyphHeight: number;
|
||||
};
|
||||
|
||||
export function pngItemFromNote(note: Pick<LineNote, "kind" | "pitch" | "quarters" | "label">, chartWidth = PNG_CHART_WIDTH): PngItem {
|
||||
const glyphHeight = chartPixelHeight(chartWidth);
|
||||
const caption = note.kind === "note" ? note.pitch : note.kind === "rest" ? "Rest" : "Space";
|
||||
return {
|
||||
kind: note.kind,
|
||||
caption,
|
||||
glyphWidth: note.kind === "space" ? spacePixelWidth(note.quarters, chartWidth) : chartWidth,
|
||||
glyphHeight,
|
||||
};
|
||||
}
|
||||
|
||||
export function pngSlotWidth(item: PngItem): number {
|
||||
const text = item.caption.length * 8;
|
||||
return Math.max(item.glyphWidth, text, 48);
|
||||
}
|
||||
|
||||
export function pngLayout(items: PngItem[], title: string) {
|
||||
const slots = items.map((item) => ({ item, width: pngSlotWidth(item) }));
|
||||
const content =
|
||||
slots.reduce((sum, slot) => sum + slot.width, 0) + GAP * Math.max(0, slots.length - 1);
|
||||
const titleWidth = Math.max(220, title.length * 13 + 8);
|
||||
const width = Math.max(titleWidth, content, 1) + PAD * 2;
|
||||
const glyphHeight = chartPixelHeight(PNG_CHART_WIDTH);
|
||||
const height = PAD + 44 + glyphHeight + 28 + PAD;
|
||||
return { width, height, slots, glyphHeight, pad: PAD, gap: GAP };
|
||||
}
|
||||
|
||||
export function pngFilename(title: string): string {
|
||||
const slug = title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
return `${slug || "line"}.png`;
|
||||
}
|
||||
Reference in new issue
Block a user