From 83296e10ccb664427a773bc59122efe4e0c23adb Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Sat, 27 Jun 2026 18:16:12 -0400 Subject: [PATCH 1/6] update render-musicxml skill --- .agents/skills/render-musicxml/SKILL.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.agents/skills/render-musicxml/SKILL.md b/.agents/skills/render-musicxml/SKILL.md index 834a3c2f1..89d2a6776 100644 --- a/.agents/skills/render-musicxml/SKILL.md +++ b/.agents/skills/render-musicxml/SKILL.md @@ -1,6 +1,6 @@ --- name: render-musicxml -description: Render a MusicXML file in vexml by running `vex render -i `, inspect the generated screenshot when needed, and delete ephemeral render output when finished. +description: Render a MusicXML file in vexml by running `vex render -i `, optionally pass render configuration with `--config `, inspect the generated screenshot when needed, and delete ephemeral render output when finished. --- # Render MusicXML @@ -17,10 +17,18 @@ vex render -i Replace `` with the project-relative or absolute path to the MusicXML file the user wants rendered. +To override render settings, pass a partial render config as JSON with `-c`/`--config`: + +```sh +vex render -i --config '{"noteSpacing":40,"showPartLabels":true}' +``` + +The JSON object corresponds to `Partial` from `src/config.ts`; use that file as the source of truth for available options and defaults. + ## Workflow 1. Identify the MusicXML input path from the user's request or from the repository. -2. Run `vex render -i ` from `vexml`. +2. Run `vex render -i ` from `vexml`. If the user asks for non-default render settings, include `-c`/`--config ` using option names from `src/config.ts`. 3. Read the command output to find the generated screenshot path. 4. If visual inspection is needed, open or inspect the generated screenshot with available tools. 5. When finished, delete the generated screenshot if it was only meant to be ephemeral. From 381730b66e47de43e1db1566aa8913418a782eb9 Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Sat, 27 Jun 2026 19:24:28 -0400 Subject: [PATCH 2/6] add several technical engravings for directions, notations, and harmonies --- site/src/App.tsx | 44 +- src/config.ts | 5 + src/constants.ts | 26 +- src/draw.ts | 132 +++++- src/layout.ts | 3 +- src/notes.ts | 132 +++++- tests/integration/__data__/fermata.musicxml | 44 ++ tests/integration/__data__/harmony.musicxml | 183 ++++++++ .../__data__/measures_light_light.musicxml | 39 ++ .../__data__/notehead_parentheses.musicxml | 121 ++++++ .../integration/__data__/notehead_x.musicxml | 404 ++++++++++++++++++ tests/integration/__data__/words.musicxml | 100 +++++ .../__screenshots__/beam_variations.png | Bin 21283 -> 21052 bytes tests/integration/__screenshots__/fermata.png | Bin 0 -> 5952 bytes tests/integration/__screenshots__/harmony.png | Bin 0 -> 6946 bytes .../measure_numbering_every.png | Bin 11119 -> 11019 bytes .../measure_numbering_every_2.png | Bin 10160 -> 10060 bytes .../measure_numbering_every_3.png | Bin 9802 -> 9702 bytes .../measure_numbering_none.png | Bin 8993 -> 8893 bytes .../__screenshots__/measures_light_light.png | Bin 0 -> 4877 bytes .../__screenshots__/note_density.png | Bin 15968 -> 15768 bytes .../__screenshots__/notehead_parentheses.png | Bin 0 -> 9883 bytes .../__screenshots__/notehead_x.png | Bin 0 -> 11956 bytes .../__screenshots__/system_break.png | Bin 9262 -> 9162 bytes .../__screenshots__/tab_hammer_pull_wrap.png | Bin 13001 -> 12848 bytes tests/integration/__screenshots__/words.png | Bin 0 -> 8277 bytes tests/integration/render.test.ts | 63 +++ 27 files changed, 1282 insertions(+), 14 deletions(-) create mode 100644 tests/integration/__data__/fermata.musicxml create mode 100644 tests/integration/__data__/harmony.musicxml create mode 100644 tests/integration/__data__/measures_light_light.musicxml create mode 100644 tests/integration/__data__/notehead_parentheses.musicxml create mode 100644 tests/integration/__data__/notehead_x.musicxml create mode 100644 tests/integration/__data__/words.musicxml create mode 100644 tests/integration/__screenshots__/fermata.png create mode 100644 tests/integration/__screenshots__/harmony.png create mode 100644 tests/integration/__screenshots__/measures_light_light.png create mode 100644 tests/integration/__screenshots__/notehead_parentheses.png create mode 100644 tests/integration/__screenshots__/notehead_x.png create mode 100644 tests/integration/__screenshots__/words.png diff --git a/site/src/App.tsx b/site/src/App.tsx index c0bc3d5f3..6bfe06881 100644 --- a/site/src/App.tsx +++ b/site/src/App.tsx @@ -97,7 +97,8 @@ export default function App() { const [config, setConfig] = useState>({}); const noteSpacing = config.noteSpacing ?? 36; const softmaxFactor = config.softmaxFactor ?? 10; - const reset = (key: 'noteSpacing' | 'softmaxFactor') => + const systemSpacing = config.systemSpacing ?? 30; + const reset = (key: 'noteSpacing' | 'softmaxFactor' | 'systemSpacing') => setConfig(({ [key]: _, ...rest }) => rest); // `config` stays live so the sliders/reset respond instantly; `renderConfig` lags @@ -475,6 +476,47 @@ export default function App() { width difference between long and short notes.

+ +
+ + + setConfig((c) => ({ + ...c, + systemSpacing: e.target.valueAsNumber, + })) + } + /> +

+ Vertical gap between stacked systems. Lower packs systems + closer together down the page. +

+
diff --git a/src/config.ts b/src/config.ts index e7b06135d..8556fb9de 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,3 +1,4 @@ +import { SYSTEM_GAP } from './constants'; import type { FontConfig } from './fonts'; import type { Layout, MeasureNumbering } from './layout'; @@ -23,6 +24,9 @@ export type Config = { * Given the width noteSpacing allots, higher exaggerates the long-vs-short note ratio. A * shape constant, independent of overall density. */ softmaxFactor: number; + /** Vertical gap in px between stacked systems (default: SYSTEM_GAP). Smaller packs + * systems closer together down the page. */ + systemSpacing: number; /** Print each part's instrument name to the left of the first system (default: false). */ showPartLabels: boolean; /** When to print measure numbers above the staff (default: 'system'). 'none' prints @@ -52,6 +56,7 @@ export const DEFAULT_CONFIG: Config = { layout: { type: 'standard', width: 1000 }, noteSpacing: 36, softmaxFactor: 10, + systemSpacing: SYSTEM_GAP, showPartLabels: false, measureNumbering: 'system', showTabHammerPullText: false, diff --git a/src/constants.ts b/src/constants.ts index 98c6803f1..8d78995a5 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -18,8 +18,8 @@ export const PAGE_MARGIN_TOP_WITH_TEMPO = 70; export const PAGE_MARGIN_BOTTOM = 40; /** Vertical gap between stacked systems, plus room for the next system's notes that - * rise above its top staff. */ -export const SYSTEM_GAP = 90; + * rise above its top staff. The default for `Config.systemSpacing`. */ +export const SYSTEM_GAP = 30; /** Vertical gap between staves within one part (a brace-joined group reads as one * instrument because this exceeds INTER_PART_SPACING). */ @@ -95,6 +95,28 @@ export const TAB_TIE_CP2 = 12; * the system's left line with a small gap. */ export const BRACKET_X_SHIFT = 3; +/** Chord-symbol (from ``) text size — a touch smaller than the part label so it + * reads as an annotation above the notes. */ +export const HARMONY_FONT_SIZE = 13; + +/** How far a chord symbol's baseline sits above the top staff line. */ +export const HARMONY_Y_OFFSET = 14; + +/** Clearance kept between a chord symbol's baseline and the top of a high note it + * sits over, so the symbol lifts clear instead of colliding with the notehead. */ +export const HARMONY_NOTE_CLEARANCE = 8; + +/** Words-direction (e.g. "ritardando") text size — matches the chord-symbol size so + * both read as annotations above the notes. */ +export const WORDS_FONT_SIZE = 13; + +/** How far a words-direction baseline sits above the top staff line. */ +export const WORDS_Y_OFFSET = 14; + +/** Clearance kept between a words-direction baseline and the top of a high note it sits + * over, so the directive lifts clear instead of colliding with the notehead. */ +export const WORDS_NOTE_CLEARANCE = 8; + /** Clearance between the bottom of a metronome mark and the top of the first note. */ export const TEMPO_NOTE_CLEARANCE = 6; diff --git a/src/draw.ts b/src/draw.ts index d8675e2b2..7ae559998 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -23,6 +23,9 @@ import { import type { Config } from './config'; import { BRACKET_X_SHIFT, + HARMONY_FONT_SIZE, + HARMONY_NOTE_CLEARANCE, + HARMONY_Y_OFFSET, LABEL_FONT_SIZE, LABEL_GAP, LEDGER_HEADROOM, @@ -30,11 +33,15 @@ import { PAGE_MARGIN_TOP, TEMPO_NOTE_CLEARANCE, TEMPO_SCALE, + WORDS_FONT_SIZE, + WORDS_NOTE_CLEARANCE, + WORDS_Y_OFFSET, } from './constants'; import type { MeasureNumbering, ScoreLayout } from './layout'; import { endBeatOf, getNoteheadHalfWidth, + harmoniesOf, meterBeats, staffVoices, type TempoMark, @@ -42,6 +49,7 @@ import { vexflowClef, vexflowTabTickables, vexflowVoiceTickables, + wordsOf, } from './notes'; import { buildBeams, @@ -330,6 +338,62 @@ function drawTempo( context.restore(); } +// Draw a chord symbol (from a ) above its note's stave, left-anchored at +// the note's x — the laid-out position of the note the harmony applies to. Returns +// the y the text reaches up to so the caller can grow the page crop to keep a margin +// above it (drawTempo relies on reserved layout headroom instead; harmony feeds the +// crop directly so no extra top margin is needed). Drawn after the notes are +// formatted so getAbsoluteX is real. +function drawHarmony( + context: RenderContext, + staveNote: StaveNote, + text: string, + font: string, +): number { + const stave = staveNote.getStave(); + if (!stave) { + return Infinity; + } + // Sit a fixed gap above the top staff line, but lift higher when the note rises into + // that band (a high note or its ledger lines) so the symbol clears the notehead. + const baseY = stave.getYForLine(0) - HARMONY_Y_OFFSET; + const noteClearY = staveNote.getBoundingBox().getY() - HARMONY_NOTE_CLEARANCE; + const y = Math.min(baseY, noteClearY); + context.save(); + context.setFont(font, HARMONY_FONT_SIZE); + context.setFillStyle('#000000'); + context.fillText(text, staveNote.getAbsoluteX(), y); + context.restore(); + return y - HARMONY_FONT_SIZE; +} + +// Draw a words direction (e.g. "ritardando") above the stave in italics, left-anchored at +// the first note's x — where the directive applies. Sits a fixed gap above the top staff +// line, but lifts higher when the first note rises into that band (a high note or its ledger +// lines) so the text clears the notehead. Returns the y the text reaches up to so the caller +// can grow the page crop above it (like drawHarmony). Drawn after the notes are formatted so +// getAbsoluteX/getBoundingBox are real. +function drawWords( + context: RenderContext, + stave: Stave, + text: string, + firstNote: StaveNote | undefined, + font: string, +): number { + const baseY = stave.getYForLine(0) - WORDS_Y_OFFSET; + const noteClearY = firstNote + ? firstNote.getBoundingBox().getY() - WORDS_NOTE_CLEARANCE + : baseY; + const y = Math.min(baseY, noteClearY); + const x = firstNote ? firstNote.getAbsoluteX() : stave.getNoteStartX(); + context.save(); + context.setFont(font, WORDS_FONT_SIZE, 'normal', 'italic'); + context.setFillStyle('#000000'); + context.fillText(text, x, y); + context.restore(); + return y - WORDS_FONT_SIZE; +} + // Build a tablature staff's notes into vexflow voices of TabNotes (fret numbers on // their strings). Tab notes carry no clef/key, no ghost-note gap filling, and no // beams — the roadmap cases are single-voice fretted lines — so this is a slimmer @@ -550,6 +614,13 @@ export function drawScore( const { x: measureX, width: measureWidth, systemIndex } = box; const { isSystemStart } = box; const isLastMeasure = m === measureCount - 1; + // An explicit right with light-light draws a thin + // double line at this measure's end instead of the default single divider (or, on + // the final measure, the thin-thick end). Read from the first part — a light-light + // boundary applies across the system. + const isLightLight = + parts[0]?.measures[m]?.barlines.find((b) => b.location === 'right') + ?.barStyle === 'light-light'; const showMeasureNumber = showsMeasureNumber( measureNumbering, m, @@ -579,6 +650,16 @@ export function drawScore( tempo: TempoMark; firstNote: StaveNote | undefined; }> = []; + // Chord symbols, drawn after the system is formatted so each sits at its + // note's laid-out x. + const harmonyTasks: Array<{ staveNote: StaveNote; text: string }> = []; + // Words directions (e.g. "ritardando"), each drawn above its part's top stave at + // the first note's laid-out x. + const wordsTasks: Array<{ + stave: Stave; + text: string; + firstNote: StaveNote | undefined; + }> = []; for (const part of parts) { const staveCount = Math.max(part.staveCount, 1); @@ -623,9 +704,11 @@ export function drawScore( stave.setEndBarType( totalStaves > 1 ? Barline.type.NONE - : isLastMeasure - ? Barline.type.END - : Barline.type.SINGLE, + : isLightLight + ? Barline.type.DOUBLE + : isLastMeasure + ? Barline.type.END + : Barline.type.SINGLE, ); // The previous measure's effective signatures (carried forward), used to @@ -742,6 +825,16 @@ export function drawScore( // across parts, not just within this part. systemPending.push(...pendingStaves); + // Chord symbols from this measure's elements, each bound to the + // lead note it sits above. Resolved via byLead (the notation staff's notes); + // a harmony over a tab-only note isn't drawn. + for (const { lead, text } of harmoniesOf(measure)) { + const staveNote = byLead.get(lead); + if (staveNote) { + harmonyTasks.push({ staveNote, text }); + } + } + // A metronome mark (from a ) prints on this part's top // staff wherever it appears — the piece start or a mid-piece tempo change. // Drawn after the system is formatted so it can clear a high first note. @@ -755,6 +848,19 @@ export function drawScore( }); } + // Words directions (e.g. "ritardando") print on this part's top staff, like + // the metronome mark. Drawn after the system is formatted so the first note's + // x is real. + if (topStave) { + for (const text of wordsOf(measure)) { + wordsTasks.push({ + stave: topStave.stave, + text, + firstNote: topStave.staveNotes[0], + }); + } + } + // A part's own staves are joined at each system start by the symbol named in // (brace by default; bracket for guitar notation+tab pairs). // 'none' suppresses the connector entirely. @@ -809,6 +915,18 @@ export function drawScore( for (const t of tempoTasks) { drawTempo(context, t.stave, t.tempo, t.firstNote); } + for (const h of harmonyTasks) { + pageTop = Math.min( + pageTop, + drawHarmony(context, h.staveNote, h.text, labelFont), + ); + } + for (const w of wordsTasks) { + pageTop = Math.min( + pageTop, + drawWords(context, w.stave, w.text, w.firstNote, labelFont), + ); + } // Join the whole system across all parts with a shared left line at the // system start, and a closing line at the system end. @@ -838,7 +956,13 @@ export function drawScore( // The piece's final measure gets a bold thin-thick connector to match its // end barline; all other measure ends get a plain single line. new StaveConnector(systemTop, systemBottom) - .setType(isLastMeasure ? 'boldDoubleRight' : 'singleRight') + .setType( + isLightLight + ? 'thinDouble' + : isLastMeasure + ? 'boldDoubleRight' + : 'singleRight', + ) .setContext(context) .draw(); } diff --git a/src/layout.ts b/src/layout.ts index c2908f3af..4546c3a3d 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -19,7 +19,6 @@ import { PAGE_MARGIN_X, QUARTER_NOTE_TICKS, REFERENCE_WIDTH, - SYSTEM_GAP, TAB_MIN_NOTE_SPACING, } from './constants'; import { @@ -358,7 +357,7 @@ export function computeLayout(parts: Part[], config: Config): ScoreLayout { boxes, staveOffsets, top: y, - systemGap: SYSTEM_GAP, + systemGap: config.systemSpacing, width: naturalWidth, floorHeight, softmaxFactor, diff --git a/src/notes.ts b/src/notes.ts index 6b1254e9d..cca9358b7 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -1,10 +1,10 @@ import type { Chord, Measure, - Note, Voice as ScoreVoice, Time, } from '@stringsync/mdom'; +import { MElement, Note } from '@stringsync/mdom'; import { Accidental, Annotation, @@ -17,6 +17,7 @@ import { GraceNoteGroup, GraceTabNote, Modifier, + Parenthesis, StaveNote, Stem, type StemmableNote, @@ -89,16 +90,35 @@ function isHarmonic(note: Note): boolean { return !!note.child('notations')?.child('technical')?.child('harmonic'); } +// A x: an X-shaped notehead (a dead/muted note), drawn as a cross on a +// notation stave (see vexflowKey) and as an "X" in place of the fret on tab (see tabPositions). +function isXNotehead(note: Note): boolean { + return note.child('notehead')?.text === 'x'; +} + +// A : a ghost/optional note, drawn with round brackets around the +// notehead on a notation stave (see addParentheses) and the fret wrapped in "()" on tab (see +// tabPositions). +function isParenthesized(note: Note): boolean { + return note.child('notehead')?.getAttribute('parentheses') === 'yes'; +} + // A note's vexflow key, e.g. C#5 -> 'c/5'. A harmonic appends the '/H' notehead code so -// vexflow draws a diamond (open for half+/whole, filled for quarter). Rests have no pitch; -// callers handle them. +// vexflow draws a diamond (open for half+/whole, filled for quarter); an X notehead appends +// '/X2' for a cross. Rests have no pitch; callers handle them. function vexflowKey(note: Note): string { const pitch = note.pitch; if (!pitch) { return 'b/4'; } const key = `${pitch.step.toLowerCase()}/${pitch.octave}`; - return isHarmonic(note) ? `${key}/H` : key; + if (isHarmonic(note)) { + return `${key}/H`; + } + if (isXNotehead(note)) { + return `${key}/X2`; + } + return key; } // Augmentation dots. @@ -134,6 +154,24 @@ function addArticulations(staveNote: StaveNote, note: Note): void { } } +// A : the held-note arc-over-dot. Default placement is above +// (vexflow "a@a"); type="inverted" mirrors it below ("a@u"). Unlike articulations, +// the side is the fermata's type, not the stem direction. +function addFermata(staveNote: StaveNote, note: Note): void { + const fermata = note.child('notations')?.child('fermata'); + if (!fermata) { + return; + } + const inverted = fermata.getAttribute('type') === 'inverted'; + const articulation = new Articulation(inverted ? 'a@u' : 'a@a'); + // Vexflow defaults every Articulation to ABOVE; the below-shaped glyph also needs the + // BELOW position so it sits under the note instead of floating over it. + articulation.setPosition( + inverted ? Modifier.Position.BELOW : Modifier.Position.ABOVE, + ); + staveNote.addModifier(articulation); +} + // Honor an explicit up|down (e.g. to separate two voices on one stave). // Absent, auto-pick from staff position (see vexflowChord's auto_stem). function applyStem(staveNote: StaveNote, note: Note): void { @@ -157,6 +195,17 @@ function addAccidentals(staveNote: StaveNote, chord: Chord): void { }); } +// Wrap each parenthesized chord member's notehead in round brackets. Per-member (like +// accidentals) rather than Parenthesis.buildAndAttach, which brackets every notehead. +function addParentheses(staveNote: StaveNote, chord: Chord): void { + chord.notes.forEach((note, i) => { + if (isParenthesized(note)) { + staveNote.addModifier(new Parenthesis(Modifier.Position.LEFT), i); + staveNote.addModifier(new Parenthesis(Modifier.Position.RIGHT), i); + } + }); +} + // Build a vexflow StaveNote for one chord (a lead note plus any members; // a single note is a one-member chord). Rests render as a centered rest glyph; // grace notes (no ) become small GraceNotes — slashed for an @@ -206,9 +255,11 @@ export function vexflowChord( autoStem: !lead.stem, }); addAccidentals(staveNote, chord); + addParentheses(staveNote, chord); addDots(staveNote, lead); applyStem(staveNote, lead); addArticulations(staveNote, lead); + addFermata(staveNote, lead); return staveNote; } @@ -277,9 +328,23 @@ function addTabModifiers(tabNote: TabNote, lead: Note): void { function tabPositions(chord: Chord) { const toPosition = (note: Chord['notes'][number]) => { const fret = note.fret ?? 0; + // A dead note (x) prints "X" on its string instead of a fret; + // a harmonic angle-brackets its fret. vexflow renders the fret string verbatim. + let fretText: string | number = fret; + if (isXNotehead(note)) { + // A dingbat "✕" (U+2715), not an ASCII "X": the notation font (Bravura) draws an + // ornate glyph for "X" and would win the CSS font fallthrough, but it lacks this + // dingbat, so the fret falls through to the plain text font like the fret digits do. + fretText = '✕'; + } else if (isHarmonic(note)) { + fretText = `<${fret}>`; + } else if (isParenthesized(note)) { + // A ghost/optional fret reads as "(2)". vexflow renders the fret string verbatim. + fretText = `(${fret})`; + } return { str: note.string ?? 1, - fret: isHarmonic(note) ? `<${fret}>` : fret, + fret: fretText, }; }; const struck = chord.notes.filter((note) => !isTieStop(note)); @@ -529,6 +594,63 @@ export function tempoOf(measure: Measure): TempoMark | null { return null; } +// A measure's text directives (e.g. "ritardando", +// "dolce"), in document order. These are free-text expressions printed above the stave. +// ponytail: placement and font-style attributes ignored — every words direction prints +// above the staff in italics; add a placement/style field if a fixture needs below or +// upright words. +export function wordsOf(measure: Measure): string[] { + const out: string[] = []; + for (const direction of measure.directions) { + const words = direction.child('direction-type')?.child('words')?.text; + if (words) { + out.push(words); + } + } + return out; +} + +// MusicXML / semitones -> the printed accidental sign. ASCII +// '#'/'b' (not the Unicode ♯/♭), which the text font has glyphs for — the music-symbol +// codepoints fall back to a system font with loose side-bearings that space the symbol out. +// ponytail: real ♯/♭ engraving would need the notation font's accidental glyph drawn as a +// separate block (vexflow's ChordSymbol); add it if a fixture wants typeset accidentals. +const HARMONY_ALTER: Record = { '1': '#', '-1': 'b' }; + +// A 's printed chord symbol, e.g. "G7", "C", "F♯m": the plus +// any sign, then the suffix MusicXML carries for +// exactly this (a major triad's text is empty, so it prints the bare root). +// ponytail: a without a text attribute prints just the root — no +// kind-name->suffix table (major-seventh -> "maj7", …); add one if a fixture needs it. +function harmonyText(harmony: MElement): string { + const root = harmony.child('root'); + const step = root?.child('root-step')?.text ?? ''; + const alter = root?.child('root-alter')?.text ?? ''; + const kind = harmony.child('kind')?.getAttribute('text') ?? ''; + return step + (HARMONY_ALTER[alter] ?? '') + kind; +} + +// Each in a measure paired with the lead note it sits above. +// elements are interleaved with s in document order and apply to the note +// that follows, so walk the measure's children tracking the pending harmony and +// bind it to the next chord lead (the next non- note). +export function harmoniesOf(measure: Measure): { lead: Note; text: string }[] { + const harmonies: { lead: Note; text: string }[] = []; + let pending: MElement | null = null; + for (const child of measure.children) { + if (child instanceof MElement && child.tag === 'harmony') { + pending = child; + } else if (pending && child instanceof Note && !child.isChordMember) { + const text = harmonyText(pending); + if (text) { + harmonies.push({ lead: child, text }); + } + pending = null; + } + } + return harmonies; +} + // The beat a measure's voices run out to: the latest onset+duration across them. // Voices that end before this (e.g. one silent on the final beat via ) // are padded out to it so every voice spans the same range — see the trailing diff --git a/tests/integration/__data__/fermata.musicxml b/tests/integration/__data__/fermata.musicxml new file mode 100644 index 000000000..1a7a13643 --- /dev/null +++ b/tests/integration/__data__/fermata.musicxml @@ -0,0 +1,44 @@ + + + + + Music + + + + + + + 8 + + 1 + + G + 2 + + + + C5 + 32 + whole + + normal + + + + + + + C5 + 32 + whole + + normal + + + + + diff --git a/tests/integration/__data__/harmony.musicxml b/tests/integration/__data__/harmony.musicxml new file mode 100644 index 000000000..2ba9f121c --- /dev/null +++ b/tests/integration/__data__/harmony.musicxml @@ -0,0 +1,183 @@ + + + + + Music + + + + + + 1 + + 1 + + G + 2 + + + + + C + + major + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + + + G + + dominant + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + + + F + 1 + + minor + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + + + D + + major + + + + C + 6 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + diff --git a/tests/integration/__data__/measures_light_light.musicxml b/tests/integration/__data__/measures_light_light.musicxml new file mode 100644 index 000000000..52005542e --- /dev/null +++ b/tests/integration/__data__/measures_light_light.musicxml @@ -0,0 +1,39 @@ + + + + + Music + + + + + + 1 + + 1 + + G + 2 + + + + C5 + 4 + whole + + + light-light + + + + + C5 + 4 + whole + + + + diff --git a/tests/integration/__data__/notehead_parentheses.musicxml b/tests/integration/__data__/notehead_parentheses.musicxml new file mode 100644 index 000000000..93632a881 --- /dev/null +++ b/tests/integration/__data__/notehead_parentheses.musicxml @@ -0,0 +1,121 @@ + + + + + Guitar + + + Guitar + + + + + + + 2 + 1 + + G + 2 + + + + B4 + 2 + 1 + quarter + normal + + + B4 + 2 + 1 + quarter + + + G4 + 4 + 1 + half + normal + + + + B4 + 4 + 1 + half + normal + + + + D5 + 4 + 1 + half + normal + + + + + + + 2 + 1 + + TAB + 5 + + + 6 + + + + B4 + 2 + 1 + quarter + normal + 12 + + + B4 + 2 + 1 + quarter + 15 + + + G4 + 4 + 1 + half + normal + 30 + + + + B4 + 4 + 1 + half + normal + 20 + + + + D5 + 4 + 1 + half + normal + 12 + + + + diff --git a/tests/integration/__data__/notehead_x.musicxml b/tests/integration/__data__/notehead_x.musicxml new file mode 100644 index 000000000..ef18dc21a --- /dev/null +++ b/tests/integration/__data__/notehead_x.musicxml @@ -0,0 +1,404 @@ + + + + + Guitar + + + Guitar + + + + + + + 2 + 1 + + G + 2 + + + + B4 + 2 + 1 + quarter + x + + + B4 + 2 + 1 + quarter + x + + + B4 + 2 + 1 + quarter + x + + + B4 + 2 + 1 + quarter + x + + + + + B4 + 1 + 1 + eighth + x + begin + + + B4 + 1 + 1 + eighth + x + continue + + + B4 + 1 + 1 + eighth + x + continue + + + B4 + 1 + 1 + eighth + x + end + + + B4 + 1 + 1 + eighth + x + begin + + + B4 + 1 + 1 + eighth + x + continue + + + B4 + 1 + 1 + eighth + x + continue + + + B4 + 1 + 1 + eighth + x + end + + + + + G4 + 8 + 1 + whole + x + + + + B4 + 8 + 1 + whole + x + + + + D5 + 8 + 1 + whole + x + + + + + G4 + 1 + 1 + eighth + begin + + + A3 + 1 + 1 + eighth + x + continue + + + + D4 + 1 + 1 + eighth + x + + + G4 + 1 + 1 + eighth + continue + + + A3 + 1 + 1 + eighth + x + end + + + + D4 + 1 + 1 + eighth + x + + + G4 + 4 + 1 + half + + + + + + + 2 + 1 + + TAB + 5 + + + 6 + + + + B4 + 2 + 1 + quarter + x + 60 + + + B4 + 2 + 1 + quarter + x + 40 + + + B4 + 2 + 1 + quarter + x + 20 + + + B4 + 2 + 1 + quarter + x + 10 + + + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + B4 + 1 + 1 + eighth + x + 10 + + + + + G3 + 8 + 1 + whole + x + 30 + + + + B3 + 8 + 1 + whole + x + 20 + + + + E4 + 8 + 1 + whole + x + 10 + + + + + G4 + 1 + 1 + eighth + 30 + + + A3 + 1 + 1 + eighth + x + 20 + + + + D4 + 1 + 1 + eighth + x + 10 + + + G4 + 1 + 1 + eighth + 30 + + + A3 + 1 + 1 + eighth + x + 20 + + + + D4 + 1 + 1 + eighth + x + 10 + + + G4 + 4 + 1 + half + 30 + + + + diff --git a/tests/integration/__data__/words.musicxml b/tests/integration/__data__/words.musicxml new file mode 100644 index 000000000..e046fbaf5 --- /dev/null +++ b/tests/integration/__data__/words.musicxml @@ -0,0 +1,100 @@ + + + + + Music + + + + + + 1 + + 1 + + G + 2 + + + + + *ritardando... + + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + + + *ritardando... + + + + + C + 6 + + 1 + quarter + + + + C + 6 + + 1 + quarter + + + + C + 6 + + 1 + quarter + + + + C + 6 + + 1 + quarter + + + + diff --git a/tests/integration/__screenshots__/beam_variations.png b/tests/integration/__screenshots__/beam_variations.png index c7bd2a3c5818d90dae082484432b2b5c8bf375bb..7273a53a51097acba36974b63fc926724965af5f 100644 GIT binary patch literal 21052 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 literal 21283 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 OqNT2<_W8P9$bSLHubPnn literal 0 HcmV?d00001 diff --git a/tests/integration/__screenshots__/harmony.png b/tests/integration/__screenshots__/harmony.png new file mode 100644 index 0000000000000000000000000000000000000000..98871193a553a81c94a97abed504abf19f8a14d8 GIT binary patch literal 6946 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 KweYf4(0>8GOvO?F literal 0 HcmV?d00001 diff --git a/tests/integration/__screenshots__/measure_numbering_every.png b/tests/integration/__screenshots__/measure_numbering_every.png index 0fb45268c5a0d1e5b317b2591daa5bbac9d415ca..f42e74588ff5578bedea999b0c09854805d1cba0 100644 GIT binary patch delta 83 zcmaDK)*UuMoNFHk69WUo#DIlO8xFVdQ&MBb@08mdKI;Vst04|3d+yDRo diff --git a/tests/integration/__screenshots__/measure_numbering_every_2.png b/tests/integration/__screenshots__/measure_numbering_every_2.png index 4a2aff694749dd3b22a990f97cff0ee12842fd47..cd5051c321d803d11b1d18b1eb267bb1127f3659 100644 GIT binary patch delta 83 zcmdnsf5vZuIM+T7CI$wEi2)0nHY%PG+Z-tVgk!R!LJAMlxy9lP3~VnwT^vI;FI9NS lrZh!m@<*UjHjoH219#sC-UmnBp8`b~JYD@<);T3K0RWw48=3$B delta 87 zcmX@(x50mcIM*c(CI$wEcWHTxH!7YHn=HVXviYsp6AqqJi>|C=U|{$4ba4!sd{I7S pv!lXGHYJ7Ki&cTj*+8Pq4BOg1m};J}XaR~ac)I$ztaD0e0sv(B9k>7h diff --git a/tests/integration/__screenshots__/measure_numbering_every_3.png b/tests/integration/__screenshots__/measure_numbering_every_3.png index 939a63f9ae8227b8777f23a6261314434d48536a..a5d2048708ce0ff1fade146d78baa571fe2ad8f1 100644 GIT binary patch delta 83 zcmX@*^UQmKIM+T7CI$wEi2)0nHYyg0ZvHN6$2HkeA%*9HrL{N%18cLVi(|;kCxQ1`=gvxb{&k_hTCuFHnTR)78&qol`;+052IF(f|Me diff --git a/tests/integration/__screenshots__/measure_numbering_none.png b/tests/integration/__screenshots__/measure_numbering_none.png index ce65b773c75612f28e920751ec24ce8ac68d445d..a603d8ff2153888c950bb6449e1fac95806553ef 100644 GIT binary patch delta 83 zcmZ4Jw%2unIM+T7CI$wEi2)0nHYyg2Z2lo)%RSjqA%%zIm74?u15=czi(|;FVdQ&MBb@04)(2O#lD@ delta 83 zcmdn%y3lQcIM*c(CI$wEcWHTxH!2p3Y&H;C$j#%R|BZ!#foY$oi(|;-i}ER(9TlRO kls>o2z6Mmv1`=gvIBI<1n9}1OPM`>br>mdKI;Vst0C-Ir)c^nh diff --git a/tests/integration/__screenshots__/measures_light_light.png b/tests/integration/__screenshots__/measures_light_light.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5cd8cae180d876089ba9286be34c1c1c0010a2 GIT binary patch literal 4877 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 literal 0 HcmV?d00001 diff --git a/tests/integration/__screenshots__/note_density.png b/tests/integration/__screenshots__/note_density.png index cc30e71982f1d698d6eda33e0d85a825df8e745b..bc21d93e9cca9d01033ab66605fa75e1c2e8c848 100644 GIT binary patch delta 109 zcmaD*GoyNfI9D4769WT-$3(mP8x=Q*FE*9nnCz&K!n0^W@CF730R~SO$B@lS6}Itg z-mlxlG}+hS1dru!69WbYUQMu+sG%mWlJwheN^WZDc%48 diff --git a/tests/integration/__screenshots__/notehead_parentheses.png b/tests/integration/__screenshots__/notehead_parentheses.png new file mode 100644 index 0000000000000000000000000000000000000000..a17d15479b3a25e8b1a6047f6bd17898df86c206 GIT binary patch literal 9883 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 literal 0 HcmV?d00001 diff --git a/tests/integration/__screenshots__/notehead_x.png b/tests/integration/__screenshots__/notehead_x.png new file mode 100644 index 0000000000000000000000000000000000000000..45ba4b66e5ea2a6574aa15508141ab8cf23bffb6 GIT binary patch literal 11956 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 delta 86 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 Ay8r+H literal 13001 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 diff --git a/tests/integration/__screenshots__/words.png b/tests/integration/__screenshots__/words.png new file mode 100644 index 0000000000000000000000000000000000000000..dafb287de2c6d235a8d6e659a64454c3f9bf8008 GIT binary patch literal 8277 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 literal 0 HcmV?d00001 diff --git a/tests/integration/render.test.ts b/tests/integration/render.test.ts index 098089e61..6bef48049 100644 --- a/tests/integration/render.test.ts +++ b/tests/integration/render.test.ts @@ -150,6 +150,15 @@ const TEST_CASES = [ // up into the mark's default band, so the mark is lifted clear of the notehead. testCase('tempo.musicxml', 'tempo.png'), + // Treble stave, 4/4: a words direction from , drawn + // in italics above the staff at the first note's x. Four boring quarters per measure so + // only the directive and the first note's height vary. + // - M1: "*ritardando..." over B4 quarters (mid-staff, no collision) — the text sits one + // fixed gap above the staff. + // - M2: "*ritardando..." over a high first note (C6, two ledger lines above) that reaches + // up into the text's default band, so the text is lifted clear of the notehead. + testCase('words.musicxml', 'words.png'), + // Treble stave, 4/4: two measures split by a barline, each holding one whole note // (C5, same pitch in both). testCase('measures_two.musicxml', 'measures_two.png'), @@ -164,6 +173,12 @@ const TEST_CASES = [ // other measure end. testCase('measures_end_barline.musicxml', 'measures_end_barline.png'), + // Treble stave, 4/4, two whole-note measures (C5 in both). M1 carries an explicit + // right with light-light, so the divider between M1 + // and M2 renders as a thin double line instead of the default single line; M2 closes + // with the usual thin-thick end barline. + testCase('measures_light_light.musicxml', 'measures_light_light.png'), + // Beam variations across seven 4/4 measures. Wraps across systems. // - M1: simple beamed eighths in a small range. // - M2: beamed eighths leaping a wide range (steep beams, ledger lines above on @@ -368,6 +383,35 @@ const TEST_CASES = [ // (strings 3/2/1, single-digit "<5>"). Watch the stacked brackets for vertical clashing. testCase('tab_harmonic.musicxml', 'tab_harmonic.png'), + // Notation stave over a 6-line TAB stave: X noteheads (x) for + // dead/muted notes. The notation stave draws a cross at each pitch (vexflow "/X2"); the tab + // stave prints "✕" in place of the fret on the matching string (src/notes.ts). No + +
+ + +

+ The engraving font for noteheads, clefs, accidentals, and + rests. Bravura is the default. +

+
diff --git a/src/draw.ts b/src/draw.ts index 7ae559998..e885c3723 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -295,7 +295,8 @@ function formatAndDrawPart( // one text line above the staff; if the first note reaches up into that band (a high // note with ledger lines), lift the mark with a negative y-shift so its bottom clears // the notehead — the layout reserves the matching top headroom. Drawn after the notes -// are formatted so firstNote's bounding box is real. +// are formatted so firstNote's extents are real. Uses noteTop, not the bounding box: an +// attached grace-note group makes the box report a bogus near-origin y. function drawTempo( context: RenderContext, stave: Stave, @@ -305,7 +306,7 @@ function drawTempo( const baseY = stave.getYForTopText(1); let shiftY = 0; if (firstNote) { - const clearY = firstNote.getBoundingBox().getY() - TEMPO_NOTE_CLEARANCE; + const clearY = noteTop(firstNote) - TEMPO_NOTE_CLEARANCE; if (clearY < baseY) { shiftY = clearY - baseY; } @@ -338,6 +339,11 @@ function drawTempo( context.restore(); } +// Accidental glyphs in a chord symbol; pulled tight against their root letter. +const HARMONY_ACCIDENTALS = new Set(['♯', '♭', '♮']); +const HARMONY_ACCIDENTAL_KERN = 2.5; +const HARMONY_ACCIDENTAL_FONT_SIZE = HARMONY_FONT_SIZE - 3; + // Draw a chord symbol (from a ) above its note's stave, left-anchored at // the note's x — the laid-out position of the note the harmony applies to. Returns // the y the text reaches up to so the caller can grow the page crop to keep a margin @@ -355,14 +361,33 @@ function drawHarmony( return Infinity; } // Sit a fixed gap above the top staff line, but lift higher when the note rises into - // that band (a high note or its ledger lines) so the symbol clears the notehead. + // that band (a high note or its ledger lines) so the symbol clears the notehead. Uses + // noteTop, not the bounding box: an attached grace-note group makes the box report a + // bogus near-origin y, which would fling the symbol to the top of the page and defeat + // the top crop (leaving a huge blank margin above the first system). const baseY = stave.getYForLine(0) - HARMONY_Y_OFFSET; - const noteClearY = staveNote.getBoundingBox().getY() - HARMONY_NOTE_CLEARANCE; + const noteClearY = noteTop(staveNote) - HARMONY_NOTE_CLEARANCE; const y = Math.min(baseY, noteClearY); context.save(); context.setFont(font, HARMONY_FONT_SIZE); context.setFillStyle('#000000'); - context.fillText(text, staveNote.getAbsoluteX(), y); + // The ♯/♭/♮ glyphs carry wide side-bearings in the text font, so a single fillText + // of "B♭" reads as "B ♭". Draw char by char and pull the accidental in on both sides + // so it sits tight against its root letter. + let x = staveNote.getAbsoluteX(); + for (const ch of text) { + const accidental = HARMONY_ACCIDENTALS.has(ch); + if (accidental) { + x -= HARMONY_ACCIDENTAL_KERN; + context.setFont(font, HARMONY_ACCIDENTAL_FONT_SIZE); + } + context.fillText(ch, x, y); + x += context.measureText(ch).width; + if (accidental) { + x -= HARMONY_ACCIDENTAL_KERN; + context.setFont(font, HARMONY_FONT_SIZE); + } + } context.restore(); return y - HARMONY_FONT_SIZE; } @@ -372,7 +397,8 @@ function drawHarmony( // line, but lifts higher when the first note rises into that band (a high note or its ledger // lines) so the text clears the notehead. Returns the y the text reaches up to so the caller // can grow the page crop above it (like drawHarmony). Drawn after the notes are formatted so -// getAbsoluteX/getBoundingBox are real. +// getAbsoluteX is real. Uses noteTop, not the bounding box, to clear the note: an attached +// grace-note group makes the box report a bogus near-origin y. function drawWords( context: RenderContext, stave: Stave, @@ -382,7 +408,7 @@ function drawWords( ): number { const baseY = stave.getYForLine(0) - WORDS_Y_OFFSET; const noteClearY = firstNote - ? firstNote.getBoundingBox().getY() - WORDS_NOTE_CLEARANCE + ? noteTop(firstNote) - WORDS_NOTE_CLEARANCE : baseY; const y = Math.min(baseY, noteClearY); const x = firstNote ? firstNote.getAbsoluteX() : stave.getNoteStartX(); diff --git a/src/notes.ts b/src/notes.ts index cca9358b7..1992cf21a 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -610,12 +610,11 @@ export function wordsOf(measure: Measure): string[] { return out; } -// MusicXML / semitones -> the printed accidental sign. ASCII -// '#'/'b' (not the Unicode ♯/♭), which the text font has glyphs for — the music-symbol -// codepoints fall back to a system font with loose side-bearings that space the symbol out. -// ponytail: real ♯/♭ engraving would need the notation font's accidental glyph drawn as a -// separate block (vexflow's ChordSymbol); add it if a fixture wants typeset accidentals. -const HARMONY_ALTER: Record = { '1': '#', '-1': 'b' }; +// MusicXML / semitones -> the printed accidental sign, using the +// real Unicode music symbols (♯ ♭ ♮). 0 prints an explicit natural — rare in a root, but +// MusicXML carries it when the chart wants the sign drawn. An absent maps to +// nothing (no sign), so plain roots stay bare. +const HARMONY_ALTER: Record = { '1': '♯', '-1': '♭', '0': '♮' }; // A 's printed chord symbol, e.g. "G7", "C", "F♯m": the plus // any sign, then the suffix MusicXML carries for diff --git a/tests/integration/__data__/harmony.musicxml b/tests/integration/__data__/harmony.musicxml index 2ba9f121c..c506291c9 100644 --- a/tests/integration/__data__/harmony.musicxml +++ b/tests/integration/__data__/harmony.musicxml @@ -179,5 +179,87 @@ quarter

(q!^bE4IvLuL7Z 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 delta 87 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 Ay8r+H From 9b23bec8f6fdff69335b6585c538f7bde2fcf346 Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Sat, 27 Jun 2026 19:47:40 -0400 Subject: [PATCH 4/6] add a font selector to the config and improve harmony support --- site/src/App.tsx | 36 +++++++ src/draw.ts | 40 ++++++-- src/notes.ts | 11 +- tests/integration/__data__/harmony.musicxml | 82 +++++++++++++++ .../__data__/harmony_grace.musicxml | 70 +++++++++++++ tests/integration/__data__/tie_chain.musicxml | 94 ++++++++++++++++++ tests/integration/__screenshots__/harmony.png | Bin 6946 -> 11783 bytes .../__screenshots__/harmony_grace.png | Bin 0 -> 5487 bytes tests/integration/__screenshots__/tempo.png | Bin 6610 -> 6278 bytes .../integration/__screenshots__/tie_chain.png | Bin 0 -> 8910 bytes tests/integration/__screenshots__/words.png | Bin 8277 -> 8229 bytes tests/integration/render.test.ts | 22 +++- 12 files changed, 341 insertions(+), 14 deletions(-) create mode 100644 tests/integration/__data__/harmony_grace.musicxml create mode 100644 tests/integration/__data__/tie_chain.musicxml create mode 100644 tests/integration/__screenshots__/harmony_grace.png create mode 100644 tests/integration/__screenshots__/tie_chain.png diff --git a/site/src/App.tsx b/site/src/App.tsx index 6bfe06881..dc4e9932f 100644 --- a/site/src/App.tsx +++ b/site/src/App.tsx @@ -98,6 +98,7 @@ export default function App() { const noteSpacing = config.noteSpacing ?? 36; const softmaxFactor = config.softmaxFactor ?? 10; const systemSpacing = config.systemSpacing ?? 30; + const notationFont = config.fonts?.notation?.family ?? 'Bravura'; const reset = (key: 'noteSpacing' | 'softmaxFactor' | 'systemSpacing') => setConfig(({ [key]: _, ...rest }) => rest); @@ -517,6 +518,41 @@ export default function App() { closer together down the page.

+ + + + B + -1 + + major + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + + + B + 0 + + major + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + diff --git a/tests/integration/__data__/harmony_grace.musicxml b/tests/integration/__data__/harmony_grace.musicxml new file mode 100644 index 000000000..0651f123b --- /dev/null +++ b/tests/integration/__data__/harmony_grace.musicxml @@ -0,0 +1,70 @@ + + + + + Music + + + + + + 1 + + 1 + + G + 2 + + + + + C + + major + + + + + D + 5 + + eighth + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + B + 4 + + 1 + quarter + + + + diff --git a/tests/integration/__data__/tie_chain.musicxml b/tests/integration/__data__/tie_chain.musicxml new file mode 100644 index 000000000..5fc1e2d4e --- /dev/null +++ b/tests/integration/__data__/tie_chain.musicxml @@ -0,0 +1,94 @@ + + + + + Music + + + + + + + 96 + + 2 + major + + + 1 + + G + 2 + + + + E4 + 24 + 16th + begin + + + F14 + 72 + + eighth + + end + + + + F14 + 96 + + + quarter + + + + F14 + 96 + + quarter + + + + F14 + 24 + 16th + begin + + + + + + + G4 + 24 + 16th + continue + + + + + E4 + eighth + end + + + + + + + F14 + 48 + eighth + + + + + diff --git a/tests/integration/__screenshots__/harmony.png b/tests/integration/__screenshots__/harmony.png index 98871193a553a81c94a97abed504abf19f8a14d8..bd568c1f0d151dbf54d433e793a883a2116f3d36 100644 GIT binary patch literal 11783 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 W9&)G-Aa~#s(vd?t8tDftZv7WM69m8j literal 6946 zcmd^E`9G9>zn^ZQB#Nv};g$$lvt>&g$`Xp~k|j%)gt5(tlAV$*TgsA%>{%zm7(^nn zXP12}!&qj{XP)~!uh%(0oPXdvzsz=B*Z2BfpXI%LChV4u`cVdM1_T0eR8!-sJ_2#@ z5PaS{^cTE(RvyqpAdVq4ud3Zfr7n*6m3{LhtFFrZNy#*$J2(CMrdYgPEIvEwdbZ{V zzN~g@6I(~?wrraON3%yMk}?iIY{ReSOX_K`OiO8t<-Kyc5`N?Ay=LCoEeqo7I^s&I z6uqLo>**L(m4&*ojJhs=y9^`TEXfBmn&JH-H8mABfE;3=M<9MD339@hpaTd5FZF|( z1ofL0yc}$RmqXM8#}3lK(L;0y#HC}52t?q2&WVA0bKURMGbtCxpR#_qliychT&hYY z#MF2#F}U3pVnHBUGq|MfkeEG!A92wbelD?Xr(@)laGz-6u=Fq1N|riMk_y3$wRC^= z=0W#ceBwy8r&I6y?sy{$1^doagmLG`s|dvN_l6%$w#G1&;VKXKm5aCiFa-N~p?Qs$ zyCSUo@6!q|KV!HSe!>`w4hR&b<_(!J2`RorWQDXajR743bPRclLBx3in19piC$}@Afgaiczp-6DDM^d3o{_h%6YcMIc zzLud9AXYv1RzLejntKb^!=Z{((sq&bt@^*=;XV7!y~`bc&f_4we{wU>g8C9m_W=icuw_eq?FN4ZD4f5g(YZ8edZPF>7GJ5Dr(N%p~U=}Xnk*zmAtc5yoL z<4s_im?TcwbmP zE{`|!J}z2Py3DCx?2=k&ym6sf)p7poQ{1H=Oe(`DzaRP>g>mRoTJN~~D@D$gdb9gJxbBa;D_GSp4WW}XM^DOXY13*JmtBuW zLYZ?(3L$ohOMd&C{jj!q_2WOaevmevH@r=4sfyk%N)LrCYEh$gV{+UQ&=^T}9Oq3= z{BFGwRpgG4Ew6(*WQ81*cBw3kVJS}!v(Ep__g*URCoT7t?%Q)qz9Gyw?9@QKyc$gEjzPa#$h(T)Jfb>}EYPHBaqM0RU}RV)oG8d`iP`rYjZvcP ztv?(r(=;o3#?$Jp691t0y&gWd@+kKOp#h#DK*WGO0*(fGZluOLkwO0AXD@vTsKzQN zh3%rj<&heLT?%;%yR|&xH(2IyfZ=jM2Q<)3#gNNTjkjx|xzF?N{vu24y{{o={SU@l zx4*ff+{tfa?#11!UVsIYxR?x8 z47$=~WWMiXivKz=#YBbg=KKMM#)R{x_4~x3ra43Bm7&V665QS!ld=bdnH1OM!EzDu z2!NPH+*$1j%jOmT$dfjCk%#Db0ygw=b<*a0^E|Z7XQ2OXLX0zf=kw%w>rsRW%HFK% zY?`-4m^uWb`D_?$sbZ=ty&GK5nY%6@h3U5pr1Y@0~Y#=(mS zguD>faYjH$cBZe8xT5-zNut_YynEgpr@CZ42GNBUF8p{Wi)S6MiBRSWT+vQEv zO_s6+I_VRnM=%-Bx8Z_m$;ioH?6T|yCN zUxZZRvpxePvi)A~on!C&V(*pFFjhg}XI>t-_6?-)xxdIL)J%#qGmnZ=6)y>(#{#s# zvm+d%KwYqnZOf8f!?y#a_JZ6{wz@e%a~nOnu0OKy6U`AItzwx6lu4-3S|4{);I$Y0 z>NA6PAe0!&?ilqMo{KWk-AoYGynxIb{PDG0-b4vbJ);X?boUPYxpWJfj&hM;0eM+Gu(9*YvV4lz1A-N zm3)}a$9tdDg^3=j_FVYq$)=~Ko_5@Ne=C#9?@5dbd|hvj2M6z8-`QM{bNl_J_&&}H z2yB2v!12gA|5}X@uMb@st@C5%k~))x_nA$r1hnW)m%mE@9;z}8>o^hTHPeK?6>IbA zicstJ3-bQ1DJiK;!_X?noV{zpGz`7*j;Hw{X>B@AIYsti^Dx3uJ#5?ds){)1MCCik<@?xXemWcv#(#LmSO3;8)!FR?QS$!%b~$xCXZuT16;g(PXGClMzZFi zFfvpDRCKG(fTZ;?-JYV)6X9m|Q{4euBbEN7wZp7u3rxyCfCl6X5H>83hfSp^de4lo z?RqZ_#`_O|=FibiX}J#C2t1ojuIM4Up^AqQdA$8BcHK#m_X}&5s~dvpaaOD3-IeEM z!e*b{y3&=g9{r)m`SpVvo^e>9l@(gkblekxx^=S|9zWSk7;|9+&c5-sop6tCMVp-}|b8i%n<9c*C{f`HuwPAY-!^FzD7YuKK z$8bwSuGmx2p&%Qks^9(jPA4*v%Ps4iRQbD+Yqt6|){u;CdL;#{QCnjz zjM^IUzEU4`TG_WboQ)oJCExJlWwrM3V8;56vbMd+jRl<}w8>(y|B`H8=?qBB{aW6S z{@}G}@yOueM`R4uIE@Se>YBNtCc*@nlqC1k{g&~X8C0RPLjw33D!#AY*>HsZ0<>x> zqua1M&X%mEve|2pOtD3SfTDdA%hy%$MW2X3Ftk%=0T=@kNh1W447w4&%I^=#SeoLb zw0eh=HW~9jcEWEEi)UcuI_u#o;5!*5_i_ovKwkaIoV#2HN&?7dr(2!p)NesXr2J~C zN2hW1V+VO>VC;4o{AbXsplU=wSZm}1?~Val^UbFt{ zTvX%s3&g`ZD9S7%Blm^(kX_K4%3n5K1?vN~C0&rR|KJBfU-z;bR6}PJ$m>|n@X1d` zO0RkCc=8m0td?}m4N^Kted20f>F|GIFYW!LbSj?QqocU=+Nn^JSY%Q@52DhbwK87B zh`7-2`X%tdxP+)_h3MwAK%yDTS3HP;*K)3>abiHzY)twQ?B_@Q*S~>^yi;URXHn;? z{rbY6zK^DZI36Z-D6~pwDL{8EmDZ=6W0QgUAw2e=f$hJ&jwe~#g&56%XRHCFG2gXa zlN-psnMid~_nAv>=jnrT0ZUL7q@+dN@_SzC)c@YH9H;Z}XUXo*^B?l{T~h$^c8SX) zDLb9pMN+*0*g4KW( zhyXyDr(>(%1 zAK2;j#v|gOV&qM1mZv7CruyZ@5*CM{m)`1u@9b6FUFgkYC5qomTT~!4v8qRL$NN_S zp1Wy)B#*4c4DsKcSA799pp7BInLgEBk^vH0GHd~^H`(6b>!ApK|bA6 zoJiwPDlM78SN))A$745^hU8vcpVEQY07BQ$LV567&dFwol zWZI*TnDqByEAQUp<23S1WRKa|uGA7(5p{812D5x9CXFao%u9c!H4B|nB4K!M%2*W+v+{ws#|4F+zRtbFu83{_(pDXPS?9GkH5MP8=LpJj%xL-{c(0 zMAse5cV*^V$`*8x=i)DSn5p2&pjfHWgz86wXpgWchna>MLi0nXvk2U1A_g9yk#!m7 z#IXY-b290JA%eLQDXr#uBGuf?s7)r9R3mrkx<(xNrU(Nb6_C~aguOCuN!t>bvVvbj+ubxTDs>51Jmav2g27nHh z&~g&E4iL^q>rfZ8Crmew6UD<*Ll1zp^@D*G)yDmB+}ZdOu(LtxG^e`9o}4Hvh#Rrw ze{~JBHi*^9n88o?uISJmF;vlE72(M>nlZ}pRPK3uiT$V#t@NE=Tl9Spkp*DV7ooK`34;$OUP!$YMx=O&# zYz8KM?woOn4FJ5N_wq0ZIoL6>cJTnRPG@;w z$EwH%_(uI>0YUxnAO4TS|A+rsLdiUkND5_TR09tm=%})m265eZ&cw^%b3Ocm(7dK| KweYf4(0>8GOvO?F diff --git a/tests/integration/__screenshots__/harmony_grace.png b/tests/integration/__screenshots__/harmony_grace.png new file mode 100644 index 0000000000000000000000000000000000000000..ec954e65794ccc90049778789cb2bb7e91b78846 GIT binary patch literal 5487 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 Iu3J9*4^=g~3jhEB literal 8277 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 diff --git a/tests/integration/render.test.ts b/tests/integration/render.test.ts index 6bef48049..6b146d8bf 100644 --- a/tests/integration/render.test.ts +++ b/tests/integration/render.test.ts @@ -212,6 +212,17 @@ const TEST_CASES = [ // ("tie from nothing"), rather than one line slanting down across the page. testCase('tie.musicxml', 'tie.png'), + // Treble stave, D major, 4/4: a three-note tie chain on F#4 — dotted-eighth -> quarter -> + // quarter — where the middle note carries both tie start and stop, so two arcs join end to + // end across the same pitch. Beat 1 leads in with a 16th E4 beamed to the dotted eighth; + // beats 3-4 add a below-placed slur over a 16th run (F#4-G4) into a slashed grace E4 that + // slurs into the closing F#4 eighth. + // TODO: False positive: this baseline was created from the current render, so it may be + // accepting an incorrect tie-chain rendering. The user reports "something wrong" here. + // Review the render (focus on the F#4 tie chain — the middle note's two arcs and whether + // they connect cleanly), then run vex test tie_chain --update only once confirmed correct. + testCase('tie_chain.musicxml', 'tie_chain.png'), + // Treble stave, 4/4, one measure: two stem-up half-note chords (C5/E5/G5) with all three // members tied — the bottom member (C5) bows under (concave up) and the upper two (E5, G5) // bow over (concave down), sandwiching the chord while the over-arcs clear the up-stems. @@ -458,11 +469,20 @@ const TEST_CASES = [ // - M1: a bare major triad — root C, kind text empty — prints just "C". // - M2: a dominant seventh — root G, kind text "7" — prints "G7". // - M3: an altered-root minor — root F with 1, kind text - // "m" — prints "F#m" (ASCII '#', which the text font renders tightly). + // "m" — prints "F♯m" (real Unicode sharp). // - M4: a high first note (C6, two ledger lines above the staff) under a "D" symbol — // the symbol lifts above the notehead/ledger lines instead of colliding with them. + // - M5: a flat root — root B with -1 — prints "B♭". + // - M6: an explicit natural root — root B with 0 — prints "B♮". testCase('harmony.musicxml', 'harmony.png'), + // Treble stave, 4/4: a chord symbol over a note that carries a grace note. The grace + // note's group gives the main note a bogus near-origin bounding box; the harmony must + // position from the notehead (noteTop), not that box — otherwise it flies to the top of + // the page and defeats the top crop, leaving a huge blank margin above the system. + // - M1: a "C" symbol over a B4 quarter preceded by a slashed D5 grace. + testCase('harmony_grace.musicxml', 'harmony_grace.png'), + // Treble stave, 4/4: natural harmonics drawn as diamond noteheads (from // ). The tab counterpart (angle-bracketed frets) is tab_harmonic. // - M1: single notes on E5 — an open diamond for the half note, then filled diamonds for From 56b20230b4552103f7c7ed85e7f327cd6664c3c1 Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Sat, 27 Jun 2026 19:49:29 -0400 Subject: [PATCH 5/6] fix tie chains being incorrect sometimes --- src/spanners.ts | 33 +++++++++++++++++- .../integration/__screenshots__/tie_chain.png | Bin 8910 -> 9109 bytes tests/integration/render.test.ts | 12 +++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/spanners.ts b/src/spanners.ts index d15eb46e9..0756eb20e 100644 --- a/src/spanners.ts +++ b/src/spanners.ts @@ -170,10 +170,18 @@ export function buildTies( // share number "1", so partner() pairs every start to the chord's first // stop. Re-resolve to the same-pitch member so the tie hits the right // notehead. - const partnerNote = + let partnerNote = (tie.partner && samePitchMember(note, chordOf.get(tie.partner.note))) ?? tie.partner?.note; + // A chain-middle note carries both a tie stop and a tie start. When the + // exporter orders before on that note, mdom's + // document-order pairing matches the start to the note's OWN stop — a + // degenerate self-tie that draws nothing. Re-resolve to the next same-pitch + // note carrying a tie stop, so each link of the chain draws its own arc. + if (tie.tieType === 'start' && (!partnerNote || partnerNote === note)) { + partnerNote = nextTieStopMember(note, chords); + } const to = partnerNote && placement.get(partnerNote); if (tie.tieType !== 'start' || !from || !to) { continue; @@ -231,6 +239,29 @@ export function buildTies( return ties; } +// The next same-pitch note after `note` (in document order) that carries a tie stop. +// Used to recover the partner of a chain-middle tie start when mdom mis-pairs it to +// the note's own stop (see buildTies). null when the chain dangles past the score. +function nextTieStopMember(note: Note, chords: Chord[]): Note | undefined { + const p = note.pitch; + if (!p) { + return undefined; + } + const flat = chords.flatMap((chord) => chord.notes); + for (let i = flat.indexOf(note) + 1; i < flat.length; i++) { + const n = flat[i]; + if ( + n?.pitch?.step === p.step && + n.pitch?.octave === p.octave && + n.pitch?.alter === p.alter && + n.ties.some((t) => t.tieType === 'stop') + ) { + return n; + } + } + return undefined; +} + // The member of `chord` whose pitch matches `note` (a tie's two ends are always the // same pitch), or null when there's no chord or no match. function samePitchMember(note: Note, chord: Chord | undefined): Note | null { diff --git a/tests/integration/__screenshots__/tie_chain.png b/tests/integration/__screenshots__/tie_chain.png index 930220e074ee815766756ba62a05adda1cdcc995..9111ee23aecde710112533f34359d95310ca2017 100644 GIT binary patch literal 9109 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 literal 8910 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 V)Ox) quarter -> // quarter — where the middle note carries both tie start and stop, so two arcs join end to - // end across the same pitch. Beat 1 leads in with a 16th E4 beamed to the dotted eighth; - // beats 3-4 add a below-placed slur over a 16th run (F#4-G4) into a slashed grace E4 that - // slurs into the closing F#4 eighth. - // TODO: False positive: this baseline was created from the current render, so it may be - // accepting an incorrect tie-chain rendering. The user reports "something wrong" here. - // Review the render (focus on the F#4 tie chain — the middle note's two arcs and whether - // they connect cleanly), then run vex test tie_chain --update only once confirmed correct. + // end across the same pitch. The exporter orders this note's before its , which mdom's document-order pairing mis-matched to the note's OWN stop (a + // degenerate self-tie drawing nothing); buildTies re-resolves it so both links draw. Beat + // 1 leads in with a 16th E4 beamed to the dotted eighth; beats 3-4 add a below-placed slur + // over a 16th run (F#4-G4) into a slashed grace E4 that slurs into the closing F#4 eighth. testCase('tie_chain.musicxml', 'tie_chain.png'), // Treble stave, 4/4, one measure: two stem-up half-note chords (C5/E5/G5) with all three From 52d659d8c9c7c90ad53540d75f4fb016d10880c9 Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Sat, 27 Jun 2026 19:58:54 -0400 Subject: [PATCH 6/6] move the notation font option --- site/src/App.tsx | 70 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/site/src/App.tsx b/site/src/App.tsx index dc4e9932f..48e1c7d88 100644 --- a/site/src/App.tsx +++ b/site/src/App.tsx @@ -396,6 +396,41 @@ export default function App() { Config +
+ + +

+ The engraving font for noteheads, clefs, accidentals, and + rests. Bravura is the default. +

+
+
- -
- - -

- The engraving font for noteheads, clefs, accidentals, and - rests. Bravura is the default. -

-