diff --git a/packages/alphatab/src/EngravingSettings.ts b/packages/alphatab/src/EngravingSettings.ts index 6fb98c6935..5db6ba4880 100644 --- a/packages/alphatab/src/EngravingSettings.ts +++ b/packages/alphatab/src/EngravingSettings.ts @@ -521,6 +521,8 @@ export class EngravingSettings { this.preBeatGlyphSpacing = 0.6 * this.oneStaffSpace; this.multiVoiceDisplacedNoteHeadSpacing = 0.2 * this.oneStaffSpace; this.staffContentPadding = 1 * this.oneStaffSpace; + this.beatContentPadding = 0.5 * this.oneStaffSpace; + this.barlineContentPadding = 1 * this.oneStaffSpace; this.tuningGlyphStringRowPadding = 0.2 * this.oneStaffSpace; } @@ -790,6 +792,23 @@ export class EngravingSettings { */ public staffContentPadding = 0; + /** + * The minimum horizontal padding between the content of two adjacent beats + * (e.g. a notehead and the accidental or grace notes of the following beat). + * Additional space is only added between beats where their content would come closer than this. + * @remarks + * Behind Bars: where space is limited, characters should not be closer than 1/2 stave-space and never collide. + */ + public beatContentPadding = 0; + + /** + * The minimum horizontal padding between the content of the last beat in a bar and the bar line. + * Additional space is only added where the content would come closer than this. + * @remarks + * Behind Bars: stems must never come closer to a barline than one stave-space. + */ + public barlineContentPadding = 0; + /** * Calculates the stem height for a note of the given duration. * @param duration The duration to calculate the height respecting flag sizes. diff --git a/packages/alphatab/src/generated/EngravingSettingsCloner.ts b/packages/alphatab/src/generated/EngravingSettingsCloner.ts index c619c836a4..d1509e8bdd 100644 --- a/packages/alphatab/src/generated/EngravingSettingsCloner.ts +++ b/packages/alphatab/src/generated/EngravingSettingsCloner.ts @@ -94,6 +94,8 @@ export class EngravingSettingsCloner { clone.directionsScale = original.directionsScale; clone.multiVoiceDisplacedNoteHeadSpacing = original.multiVoiceDisplacedNoteHeadSpacing; clone.staffContentPadding = original.staffContentPadding; + clone.beatContentPadding = original.beatContentPadding; + clone.barlineContentPadding = original.barlineContentPadding; clone.stemFlagHeight = new Map(original.stemFlagHeight); return clone; } diff --git a/packages/alphatab/src/generated/EngravingSettingsJson.ts b/packages/alphatab/src/generated/EngravingSettingsJson.ts index bd9b8fc674..080e00ba00 100644 --- a/packages/alphatab/src/generated/EngravingSettingsJson.ts +++ b/packages/alphatab/src/generated/EngravingSettingsJson.ts @@ -408,6 +408,21 @@ export interface EngravingSettingsJson { * Behind Bars: characters should not be closer than 1/2 stave-space and never collide. */ staffContentPadding?: number; + /** + * The minimum horizontal padding between the content of two adjacent beats + * (e.g. a notehead and the accidental or grace notes of the following beat). + * Additional space is only added between beats where their content would come closer than this. + * @remarks + * Behind Bars: where space is limited, characters should not be closer than 1/2 stave-space and never collide. + */ + beatContentPadding?: number; + /** + * The minimum horizontal padding between the content of the last beat in a bar and the bar line. + * Additional space is only added where the content would come closer than this. + * @remarks + * Behind Bars: stems must never come closer to a barline than one stave-space. + */ + barlineContentPadding?: number; /** * The space needed by flags on the stem-side from top to bottom to place. */ diff --git a/packages/alphatab/src/generated/EngravingSettingsSerializer.ts b/packages/alphatab/src/generated/EngravingSettingsSerializer.ts index 7639856054..c8d8240bfe 100644 --- a/packages/alphatab/src/generated/EngravingSettingsSerializer.ts +++ b/packages/alphatab/src/generated/EngravingSettingsSerializer.ts @@ -156,6 +156,8 @@ export class EngravingSettingsSerializer { o.set("directionsscale", obj.directionsScale); o.set("multivoicedisplacednoteheadspacing", obj.multiVoiceDisplacedNoteHeadSpacing); o.set("staffcontentpadding", obj.staffContentPadding); + o.set("beatcontentpadding", obj.beatContentPadding); + o.set("barlinecontentpadding", obj.barlineContentPadding); { const m = new Map(); o.set("stemflagheight", m); @@ -447,6 +449,12 @@ export class EngravingSettingsSerializer { case "staffcontentpadding": obj.staffContentPadding = v! as number; return true; + case "beatcontentpadding": + obj.beatContentPadding = v! as number; + return true; + case "barlinecontentpadding": + obj.barlineContentPadding = v! as number; + return true; case "stemflagheight": obj.stemFlagHeight = new Map(); JsonHelper.forEach(v, (v, k) => { diff --git a/packages/alphatab/src/rendering/BarRendererBase.ts b/packages/alphatab/src/rendering/BarRendererBase.ts index 2999cd2ff7..dff23fe8ad 100644 --- a/packages/alphatab/src/rendering/BarRendererBase.ts +++ b/packages/alphatab/src/rendering/BarRendererBase.ts @@ -90,6 +90,7 @@ export enum NoteXPosition { * @internal */ export class BarRendererBase { + private static readonly _compressionTolerance: number = 1; private _preBeatGlyphs = new LeftToRightLayoutingGlyphGroup(); protected readonly voiceContainer = new MultiVoiceContainerGlyph(); private readonly _postBeatGlyphs = new LeftToRightLayoutingGlyphGroup(); @@ -374,6 +375,22 @@ export class BarRendererBase { return this._preBeatGlyphs.width + this._postBeatGlyphs.width; } + /** + * Reports this bar to the layout if the available width is below the minimum width + * its content needs without overlaps. + */ + private _reportCompression(containerWidth: number): void { + const info = this.layoutingInfo; + if (info.totalSpringConstant === -1) { + return; + } + // small tolerance for rounding differences in the system width distribution + const missingWidth = info.calculateVoiceWidth(info.minStretchForce) - containerWidth; + if (missingWidth > BarRendererBase._compressionTolerance) { + this.scoreRenderer.layout!.reportCompressedBar(this.bar.masterBar.index, missingWidth); + } + } + public scaleToWidth(width: number): void { // preBeat and postBeat glyphs do not get resized const containerWidth: number = width - this._preBeatGlyphs.width - this._postBeatGlyphs.width; @@ -390,6 +407,7 @@ export class BarRendererBase { } this.voiceContainer.scaleToWidth(containerWidth); + this._reportCompression(containerWidth); for (const v of this.helpers.beamHelpers) { for (const h of v) { diff --git a/packages/alphatab/src/rendering/LineBarRenderer.ts b/packages/alphatab/src/rendering/LineBarRenderer.ts index db4e77ccef..dd651e8d12 100644 --- a/packages/alphatab/src/rendering/LineBarRenderer.ts +++ b/packages/alphatab/src/rendering/LineBarRenderer.ts @@ -636,6 +636,14 @@ export abstract class LineBarRenderer extends BarRendererBase { return this.calculateBeamYWithDirection(h, x, this.getBeamDirection(h)); } + /** + * Gets the y position of the stem end of the given beat, respecting the beam or flag it belongs to. + */ + public getBeatStemEndY(beat: Beat): number { + const helper = this.helpers.getBeamingHelperForBeat(beat)!; + return this.calculateBeamY(helper, this.getBeatX(beat, BeatXPosition.Stem)); + } + protected override createPreBeatGlyphs(): void { super.createPreBeatGlyphs(); this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines)); diff --git a/packages/alphatab/src/rendering/MultiBarRestBeatContainerGlyph.ts b/packages/alphatab/src/rendering/MultiBarRestBeatContainerGlyph.ts index b657c47db4..33f719ebed 100644 --- a/packages/alphatab/src/rendering/MultiBarRestBeatContainerGlyph.ts +++ b/packages/alphatab/src/rendering/MultiBarRestBeatContainerGlyph.ts @@ -129,6 +129,15 @@ export class MultiBarRestBeatContainerGlyph extends BeatContainerGlyphBase { public override applyLayoutingInfo(_info: BarLayoutingInfo): void {} + public override scaleToWidth(beatWidth: number): void { + super.scaleToWidth(beatWidth); + // Behind Bars: the multiple-rest bar is centred within the bar + const g = this._glyph; + if (g) { + g.x = Math.max(0, (beatWidth - g.width) / 2); + } + } + public override buildBoundingsLookup(_barBounds: BarBounds, _cx: number, _cy: number): void {} public override doLayout(): void { diff --git a/packages/alphatab/src/rendering/ScoreBeatContainerGlyph.ts b/packages/alphatab/src/rendering/ScoreBeatContainerGlyph.ts index 2a7d82cc73..5a3403dd66 100644 --- a/packages/alphatab/src/rendering/ScoreBeatContainerGlyph.ts +++ b/packages/alphatab/src/rendering/ScoreBeatContainerGlyph.ts @@ -11,13 +11,12 @@ import { FlagGlyph } from '@coderline/alphatab/rendering/glyphs/FlagGlyph'; import { ScoreBeatGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreBeatGlyph'; import { ScoreBeatPreNotesGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreBeatPreNotesGlyph'; import { ScoreBendGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreBendGlyph'; +import { ScoreEffectSlurGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreEffectSlurGlyph'; import { ScoreLegatoGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreLegatoGlyph'; import { ScoreSlideLineGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreSlideLineGlyph'; import { ScoreSlurGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreSlurGlyph'; import { ScoreTieGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreTieGlyph'; -import type { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; import type { ScoreBarRenderer } from '@coderline/alphatab/rendering/ScoreBarRenderer'; -import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; /** * @internal @@ -133,26 +132,25 @@ export class ScoreBeatContainerGlyph extends BeatContainerGlyph { const tie: ScoreSlurGlyph = new ScoreSlurGlyph(`score.slur.${n.slurOrigin!.id}`, n.slurOrigin!, n, true); this.addTie(tie); } + // effect slurs (hammer-on, pull-off, legato slide) are a single slur per chord // start effect slur on first beat - if (!this._effectSlur && n.isEffectSlurOrigin && n.effectSlurDestination) { - const effectSlur = new ScoreSlurGlyph(`score.slur.effect.${n.beat.id}`, n, n.effectSlurDestination, false); - this._effectSlur = effectSlur; - this.addTie(effectSlur); + const beat = n.beat; + if (!this._effectSlur && n.isEffectSlurOrigin) { + const destination = ScoreEffectSlurGlyph.getDestinationBeat(beat); + if (destination) { + const effectSlur = new ScoreEffectSlurGlyph(`score.slur.effect.${beat.id}`, beat, destination, false); + this._effectSlur = effectSlur; + this.addTie(effectSlur); + } } // end effect slur on last beat - if (!this._effectEndSlur && n.beat.isEffectSlurDestination && n.beat.effectSlurOrigin) { - const direction = (this.renderer as LineBarRenderer).getBeatDirection(n.beat); - const startNote = - direction === BeamDirection.Up ? n.beat.effectSlurOrigin.minNote! : n.beat.effectSlurOrigin.maxNote!; - const endNote = direction === BeamDirection.Up ? n.beat.minNote! : n.beat.maxNote!; - const effectEndSlur = new ScoreSlurGlyph( - `score.slur.effect.${startNote.beat.id}`, - startNote, - endNote, - true - ); - this._effectEndSlur = effectEndSlur; - this.addTie(effectEndSlur); + if (!this._effectEndSlur && n.effectSlurOrigin) { + const origin = n.effectSlurOrigin.beat; + if (ScoreEffectSlurGlyph.getDestinationBeat(origin) === beat) { + const effectEndSlur = new ScoreEffectSlurGlyph(`score.slur.effect.${origin.id}`, origin, beat, true); + this._effectEndSlur = effectEndSlur; + this.addTie(effectEndSlur); + } } if (n.hasBend) { if (!this._bend) { diff --git a/packages/alphatab/src/rendering/TabBarRenderer.ts b/packages/alphatab/src/rendering/TabBarRenderer.ts index 91785528c8..eedc94d060 100644 --- a/packages/alphatab/src/rendering/TabBarRenderer.ts +++ b/packages/alphatab/src/rendering/TabBarRenderer.ts @@ -87,11 +87,12 @@ export class TabBarRenderer extends LineBarRenderer { * `_gapBucketEnd[i]` is the exclusive end-offset into the parallel * `_gapRelXAndWidth` / `_gapBeatRefs` arrays for line `i`. Stores the * width-invariant payload; absolute x is projected at paint time via - * `beatGlyphsStart + bg.x + relativeX`. + * `beatGlyphsStart + bg.x + bg.onNotes.x + relativeX` (`onNotes.x` is not width-invariant: + * centered full-bar beats shift it on every scale pass). */ private _gapBucketEnd: Uint32Array | null = null; private _gapRelXAndWidth: Float32Array | null = null; - private _gapBeatRefs: BeatContainerGlyphBase[] | null = null; + private _gapBeatRefs: TabBeatContainerGlyph[] | null = null; private _gapCount: number = 0; public override get showMultiBarRest(): boolean { @@ -166,7 +167,7 @@ export class TabBarRenderer extends LineBarRenderer { while (i >= bucketEnd[line]) { line++; } - const absX = base + beatRefs[i].x + relXAndWidth[i * 2]; + const absX = base + beatRefs[i].x + beatRefs[i].onNotes.x + relXAndWidth[i * 2]; spaces[line].push(new Float32Array([absX, relXAndWidth[i * 2 + 1]])); } } @@ -218,9 +219,9 @@ export class TabBarRenderer extends LineBarRenderer { let lineX = 0; if (end > cursor + 1) { let inverted = false; - let prevX = base + beatRefs[cursor].x + relXAndWidth[cursor * 2]; + let prevX = base + beatRefs[cursor].x + beatRefs[cursor].onNotes.x + relXAndWidth[cursor * 2]; for (let k = cursor + 1; k < end; k++) { - const xk = base + beatRefs[k].x + relXAndWidth[k * 2]; + const xk = base + beatRefs[k].x + beatRefs[k].onNotes.x + relXAndWidth[k * 2]; if (xk < prevX) { inverted = true; break; @@ -233,7 +234,7 @@ export class TabBarRenderer extends LineBarRenderer { const ws = new Float32Array(segCount); for (let k = 0; k < segCount; k++) { const ki = cursor + k; - xs[k] = base + beatRefs[ki].x + relXAndWidth[ki * 2]; + xs[k] = base + beatRefs[ki].x + beatRefs[ki].onNotes.x + relXAndWidth[ki * 2]; ws[k] = relXAndWidth[ki * 2 + 1]; } const order = new Uint32Array(segCount); @@ -264,7 +265,7 @@ export class TabBarRenderer extends LineBarRenderer { } for (let k = cursor; k < end; k++) { - const gx = base + beatRefs[k].x + relXAndWidth[k * 2]; + const gx = base + beatRefs[k].x + beatRefs[k].onNotes.x + relXAndWidth[k * 2]; const gw = relXAndWidth[k * 2 + 1]; canvas.fillRect(cxLocal + lineX, cyLine, gx - lineX, thickness); lineX = gx + gw; @@ -319,7 +320,7 @@ export class TabBarRenderer extends LineBarRenderer { } const relXAndWidth = new Float32Array(total * 2); - const beatRefs: BeatContainerGlyphBase[] = new Array(total); + const beatRefs: TabBeatContainerGlyph[] = new Array(total); const padding: number = this.smuflMetrics.staffLineThickness; for (const voice of this.voiceContainer.beatGlyphs.values()) { @@ -327,7 +328,7 @@ export class TabBarRenderer extends LineBarRenderer { const notes: TabBeatGlyph = (bg as TabBeatContainerGlyph).onNotes as TabBeatGlyph; const noteNumbers: TabNoteChordGlyph | null = notes.noteNumbers; if (noteNumbers) { - const relativeXBase = notes.x + noteNumbers.x - padding; + const relativeXBase = noteNumbers.x - padding; const fullWidth = noteNumbers.width + padding * 2; for (const [str, noteNumber] of noteNumbers.notesPerString) { if (!noteNumber.isEmpty) { @@ -336,7 +337,7 @@ export class TabBarRenderer extends LineBarRenderer { const idx = fwdCursor[lineIdx]++; relXAndWidth[idx * 2] = relativeXBase; relXAndWidth[idx * 2 + 1] = fullWidth; - beatRefs[idx] = bg; + beatRefs[idx] = bg as TabBeatContainerGlyph; } } } diff --git a/packages/alphatab/src/rendering/glyphs/MultiVoiceContainerGlyph.ts b/packages/alphatab/src/rendering/glyphs/MultiVoiceContainerGlyph.ts index f7061daeb8..e528b6c77a 100644 --- a/packages/alphatab/src/rendering/glyphs/MultiVoiceContainerGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/MultiVoiceContainerGlyph.ts @@ -151,9 +151,21 @@ export class MultiVoiceContainerGlyph extends Glyph { if (i > 0) { if (currentBeatGlyph.graceIndex === 0) { - // we place the grace beat directly after the previous one - // otherwise this causes flickers on resizing - currentBeatGlyph.x = beatGlyphs[i - 1].x + beatGlyphs[i - 1].width; + // we place the grace beat directly after the content of the previous one + // (its on-time position plus the post-beat size the spacing reserves for it). + // the previous beat width is not used as it is resized to this gap below + // which would cause flickers on resizing + const previous = beatGlyphs[i - 1]; + const previousSpring = this.renderer.layoutingInfo.springs.get( + previous.absoluteDisplayStart + ); + currentBeatGlyph.x = + previous.graceType === GraceType.None && previousSpring + ? previous.x + + previous.onTimeX + + previousSpring.postSpringWidth + + this.renderer.layoutingInfo.beatContentPadding + : previous.x + previous.width; } else { // for the multiple grace glyphs we take the width of the grace rod // this width setting is aligned with the positioning logic below diff --git a/packages/alphatab/src/rendering/glyphs/NumberedSlurGlyph.ts b/packages/alphatab/src/rendering/glyphs/NumberedSlurGlyph.ts index 7c08afc64e..78502bfd2d 100644 --- a/packages/alphatab/src/rendering/glyphs/NumberedSlurGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/NumberedSlurGlyph.ts @@ -1,11 +1,64 @@ +import type { Note } from '@coderline/alphatab/model/Note'; import { TabSlurGlyph } from '@coderline/alphatab/rendering/glyphs/TabSlurGlyph'; +import { TabTieGlyph } from '@coderline/alphatab/rendering/glyphs/TabTieGlyph'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; /** * @internal */ export class NumberedSlurGlyph extends TabSlurGlyph { + private _forSlide: boolean; + + public constructor(slurEffectId: string, startNote: Note, endNote: Note, forSlide: boolean, forEnd: boolean) { + super(slurEffectId, startNote, endNote, forEnd); + this._forSlide = forSlide; + } + protected override calculateTieDirection(): BeamDirection { return BeamDirection.Up; } + + public tryExpand(startNote: Note, endNote: Note, forSlide: boolean, forEnd: boolean): boolean { + // same type required + if (this._forSlide !== forSlide) { + return false; + } + // same start and endbeat + if (this.startNote.beat.id !== startNote.beat.id) { + return false; + } + if (this.endNote.beat.id !== endNote.beat.id) { + return false; + } + const isForEnd = this.renderer === this.lookupEndBeatRenderer(); + if (isForEnd !== forEnd) { + return false; + } + // same draw direction + if (this.tieDirection !== TabTieGlyph.getBeamDirectionForNote(startNote)) { + return false; + } + // if we can expand, expand in correct direction + switch (this.tieDirection) { + case BeamDirection.Up: + if (startNote.realValue > this.startNote.realValue) { + this.startNote = startNote; + this.invalidateLabels(); // labels live on startNote + } + if (endNote.realValue > this.endNote.realValue) { + this.endNote = endNote; + } + break; + case BeamDirection.Down: + if (startNote.realValue < this.startNote.realValue) { + this.startNote = startNote; + this.invalidateLabels(); + } + if (endNote.realValue < this.endNote.realValue) { + this.endNote = endNote; + } + break; + } + return true; + } } diff --git a/packages/alphatab/src/rendering/glyphs/ScoreEffectSlurGlyph.ts b/packages/alphatab/src/rendering/glyphs/ScoreEffectSlurGlyph.ts new file mode 100644 index 0000000000..0ae7ad6aa8 --- /dev/null +++ b/packages/alphatab/src/rendering/glyphs/ScoreEffectSlurGlyph.ts @@ -0,0 +1,106 @@ +import type { Beat } from '@coderline/alphatab/model/Beat'; +import { Duration } from '@coderline/alphatab/model/Duration'; +import { BeatXPosition } from '@coderline/alphatab/rendering/BeatXPosition'; +import { ScoreSlurGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreSlurGlyph'; +import type { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; +import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; + +/** + * The slur of hammer-ons, pull-offs and legato slides in standard notation. + * @remarks + * Behind Bars: all notes on one stem take a single slur, and not a slur to each note. + * Hence the slur connects the outer notes of the start and end beat on the side of the slur, + * regardless of which notes of the chords carry the effect. + * + * In multi-voice bars each voice has its own stem direction. Like articulation, the slur is then + * placed at the stem end (Behind Bars: never on the notehead side in double-stemmed writing). + * @internal + */ +export class ScoreEffectSlurGlyph extends ScoreSlurGlyph { + private _startBeat: Beat; + private _endBeat: Beat; + + public constructor(slurEffectId: string, startBeat: Beat, endBeat: Beat, forEnd: boolean) { + super(slurEffectId, startBeat.maxNote!, endBeat.maxNote!, forEnd); + this._startBeat = startBeat; + this._endBeat = endBeat; + } + + /** + * Gets the beat on which the effect slur started on the given beat ends: the furthest destination + * of the effect slur chains starting on any note of the beat. + * @returns The destination beat or null if no effect slur chain starts on the beat. + */ + public static getDestinationBeat(beat: Beat): Beat | null { + let destination: Beat | null = null; + for (const n of beat.notes) { + if (n.isEffectSlurOrigin && n.effectSlurDestination) { + const noteDestination = n.effectSlurDestination.beat; + if (!destination || noteDestination.absoluteDisplayStart > destination.absoluteDisplayStart) { + destination = noteDestination; + } + } + } + return destination; + } + + private static _isOnStemEnd(beat: Beat, renderer: LineBarRenderer, direction: BeamDirection): boolean { + return ( + beat.voice.bar.isMultiVoice && + !beat.isRest && + beat.duration > Duration.Whole && + renderer.getBeatDirection(beat) === direction + ); + } + + private _stemEndY(renderer: LineBarRenderer, beat: Beat): number { + // same padding as other effects placed at the stem end + const padding = renderer.smuflMetrics.onNoteEffectPadding; + const y = renderer.getBeatStemEndY(beat); + return this.tieDirection === BeamDirection.Up ? y - padding : y + padding; + } + + protected override calculateTieDirection(): BeamDirection { + let direction = super.calculateTieDirection(); + if (this._startBeat.voice.bar.isMultiVoice) { + // multi-voice: slur on the stem side + direction = this.lookupStartBeatRenderer().getBeatDirection(this._startBeat); + } + const isUp = direction === BeamDirection.Up; + this.startNote = (isUp ? this._startBeat.maxNote : this._startBeat.minNote) ?? this.startNote; + this.endNote = (isUp ? this._endBeat.maxNote : this._endBeat.minNote) ?? this.endNote; + return direction; + } + + protected override calculateStartX(): number { + const renderer = this.lookupStartBeatRenderer(); + if (ScoreEffectSlurGlyph._isOnStemEnd(this._startBeat, renderer, this.tieDirection)) { + return renderer.x + renderer.getBeatX(this._startBeat, BeatXPosition.Stem); + } + return super.calculateStartX(); + } + + protected override calculateStartY(): number { + const renderer = this.lookupStartBeatRenderer(); + if (ScoreEffectSlurGlyph._isOnStemEnd(this._startBeat, renderer, this.tieDirection)) { + return this._stemEndY(renderer, this._startBeat); + } + return super.calculateStartY(); + } + + protected override calculateEndX(): number { + const renderer = this.lookupEndBeatRenderer(); + if (renderer && ScoreEffectSlurGlyph._isOnStemEnd(this._endBeat, renderer, this.tieDirection)) { + return renderer.x + renderer.getBeatX(this._endBeat, BeatXPosition.Stem); + } + return super.calculateEndX(); + } + + protected override caclculateEndY(): number { + const renderer = this.lookupEndBeatRenderer(); + if (renderer && ScoreEffectSlurGlyph._isOnStemEnd(this._endBeat, renderer, this.tieDirection)) { + return this._stemEndY(renderer, this._endBeat); + } + return super.caclculateEndY(); + } +} diff --git a/packages/alphatab/src/rendering/glyphs/TabBeatContainerGlyph.ts b/packages/alphatab/src/rendering/glyphs/TabBeatContainerGlyph.ts index 437899ea0a..348e404ddb 100644 --- a/packages/alphatab/src/rendering/glyphs/TabBeatContainerGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/TabBeatContainerGlyph.ts @@ -10,6 +10,7 @@ import { TabSlideLineGlyph } from '@coderline/alphatab/rendering/glyphs/TabSlide import { TabSlurGlyph } from '@coderline/alphatab/rendering/glyphs/TabSlurGlyph'; import { TabTieGlyph } from '@coderline/alphatab/rendering/glyphs/TabTieGlyph'; import type { TabBarRenderer } from '@coderline/alphatab/rendering/TabBarRenderer'; +import type { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; import type { BeamingHelper } from '@coderline/alphatab/rendering/utils/BeamingHelper'; /** @@ -17,7 +18,8 @@ import type { BeamingHelper } from '@coderline/alphatab/rendering/utils/BeamingH */ export class TabBeatContainerGlyph extends BeatContainerGlyph { private _bend: TabBendGlyph | null = null; - private _effectSlurs: TabSlurGlyph[] = []; + private _effectSlurStarts: Set = new Set(); + private _effectSlurEnds: Set = new Set(); public constructor(beat: Beat) { super(beat); @@ -30,7 +32,8 @@ export class TabBeatContainerGlyph extends BeatContainerGlyph { } public override doLayout(): void { - this._effectSlurs = []; + this._effectSlurStarts.clear(); + this._effectSlurEnds.clear(); super.doLayout(); if (this._bend) { this._bend.renderer = this.renderer; @@ -56,46 +59,31 @@ export class TabBeatContainerGlyph extends BeatContainerGlyph { const tapSlur: TabTieGlyph = new TabTieGlyph(`tab.tie.leftHandTap.${n.id}`, n, n, false); this.addTie(tapSlur); } + // effect slurs: one arc per side of the beat (see TabSlurGlyph) // start effect slur on first beat if (n.isEffectSlurOrigin && n.effectSlurDestination) { - let expanded: boolean = false; - for (const slur of this._effectSlurs) { - if (slur.tryExpand(n, n.effectSlurDestination, false, false)) { - expanded = true; - break; - } - } - if (!expanded) { - const effectSlur: TabSlurGlyph = new TabSlurGlyph( - `tab.slur.effect.${n.id}`, - n, - n.effectSlurDestination, - false, - false + const direction = TabTieGlyph.getBeamDirectionForNote(n); + const group = this._effectSlurStarts.has(direction) + ? null + : TabSlurGlyph.getEffectSlurGroup(this.beat, direction); + if (group) { + this._effectSlurStarts.add(direction); + this.addTie( + new TabSlurGlyph(`tab.slur.effect.${group.startNote.id}`, group.startNote, group.endNote, false) ); - this._effectSlurs.push(effectSlur); - this.addTie(effectSlur); } } // end effect slur on last beat if (n.isEffectSlurDestination && n.effectSlurOrigin) { - let expanded: boolean = false; - for (const slur of this._effectSlurs) { - if (slur.tryExpand(n.effectSlurOrigin, n, false, true)) { - expanded = true; - break; - } - } - if (!expanded) { - const effectSlur: TabSlurGlyph = new TabSlurGlyph( - `tab.slur.effect.${n.effectSlurOrigin.id}`, - n.effectSlurOrigin, - n, - false, - true + const direction = TabTieGlyph.getBeamDirectionForNote(n.effectSlurOrigin); + const group = this._effectSlurEnds.has(direction) + ? null + : TabSlurGlyph.getEffectSlurGroup(n.effectSlurOrigin.beat, direction); + if (group && group.endNote === n) { + this._effectSlurEnds.add(direction); + this.addTie( + new TabSlurGlyph(`tab.slur.effect.${group.startNote.id}`, group.startNote, group.endNote, true) ); - this._effectSlurs.push(effectSlur); - this.addTie(effectSlur); } } if (n.slideInType !== SlideInType.None || n.slideOutType !== SlideOutType.None) { diff --git a/packages/alphatab/src/rendering/glyphs/TabSlurGlyph.ts b/packages/alphatab/src/rendering/glyphs/TabSlurGlyph.ts index 380eeaf13f..dec5b67b44 100644 --- a/packages/alphatab/src/rendering/glyphs/TabSlurGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/TabSlurGlyph.ts @@ -1,18 +1,69 @@ +import type { Beat } from '@coderline/alphatab/model/Beat'; import type { Note } from '@coderline/alphatab/model/Note'; import { TabTieGlyph } from '@coderline/alphatab/rendering/glyphs/TabTieGlyph'; import { TieGlyphLabels, type TieGlyphLabel } from '@coderline/alphatab/rendering/glyphs/TieGlyphLabel'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; /** + * The notes connected by the effect slur arc of one side of a beat. + * @internal + * @record + */ +export interface TabEffectSlurGroup { + startNote: Note; + endNote: Note; +} + +/** + * The arc of hammer-ons, pull-offs and legato slides on the tab staff. + * @remarks + * Like Guitar Pro, the notes of a beat take one arc per side (above the upper strings, below the lower strings), + * connecting the outer note of that side up to the furthest destination of the chains starting on it. * @internal */ export class TabSlurGlyph extends TabTieGlyph { - private _forSlide: boolean; private _labels: TieGlyphLabel[] | null = null; - public constructor(slurEffectId: string, startNote: Note, endNote: Note, forSlide: boolean, forEnd: boolean) { - super(slurEffectId, startNote, endNote, forEnd); - this._forSlide = forSlide; + /** + * Gets the notes the effect slur arc on the given side of the beat connects. + * @returns The notes, or null if no effect slur chain starts on this side of the beat. + */ + public static getEffectSlurGroup(beat: Beat, direction: BeamDirection): TabEffectSlurGroup | null { + const isUp = direction === BeamDirection.Up; + let startNote: Note | null = null; + let endNote: Note | null = null; + for (const n of beat.notes) { + const destination = n.effectSlurDestination; + if ( + !n.isVisible || + !n.isEffectSlurOrigin || + !destination || + TabTieGlyph.getBeamDirectionForNote(n) !== direction + ) { + continue; + } + + if (!startNote || (isUp ? n.realValue > startNote.realValue : n.realValue < startNote.realValue)) { + startNote = n; + } + + if ( + !endNote || + destination.beat.absoluteDisplayStart > endNote.beat.absoluteDisplayStart || + (destination.beat === endNote.beat && + (isUp ? destination.realValue > endNote.realValue : destination.realValue < endNote.realValue)) + ) { + endNote = destination; + } + } + if (!startNote || !endNote) { + return null; + } + return { startNote: startNote!, endNote: endNote! }; + } + + protected invalidateLabels(): void { + this._labels = null; } public override getTieHeight(startX: number, _startY: number, endX: number, _endY: number): number { @@ -35,48 +86,4 @@ export class TabSlurGlyph extends TabTieGlyph { } return this._labels.length > 0 ? this._labels : null; } - - public tryExpand(startNote: Note, endNote: Note, forSlide: boolean, forEnd: boolean): boolean { - // same type required - if (this._forSlide !== forSlide) { - return false; - } - // same start and endbeat - if (this.startNote.beat.id !== startNote.beat.id) { - return false; - } - if (this.endNote.beat.id !== endNote.beat.id) { - return false; - } - const isForEnd = this.renderer === this.lookupEndBeatRenderer(); - if (isForEnd !== forEnd) { - return false; - } - // same draw direction - if (this.tieDirection !== TabTieGlyph.getBeamDirectionForNote(startNote)) { - return false; - } - // if we can expand, expand in correct direction - switch (this.tieDirection) { - case BeamDirection.Up: - if (startNote.realValue > this.startNote.realValue) { - this.startNote = startNote; - this._labels = null; // invalidate cache — labels live on startNote - } - if (endNote.realValue > this.endNote.realValue) { - this.endNote = endNote; - } - break; - case BeamDirection.Down: - if (startNote.realValue < this.startNote.realValue) { - this.startNote = startNote; - this._labels = null; - } - if (endNote.realValue < this.endNote.realValue) { - this.endNote = endNote; - } - break; - } - return true; - } } diff --git a/packages/alphatab/src/rendering/glyphs/TabTieGlyph.ts b/packages/alphatab/src/rendering/glyphs/TabTieGlyph.ts index 4e5963185d..7b4d0192bc 100644 --- a/packages/alphatab/src/rendering/glyphs/TabTieGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/TabTieGlyph.ts @@ -13,7 +13,10 @@ export class TabTieGlyph extends NoteTieGlyph { return TabTieGlyph.getBeamDirectionForNote(this.startNote); } - protected static getBeamDirectionForNote(note: Note): BeamDirection { + /** + * The side of tab ties and slurs: above the upper three strings, below the lower ones. + */ + public static getBeamDirectionForNote(note: Note): BeamDirection { return note.string > 3 ? BeamDirection.Up : BeamDirection.Down; } } diff --git a/packages/alphatab/src/rendering/glyphs/TieGlyph.ts b/packages/alphatab/src/rendering/glyphs/TieGlyph.ts index 22712da1a7..9b7c58c6d8 100644 --- a/packages/alphatab/src/rendering/glyphs/TieGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/TieGlyph.ts @@ -117,6 +117,7 @@ export abstract class TieGlyph extends Glyph implements ITieGlyph { } else { this._endX = this.calculateEndX(); this._endY = this.caclculateEndY(); + this._ensureMinimumSpan(); } } else { this._shouldPaint = true; @@ -124,6 +125,7 @@ export abstract class TieGlyph extends Glyph implements ITieGlyph { this._endX = this.calculateEndX(); this._startY = this.calculateStartY(); this._endY = this.caclculateEndY(); + this._ensureMinimumSpan(); } this._shouldPaint = true; } else if (startNoteRenderer.staff !== endNoteRenderer!.staff) { @@ -279,6 +281,20 @@ export abstract class TieGlyph extends Glyph implements ITieGlyph { } } + /** + * Keeps ties and slurs at least as long as the padding the spacing keeps between beats. Only bars + * squeezed below their minimum width (overlapping content) can bring the anchors closer than this or + * even reverse their order, which would otherwise produce degenerated or inverted curves. + */ + private _ensureMinimumSpan(): void { + const minSpan = this.renderer.smuflMetrics.beatContentPadding; + if (this._endX - this._startX < minSpan) { + const center = (this._startX + this._endX) / 2; + this._startX = center - minSpan / 2; + this._endX = center + minSpan / 2; + } + } + public override paint(cx: number, cy: number, canvas: ICanvas): void { if (!this._shouldPaint) { return; diff --git a/packages/alphatab/src/rendering/layout/ScoreLayout.ts b/packages/alphatab/src/rendering/layout/ScoreLayout.ts index c469aab716..016cea3d8a 100644 --- a/packages/alphatab/src/rendering/layout/ScoreLayout.ts +++ b/packages/alphatab/src/rendering/layout/ScoreLayout.ts @@ -83,12 +83,66 @@ export abstract class ScoreLayout { public slurRegistry = new SlurRegistry(); public beamingRuleLookups = new Map(); + /** + * The master bars which had to be compressed below their minimum width in the current layout pass, + * mapped to the largest missing width across their staves. + */ + private _compressedBars: Map = new Map(); + private static readonly _maxReportedCompressedBars: number = 10; + + /** + * Registers a bar which had to be compressed below its minimum width (overlapping content). + * @param masterBarIndex The index of the master bar. + * @param missingWidth The width missing to fit the content without overlaps. + */ + public reportCompressedBar(masterBarIndex: number, missingWidth: number): void { + const existing = this._compressedBars.get(masterBarIndex); + if (existing === undefined || existing < missingWidth) { + this._compressedBars.set(masterBarIndex, missingWidth); + } + } + + private _logCompressedBars(): void { + const compressedBars = this._compressedBars; + if (compressedBars.size === 0) { + return; + } + + // bars are reported in layout order (system by system, left to right) + const barNumbers: number[] = []; + let maxMissingWidth = 0; + for (const [index, missingWidth] of compressedBars) { + barNumbers.push(index + 1); + if (missingWidth > maxMissingWidth) { + maxMissingWidth = missingWidth; + } + } + + const maxReported = ScoreLayout._maxReportedCompressedBars; + let bars = barNumbers.slice(0, Math.min(maxReported, barNumbers.length)).join(', '); + if (barNumbers.length > maxReported) { + bars += ` and ${barNumbers.length - maxReported} more`; + } + + const subject = barNumbers.length === 1 ? `Bar ${bars} does` : `Bars ${bars} do`; + const missingPixels = Math.ceil(maxMissingWidth * this.renderer.settings.display.scale); + Logger.warning( + this.name, + `${subject} not fit into the available width and had to be compressed below the minimum size ` + + `(up to ${missingPixels}px missing). Notation elements might overlap. ` + + 'Increase the available width or reduce the display scale.' + ); + compressedBars.clear(); + } + public resize(): void { this._lazyPartials.clear(); this.slurRegistry.clear(); + this._compressedBars.clear(); Profiler.begin('layout.doResize'); this.doResize(); Profiler.end('layout.doResize'); + this._logCompressedBars(); } public abstract doResize(): void; @@ -96,6 +150,7 @@ export abstract class ScoreLayout { public layoutAndRender(renderHints?: RenderHints): void { this.slurRegistry.clear(); + this._compressedBars.clear(); const score: Score = this.renderer.score!; @@ -110,6 +165,7 @@ export abstract class ScoreLayout { const firstChangedMasterBar = renderHints?.firstChangedMasterBar; if (firstChangedMasterBar !== undefined) { if (this.doUpdateForBars(renderHints!)) { + this._logCompressedBars(); return; } } @@ -134,6 +190,7 @@ export abstract class ScoreLayout { Profiler.begin('layout.doLayoutAndRender'); this.doLayoutAndRender(renderHints); Profiler.end('layout.doLayoutAndRender'); + this._logCompressedBars(); } private _lazyPartials: Map = new Map(); diff --git a/packages/alphatab/src/rendering/staves/BarLayoutingInfo.ts b/packages/alphatab/src/rendering/staves/BarLayoutingInfo.ts index 9fe026118b..e7ca6fe93b 100644 --- a/packages/alphatab/src/rendering/staves/BarLayoutingInfo.ts +++ b/packages/alphatab/src/rendering/staves/BarLayoutingInfo.ts @@ -104,8 +104,25 @@ export class BarLayoutingInfo { // (rare; in normal layouts justification slack dominates). private static readonly _overlayMinPadding: number = 3; - public constructor(spacingRatio: number = Math.SQRT2) { + /** + * The minimum padding between the content of two adjacent beats ({@link EngravingSettings.beatContentPadding}). + */ + public readonly beatContentPadding: number; + + /** + * The minimum padding between the content of the last beat and the bar line + * ({@link EngravingSettings.barlineContentPadding}). + */ + public readonly barlineContentPadding: number; + + public constructor( + spacingRatio: number = Math.SQRT2, + beatContentPadding: number = 0, + barlineContentPadding: number = 0 + ) { this._spacingExponent = BarLayoutingInfo.spacingExponentFromRatio(spacingRatio); + this.beatContentPadding = beatContentPadding; + this.barlineContentPadding = barlineContentPadding; } /** @@ -461,6 +478,8 @@ export class BarLayoutingInfo { } this._incompleteGraceRodsWidth = 0; for (const s of this.incompleteGraceRods.values()) { + // padding to the beat before the grace group (see MultiVoiceContainerGlyph) + this._incompleteGraceRodsWidth += this.beatContentPadding; for (const sp of s) { this._incompleteGraceRodsWidth += sp.preBeatWidth + sp.postSpringWidth; } @@ -516,17 +535,15 @@ export class BarLayoutingInfo { let requiredSpace = 0; if (i === sortedSprings.length - 1) { - requiredSpace = currentSpring.postSpringWidth; + requiredSpace = currentSpring.postSpringWidth + this.barlineContentPadding; } else { const nextSpring = sortedSprings[i + 1]; - requiredSpace = currentSpring.postSpringWidth + nextSpring.preSpringWidth; + requiredSpace = currentSpring.postSpringWidth + this.beatContentPadding + nextSpring.preSpringWidth; } - // for the first spring we need to ensure we take the initial - // pre-spring width into account - if (i === 0) { - requiredSpace += currentSpring.preSpringWidth; - } + // the first spring's pre-spring width is not part of the requirement: + // it is a fixed offset in front of the first spring (see calculateVoiceWidth, + // spaceToForce and buildOnTimePositions) and does not need to be stretched in. const requiredSpaceForce = requiredSpace * currentSpring.springConstant; this._updateMinStretchForce(requiredSpaceForce); diff --git a/packages/alphatab/src/rendering/staves/StaffSystem.ts b/packages/alphatab/src/rendering/staves/StaffSystem.ts index 2e7136c83a..200eb3f5a5 100644 --- a/packages/alphatab/src/rendering/staves/StaffSystem.ts +++ b/packages/alphatab/src/rendering/staves/StaffSystem.ts @@ -366,7 +366,12 @@ export class StaffSystem { ): MasterBarsRenderers { const result: MasterBarsRenderers = new MasterBarsRenderers(); result.additionalMultiBarRestIndexes = additionalMultiBarRestIndexes; - result.layoutingInfo = new BarLayoutingInfo(this.layout.renderer.settings.display.spacingRatio); + const display = this.layout.renderer.settings.display; + result.layoutingInfo = new BarLayoutingInfo( + display.spacingRatio, + display.resources.engravingSettings.beatContentPadding, + display.resources.engravingSettings.barlineContentPadding + ); result.masterBar = tracks[0].score.masterBars[barIndex]; this.masterBarsRenderers.push(result); diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-a.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-a.png index a71b6dc57f..149d097fd1 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-a.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-a.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-b.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-b.png index 117f354a64..22e60e499a 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-b.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-b.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-bb.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-bb.png index 6bce33bc5f..27123f2255 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-bb.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-bb.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-csharp.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-csharp.png index 8f7ec7fc61..a43718da97 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-csharp.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-csharp.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-d.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-d.png index 43ff99ac77..b2b120127e 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-d.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-d.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-e.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-e.png index cb7f43e821..876431d2c5 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-e.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-e.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-eb.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-eb.png index 9a516ed0b5..a1d7a3dad0 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-eb.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-eb.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-f.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-f.png index 69c5c1e9e2..b52ec5ddf8 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-f.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-f.png differ diff --git a/packages/alphatab/test-data/guitarpro8/transposition-tonality-fsharp.png b/packages/alphatab/test-data/guitarpro8/transposition-tonality-fsharp.png index 9c43a5f4af..1a298a240f 100644 Binary files a/packages/alphatab/test-data/guitarpro8/transposition-tonality-fsharp.png and b/packages/alphatab/test-data/guitarpro8/transposition-tonality-fsharp.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/BeetAnGeSample.png b/packages/alphatab/test-data/musicxml-samples/BeetAnGeSample.png index 0d7cb515de..9e6df41a2f 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/BeetAnGeSample.png and b/packages/alphatab/test-data/musicxml-samples/BeetAnGeSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/Binchois.png b/packages/alphatab/test-data/musicxml-samples/Binchois.png index 39f3cfadde..6a73340f8c 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/Binchois.png and b/packages/alphatab/test-data/musicxml-samples/Binchois.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/BrahWiMeSample.png b/packages/alphatab/test-data/musicxml-samples/BrahWiMeSample.png index fab4fc93ef..98d7205dad 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/BrahWiMeSample.png and b/packages/alphatab/test-data/musicxml-samples/BrahWiMeSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/BrookeWestSample.png b/packages/alphatab/test-data/musicxml-samples/BrookeWestSample.png index b0bd13dd63..b70ddfddfd 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/BrookeWestSample.png and b/packages/alphatab/test-data/musicxml-samples/BrookeWestSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/DebuMandSample.png b/packages/alphatab/test-data/musicxml-samples/DebuMandSample.png index 1c3b2644df..d34ca4faa6 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/DebuMandSample.png and b/packages/alphatab/test-data/musicxml-samples/DebuMandSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/Dichterliebe01.png b/packages/alphatab/test-data/musicxml-samples/Dichterliebe01.png index 7256b7b19f..3f20564108 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/Dichterliebe01.png and b/packages/alphatab/test-data/musicxml-samples/Dichterliebe01.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/Echigo.png b/packages/alphatab/test-data/musicxml-samples/Echigo.png index c07c74c543..51f7832bed 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/Echigo.png and b/packages/alphatab/test-data/musicxml-samples/Echigo.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/FaurReveSample.png b/packages/alphatab/test-data/musicxml-samples/FaurReveSample.png index b41b494330..33c30d2eca 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/FaurReveSample.png and b/packages/alphatab/test-data/musicxml-samples/FaurReveSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/MahlFaGe4Sample.png b/packages/alphatab/test-data/musicxml-samples/MahlFaGe4Sample.png index 89b76bf004..9ff1e9d3af 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/MahlFaGe4Sample.png and b/packages/alphatab/test-data/musicxml-samples/MahlFaGe4Sample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/MozaChloSample.png b/packages/alphatab/test-data/musicxml-samples/MozaChloSample.png index e9dd83f6eb..7d5e7ca247 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/MozaChloSample.png and b/packages/alphatab/test-data/musicxml-samples/MozaChloSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/MozaVeilSample.png b/packages/alphatab/test-data/musicxml-samples/MozaVeilSample.png index 7f0b6b8712..1655432fa7 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/MozaVeilSample.png and b/packages/alphatab/test-data/musicxml-samples/MozaVeilSample.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/MozartPianoSonata.png b/packages/alphatab/test-data/musicxml-samples/MozartPianoSonata.png index 7537195927..9a1c831f32 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/MozartPianoSonata.png and b/packages/alphatab/test-data/musicxml-samples/MozartPianoSonata.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/MozartTrio.png b/packages/alphatab/test-data/musicxml-samples/MozartTrio.png index 00d5ad5652..1062134b34 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/MozartTrio.png and b/packages/alphatab/test-data/musicxml-samples/MozartTrio.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/Saltarello.png b/packages/alphatab/test-data/musicxml-samples/Saltarello.png index 8118551433..5446ea585f 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/Saltarello.png and b/packages/alphatab/test-data/musicxml-samples/Saltarello.png differ diff --git a/packages/alphatab/test-data/musicxml-samples/Telemann.png b/packages/alphatab/test-data/musicxml-samples/Telemann.png index 5b3e47c767..2530598b33 100644 Binary files a/packages/alphatab/test-data/musicxml-samples/Telemann.png and b/packages/alphatab/test-data/musicxml-samples/Telemann.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/01a-Pitches-Pitches.png b/packages/alphatab/test-data/musicxml-testsuite/01a-Pitches-Pitches.png index 86b93c6462..be8f1ef5a2 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/01a-Pitches-Pitches.png and b/packages/alphatab/test-data/musicxml-testsuite/01a-Pitches-Pitches.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/01b-Pitches-Intervals.png b/packages/alphatab/test-data/musicxml-testsuite/01b-Pitches-Intervals.png index 14b48f97a8..9edb86a39b 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/01b-Pitches-Intervals.png and b/packages/alphatab/test-data/musicxml-testsuite/01b-Pitches-Intervals.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/01e-Pitches-ParenthesizedAccidentals.png b/packages/alphatab/test-data/musicxml-testsuite/01e-Pitches-ParenthesizedAccidentals.png index d4b0139324..05d65e6610 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/01e-Pitches-ParenthesizedAccidentals.png and b/packages/alphatab/test-data/musicxml-testsuite/01e-Pitches-ParenthesizedAccidentals.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/03d-Rhythm-DottedDurations-Factors.png b/packages/alphatab/test-data/musicxml-testsuite/03d-Rhythm-DottedDurations-Factors.png index 9ff38193c3..7a1868dce4 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/03d-Rhythm-DottedDurations-Factors.png and b/packages/alphatab/test-data/musicxml-testsuite/03d-Rhythm-DottedDurations-Factors.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/03f-Rhythm-Forward.png b/packages/alphatab/test-data/musicxml-testsuite/03f-Rhythm-Forward.png index af06875899..baa00a6857 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/03f-Rhythm-Forward.png and b/packages/alphatab/test-data/musicxml-testsuite/03f-Rhythm-Forward.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/11f-TimeSignatures-SymbolMeaning.png b/packages/alphatab/test-data/musicxml-testsuite/11f-TimeSignatures-SymbolMeaning.png index 2b912cbeca..d866af0ced 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/11f-TimeSignatures-SymbolMeaning.png and b/packages/alphatab/test-data/musicxml-testsuite/11f-TimeSignatures-SymbolMeaning.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/21g-Chords-Tremolos.png b/packages/alphatab/test-data/musicxml-testsuite/21g-Chords-Tremolos.png index d558445e74..320123cc7f 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/21g-Chords-Tremolos.png and b/packages/alphatab/test-data/musicxml-testsuite/21g-Chords-Tremolos.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/22d-Parenthesized-Noteheads.png b/packages/alphatab/test-data/musicxml-testsuite/22d-Parenthesized-Noteheads.png index 968cea3399..ee7e74494e 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/22d-Parenthesized-Noteheads.png and b/packages/alphatab/test-data/musicxml-testsuite/22d-Parenthesized-Noteheads.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/23b-Tuplets-Styles.png b/packages/alphatab/test-data/musicxml-testsuite/23b-Tuplets-Styles.png index 5ea3632b22..7656428cc4 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/23b-Tuplets-Styles.png and b/packages/alphatab/test-data/musicxml-testsuite/23b-Tuplets-Styles.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/23d-Tuplets-Nested.png b/packages/alphatab/test-data/musicxml-testsuite/23d-Tuplets-Nested.png index 35cea70664..b4bd295f8b 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/23d-Tuplets-Nested.png and b/packages/alphatab/test-data/musicxml-testsuite/23d-Tuplets-Nested.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/23e-Tuplets-Tremolo.png b/packages/alphatab/test-data/musicxml-testsuite/23e-Tuplets-Tremolo.png index e05cc0b871..1c5487f28e 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/23e-Tuplets-Tremolo.png and b/packages/alphatab/test-data/musicxml-testsuite/23e-Tuplets-Tremolo.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/23f-Tuplets-DurationButNoBracket.png b/packages/alphatab/test-data/musicxml-testsuite/23f-Tuplets-DurationButNoBracket.png index ba3863d959..73af1d9346 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/23f-Tuplets-DurationButNoBracket.png and b/packages/alphatab/test-data/musicxml-testsuite/23f-Tuplets-DurationButNoBracket.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24a-GraceNotes.png b/packages/alphatab/test-data/musicxml-testsuite/24a-GraceNotes.png index 1ef8cf7438..7c76734ae2 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24a-GraceNotes.png and b/packages/alphatab/test-data/musicxml-testsuite/24a-GraceNotes.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24b-ChordAsGraceNote.png b/packages/alphatab/test-data/musicxml-testsuite/24b-ChordAsGraceNote.png index f9a1cae2e5..d6e44e03ae 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24b-ChordAsGraceNote.png and b/packages/alphatab/test-data/musicxml-testsuite/24b-ChordAsGraceNote.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24c-GraceNote-MeasureEnd.png b/packages/alphatab/test-data/musicxml-testsuite/24c-GraceNote-MeasureEnd.png index 47ea3666ce..9fe9e2e35b 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24c-GraceNote-MeasureEnd.png and b/packages/alphatab/test-data/musicxml-testsuite/24c-GraceNote-MeasureEnd.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24d-AfterGrace.png b/packages/alphatab/test-data/musicxml-testsuite/24d-AfterGrace.png index b43f673bd7..5c7c9f4f41 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24d-AfterGrace.png and b/packages/alphatab/test-data/musicxml-testsuite/24d-AfterGrace.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24e-GraceNote-StaffChange.png b/packages/alphatab/test-data/musicxml-testsuite/24e-GraceNote-StaffChange.png index 1d87366010..eaa11c391d 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24e-GraceNote-StaffChange.png and b/packages/alphatab/test-data/musicxml-testsuite/24e-GraceNote-StaffChange.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24g-GraceNote-Dynamics.png b/packages/alphatab/test-data/musicxml-testsuite/24g-GraceNote-Dynamics.png index 6d6c35e026..6ff7b2ca08 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24g-GraceNote-Dynamics.png and b/packages/alphatab/test-data/musicxml-testsuite/24g-GraceNote-Dynamics.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/24h-GraceNote-Simultaneous.png b/packages/alphatab/test-data/musicxml-testsuite/24h-GraceNote-Simultaneous.png index 089dbac422..91e8b19b9f 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/24h-GraceNote-Simultaneous.png and b/packages/alphatab/test-data/musicxml-testsuite/24h-GraceNote-Simultaneous.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/32a-Notations.png b/packages/alphatab/test-data/musicxml-testsuite/32a-Notations.png index 2d83cff0e9..304ece1ccc 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/32a-Notations.png and b/packages/alphatab/test-data/musicxml-testsuite/32a-Notations.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/33f-Trill-EndingOnGraceNote.png b/packages/alphatab/test-data/musicxml-testsuite/33f-Trill-EndingOnGraceNote.png index 9aa28c8230..18f26e0bf1 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/33f-Trill-EndingOnGraceNote.png and b/packages/alphatab/test-data/musicxml-testsuite/33f-Trill-EndingOnGraceNote.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/33j-Beams-Tremolos.png b/packages/alphatab/test-data/musicxml-testsuite/33j-Beams-Tremolos.png index e8b3ff6107..f32df0e8ee 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/33j-Beams-Tremolos.png and b/packages/alphatab/test-data/musicxml-testsuite/33j-Beams-Tremolos.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/34b-Colors.png b/packages/alphatab/test-data/musicxml-testsuite/34b-Colors.png index 02a3c503c4..542cd54c00 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/34b-Colors.png and b/packages/alphatab/test-data/musicxml-testsuite/34b-Colors.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/34c-Font-Size.png b/packages/alphatab/test-data/musicxml-testsuite/34c-Font-Size.png index 568ba7dfbe..46f2d6d8f0 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/34c-Font-Size.png and b/packages/alphatab/test-data/musicxml-testsuite/34c-Font-Size.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/42b-MultiVoice-MidMeasureClefChange.png b/packages/alphatab/test-data/musicxml-testsuite/42b-MultiVoice-MidMeasureClefChange.png index a23edccce4..3eb98cfdfe 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/42b-MultiVoice-MidMeasureClefChange.png and b/packages/alphatab/test-data/musicxml-testsuite/42b-MultiVoice-MidMeasureClefChange.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/43d-MultiStaff-StaffChange.png b/packages/alphatab/test-data/musicxml-testsuite/43d-MultiStaff-StaffChange.png index f36018e971..30be570b55 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/43d-MultiStaff-StaffChange.png and b/packages/alphatab/test-data/musicxml-testsuite/43d-MultiStaff-StaffChange.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/61f-Lyrics-GracedNotes.png b/packages/alphatab/test-data/musicxml-testsuite/61f-Lyrics-GracedNotes.png index 81525283af..16dcaccbf7 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/61f-Lyrics-GracedNotes.png and b/packages/alphatab/test-data/musicxml-testsuite/61f-Lyrics-GracedNotes.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/61h-Lyrics-BeamsMelismata.png b/packages/alphatab/test-data/musicxml-testsuite/61h-Lyrics-BeamsMelismata.png index 83a1612e00..d73a935a02 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/61h-Lyrics-BeamsMelismata.png and b/packages/alphatab/test-data/musicxml-testsuite/61h-Lyrics-BeamsMelismata.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/71e-TabStaves.png b/packages/alphatab/test-data/musicxml-testsuite/71e-TabStaves.png index 5d7d14c837..f5fc328317 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/71e-TabStaves.png and b/packages/alphatab/test-data/musicxml-testsuite/71e-TabStaves.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/99a-Sibelius5-IgnoreBeaming.png b/packages/alphatab/test-data/musicxml-testsuite/99a-Sibelius5-IgnoreBeaming.png index 819f110a2b..f53023115d 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/99a-Sibelius5-IgnoreBeaming.png and b/packages/alphatab/test-data/musicxml-testsuite/99a-Sibelius5-IgnoreBeaming.png differ diff --git a/packages/alphatab/test-data/musicxml-testsuite/99b-Lyrics-BeamsMelismata-IgnoreBeams.png b/packages/alphatab/test-data/musicxml-testsuite/99b-Lyrics-BeamsMelismata-IgnoreBeams.png index 83a1612e00..d73a935a02 100644 Binary files a/packages/alphatab/test-data/musicxml-testsuite/99b-Lyrics-BeamsMelismata-IgnoreBeams.png and b/packages/alphatab/test-data/musicxml-testsuite/99b-Lyrics-BeamsMelismata-IgnoreBeams.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/onnotes-beat.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/onnotes-beat.png index 0c26580d84..4c2785a8fb 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/onnotes-beat.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/onnotes-beat.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-bar.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-bar.png index 464df60163..ff24f82f59 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-bar.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-bar.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-beat.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-beat.png index c530ad9d76..337dd7eb51 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-beat.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-beat.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-master.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-master.png index 1551cfb1ac..5b3a0abe60 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-master.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-master.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-note.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-note.png index 3ad3eee57a..a812abfdc5 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-note.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-note.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-system.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-system.png index d5964f2211..ffa671558b 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/real-system.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/real-system.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-bar.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-bar.png index 464df60163..ff24f82f59 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-bar.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-bar.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-beat.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-beat.png index 1adf7a294f..2d73c1711e 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-beat.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-beat.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-master.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-master.png index 41c43bfa72..f4bb4463c4 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-master.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-master.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-note.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-note.png index 3ad3eee57a..a812abfdc5 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-note.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-note.png differ diff --git a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-system.png b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-system.png index e25731655a..f60c5141c7 100644 Binary files a/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-system.png and b/packages/alphatab/test-data/visual-tests/bounds-lookup/visual-system.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/accentuations.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/accentuations.png index cef739332e..a143b50a5a 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/accentuations.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/accentuations.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/barre.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/barre.png index b04a9b973a..df1564ef45 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/barre.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/barre.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-slash.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-slash.png index dbdde28654..9bb53edcbb 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-slash.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-slash.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-tempo-change.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-tempo-change.png index cddbdce4bd..992e4a3570 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-tempo-change.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/beat-tempo-change.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/bends.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/bends.png index e270e7f1ea..073896475c 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/bends.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/bends.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/brush.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/brush.png index e69ab853d5..d5c0ca5161 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/brush.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/brush.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/chords.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/chords.png index ef48b96ae5..2e71d1f52f 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/chords.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/chords.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/dead-slap.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/dead-slap.png index 120b969f92..2484eb6bb2 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/dead-slap.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/dead-slap.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fade-in.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fade-in.png index 11e8898387..1d61c4fcd5 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fade-in.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fade-in.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering-new.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering-new.png index 14ccc47d9f..a2302d4fd2 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering-new.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering-new.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering.png index 23d5cc38e9..c536459512 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/fingering.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/golpe.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/golpe.png index 75be3874ec..8c53322578 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/golpe.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/golpe.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at11.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at11.png index a81134be4a..64fafefa13 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at11.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at11.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at12.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at12.png index 30254562cf..bf1d084fc9 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at12.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at12.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at13.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at13.png index 345e283cdc..7890c1f06a 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at13.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at13.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at9.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at9.png index 0e0559239f..a81134be4a 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at9.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-at9.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chain-across-other-string.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chain-across-other-string.png new file mode 100644 index 0000000000..6a53b28a98 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chain-across-other-string.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-different-chain-lengths.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-different-chain-lengths.png new file mode 100644 index 0000000000..8067e8d469 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-different-chain-lengths.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-mixed-kinds.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-mixed-kinds.png new file mode 100644 index 0000000000..a6c97f2876 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-mixed-kinds.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-opposite-stems.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-opposite-stems.png new file mode 100644 index 0000000000..469f8ea641 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-opposite-stems.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-slide-accidentals.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-slide-accidentals.png new file mode 100644 index 0000000000..0bd09b4d6e Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-slide-accidentals.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-stems-up.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-stems-up.png new file mode 100644 index 0000000000..2e93217aba Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-stems-up.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-chain.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-chain.png index b76a920db1..c69ff18f24 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-chain.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-chain.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-tie.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-tie.png new file mode 100644 index 0000000000..0e0d7e9a1e Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-chord-with-tie.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice-beamed.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice-beamed.png new file mode 100644 index 0000000000..043c22c8f7 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice-beamed.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice.png new file mode 100644 index 0000000000..25af7d69a1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/hopo-arcs-multi-voice.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/let-ring.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/let-ring.png index 65b0f2e716..05b149e04f 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/let-ring.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/let-ring.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/palm-mute.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/palm-mute.png index 8bf307a1af..a25bc7038e 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/palm-mute.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/palm-mute.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/pick-stroke.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/pick-stroke.png index fbf266a54e..2abf317908 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/pick-stroke.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/pick-stroke.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides-line-break.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides-line-break.png index 1eb9055722..83d4f10a21 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides-line-break.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides-line-break.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides.png index 6eb235244b..8e05eec385 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/slides.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/string-numbers.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/string-numbers.png index 9842c6e601..5a95fbfdf4 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/string-numbers.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/string-numbers.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tap.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tap.png index 075b459b98..7cfe999d04 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tap.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tap.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/text.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/text.png index 5a1ffa18a9..2e03fe6be9 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/text.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/text.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-bar.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-bar.png index 02ba01eba2..83bc33d235 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-bar.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-bar.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags-bottom.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags-bottom.png index dbf5a4b6c0..a5df9a79b1 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags-bottom.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags-bottom.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags.png index 2ef8ae8289..d2d39293c4 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-flags.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-picking.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-picking.png index 2d0adcfc86..dcf3a194a3 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-picking.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-picking.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-beams.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-beams.png index 31e613a505..cc1b511f84 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-beams.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-flags.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-flags.png index b0c42e56c9..0095c2a42f 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-flags.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-buzzroll-flags.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-beams.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-beams.png index 1f0ef2ab90..387e248ea9 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-beams.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-flags.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-flags.png index a889dc6a64..81fb2a3abf 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-flags.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-standard-default-flags.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-beams.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-beams.png index c3997a0c56..946489e7e9 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-beams.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-flags.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-flags.png index f8e2556fa1..dc02ffcdb1 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-flags.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-buzzroll-flags.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-beams.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-beams.png index c940b5d0bf..37c096b36f 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-beams.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-flags.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-flags.png index 1971cb9712..f6a7e39664 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-flags.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tremolo-tabs-default-flags.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/trill.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/trill.png index c0323b28e1..bfe2b390ea 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/trill.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/trill.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/triplet-feel.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/triplet-feel.png index 32584c775e..d89b7f9c8a 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/triplet-feel.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/triplet-feel.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png index 4985427ec0..80ee15c3cc 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png differ diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets.png index cf32d4836b..e8befe8818 100644 Binary files a/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets.png and b/packages/alphatab/test-data/visual-tests/effects-and-annotations/tuplets.png differ diff --git a/packages/alphatab/test-data/visual-tests/general/colors-disabled.png b/packages/alphatab/test-data/visual-tests/general/colors-disabled.png index de5a77686b..52e09ae50b 100644 Binary files a/packages/alphatab/test-data/visual-tests/general/colors-disabled.png and b/packages/alphatab/test-data/visual-tests/general/colors-disabled.png differ diff --git a/packages/alphatab/test-data/visual-tests/general/colors.png b/packages/alphatab/test-data/visual-tests/general/colors.png index af31f37867..1b35244c9a 100644 Binary files a/packages/alphatab/test-data/visual-tests/general/colors.png and b/packages/alphatab/test-data/visual-tests/general/colors.png differ diff --git a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-at-bar-boundary.png b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-at-bar-boundary.png index ac031d7acf..928aa8d0bd 100644 Binary files a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-at-bar-boundary.png and b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-at-bar-boundary.png differ diff --git a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-track.png b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-track.png index 509f703eab..acbcd72eaf 100644 Binary files a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-track.png and b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-track.png differ diff --git a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-voice.png b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-voice.png index 8576d8782b..b4cf7cfcb2 100644 Binary files a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-voice.png and b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multi-voice.png differ diff --git a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multiple-consecutive.png b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multiple-consecutive.png index 44a47a482b..b0f982d405 100644 Binary files a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multiple-consecutive.png and b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-multiple-consecutive.png differ diff --git a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-without-host-incomplete-group.png b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-without-host-incomplete-group.png index 3ac1d6a743..945c836059 100644 Binary files a/packages/alphatab/test-data/visual-tests/grace-spacing/grace-without-host-incomplete-group.png and b/packages/alphatab/test-data/visual-tests/grace-spacing/grace-without-host-incomplete-group.png differ diff --git a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-slashed.png b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-slashed.png index 8b1c848798..3cff8ece07 100644 Binary files a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-slashed.png and b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-slashed.png differ diff --git a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams-slashed.png b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams-slashed.png index 9a4b23cfcc..732e26f295 100644 Binary files a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams-slashed.png and b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams-slashed.png differ diff --git a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png index d96ac0edfe..5c960e6199 100644 Binary files a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png and b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm.png b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm.png index 34709e9ba1..b1d1f6cc13 100644 Binary files a/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm.png and b/packages/alphatab/test-data/visual-tests/guitar-tabs/rhythm.png differ diff --git a/packages/alphatab/test-data/visual-tests/guitar-tabs/string-variations.png b/packages/alphatab/test-data/visual-tests/guitar-tabs/string-variations.png index e9e8fe931a..437802f3b8 100644 Binary files a/packages/alphatab/test-data/visual-tests/guitar-tabs/string-variations.png and b/packages/alphatab/test-data/visual-tests/guitar-tabs/string-variations.png differ diff --git a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-380.png b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-380.png index d962fb0d01..6e26d99ba4 100644 Binary files a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-380.png and b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-380.png differ diff --git a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-400.png b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-400.png index bf26f5da7f..f2e624e3a0 100644 Binary files a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-400.png and b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-400.png differ diff --git a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-500.png b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-500.png index 104d70b346..c08ee20199 100644 Binary files a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-500.png and b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-500.png differ diff --git a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-600.png b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-600.png index f92c673724..2392256b9e 100644 Binary files a/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-600.png and b/packages/alphatab/test-data/visual-tests/issues/whammy-resize-wrap-600.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/horizontal-layout-5to8.png b/packages/alphatab/test-data/visual-tests/layout/horizontal-layout-5to8.png index ee32f9e391..b6d8e67cd1 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/horizontal-layout-5to8.png and b/packages/alphatab/test-data/visual-tests/layout/horizontal-layout-5to8.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/horizontal-layout.png b/packages/alphatab/test-data/visual-tests/layout/horizontal-layout.png index 254bb07dbc..e9e769f015 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/horizontal-layout.png and b/packages/alphatab/test-data/visual-tests/layout/horizontal-layout.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/multi-track.png b/packages/alphatab/test-data/visual-tests/layout/multi-track.png index ab7ba0f8a0..bb59f03355 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/multi-track.png and b/packages/alphatab/test-data/visual-tests/layout/multi-track.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/multi-voice.png b/packages/alphatab/test-data/visual-tests/layout/multi-voice.png index 1c58d1257f..8e0eadb9f9 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/multi-voice.png and b/packages/alphatab/test-data/visual-tests/layout/multi-voice.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/multibar-rest-multi-track.png b/packages/alphatab/test-data/visual-tests/layout/multibar-rest-multi-track.png index a5f69fa492..ea20e2e06e 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/multibar-rest-multi-track.png and b/packages/alphatab/test-data/visual-tests/layout/multibar-rest-multi-track.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/multibar-rest-single-track.png b/packages/alphatab/test-data/visual-tests/layout/multibar-rest-single-track.png index 7cac8e7d8d..f7153e9910 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/multibar-rest-single-track.png and b/packages/alphatab/test-data/visual-tests/layout/multibar-rest-single-track.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/page-layout-5barsperrow.png b/packages/alphatab/test-data/visual-tests/layout/page-layout-5barsperrow.png index 89122fcadf..199c1032e2 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/page-layout-5barsperrow.png and b/packages/alphatab/test-data/visual-tests/layout/page-layout-5barsperrow.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/page-layout-5to8.png b/packages/alphatab/test-data/visual-tests/layout/page-layout-5to8.png index 3038733087..65cd85c9da 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/page-layout-5to8.png and b/packages/alphatab/test-data/visual-tests/layout/page-layout-5to8.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/page-layout-justify-last-row.png b/packages/alphatab/test-data/visual-tests/layout/page-layout-justify-last-row.png index 11487eeb5a..1874dd5db7 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/page-layout-justify-last-row.png and b/packages/alphatab/test-data/visual-tests/layout/page-layout-justify-last-row.png differ diff --git a/packages/alphatab/test-data/visual-tests/layout/page-layout.png b/packages/alphatab/test-data/visual-tests/layout/page-layout.png index d64a7f4b13..badca4777c 100644 Binary files a/packages/alphatab/test-data/visual-tests/layout/page-layout.png and b/packages/alphatab/test-data/visual-tests/layout/page-layout.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced-alphatex.png b/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced-alphatex.png index 49d97498a3..364faf93b2 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced-alphatex.png and b/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced-alphatex.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced.png b/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced.png index b4881c4108..0d3942b55d 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced.png and b/packages/alphatab/test-data/visual-tests/music-notation/accidentals-advanced.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/accidentals.png b/packages/alphatab/test-data/visual-tests/music-notation/accidentals.png index 87c8d4f0ea..e82e3c21d9 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/accidentals.png and b/packages/alphatab/test-data/visual-tests/music-notation/accidentals.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/beams-advanced.png b/packages/alphatab/test-data/visual-tests/music-notation/beams-advanced.png index 6ef2844211..93a3087052 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/beams-advanced.png and b/packages/alphatab/test-data/visual-tests/music-notation/beams-advanced.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/brushes-ukulele.png b/packages/alphatab/test-data/visual-tests/music-notation/brushes-ukulele.png index d719b83a1a..29ec83a31a 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/brushes-ukulele.png and b/packages/alphatab/test-data/visual-tests/music-notation/brushes-ukulele.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/brushes.png b/packages/alphatab/test-data/visual-tests/music-notation/brushes.png index 9c4e9e62d7..1736fdadf1 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/brushes.png and b/packages/alphatab/test-data/visual-tests/music-notation/brushes.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/forced-accidentals.png b/packages/alphatab/test-data/visual-tests/music-notation/forced-accidentals.png index 85570aa2f3..0c083a2723 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/forced-accidentals.png and b/packages/alphatab/test-data/visual-tests/music-notation/forced-accidentals.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c3.png b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c3.png index 2115f090d6..4eb6578565 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c3.png and b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c3.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c4.png b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c4.png index d4b8f80077..3627b9247b 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c4.png and b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-c4.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-f4.png b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-f4.png index f95a3f1f8f..38863b79f6 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-f4.png and b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-f4.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-g2.png b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-g2.png index 4bb1e85490..0f4f934855 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-g2.png and b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures-g2.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures.png b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures.png index 4bb1e85490..0f4f934855 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/key-signatures.png and b/packages/alphatab/test-data/visual-tests/music-notation/key-signatures.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/notes-rests-beams.png b/packages/alphatab/test-data/visual-tests/music-notation/notes-rests-beams.png index beab9da18a..e926353955 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/notes-rests-beams.png and b/packages/alphatab/test-data/visual-tests/music-notation/notes-rests-beams.png differ diff --git a/packages/alphatab/test-data/visual-tests/music-notation/rest-collisions.png b/packages/alphatab/test-data/visual-tests/music-notation/rest-collisions.png index cb4ce019a2..6250d82844 100644 Binary files a/packages/alphatab/test-data/visual-tests/music-notation/rest-collisions.png and b/packages/alphatab/test-data/visual-tests/music-notation/rest-collisions.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png b/packages/alphatab/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png index eda018335f..c87ceb637a 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png and b/packages/alphatab/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png b/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png index 0e0d37d40a..d82f2e5f80 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png and b/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png b/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png index a7827579fb..5d1af6c03c 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png and b/packages/alphatab/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/bends-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/bends-default.png index 317c099a40..077c710197 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/bends-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/bends-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/bends-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/bends-songbook.png index e6f9e82c58..a0d62f0107 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/bends-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/bends-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/chords-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/chords-default.png index b07c5ce297..afa671ca56 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/chords-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/chords-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/chords-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/chords-songbook.png index b07c5ce297..afa671ca56 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/chords-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/chords-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-default.png index 16834a00fd..8585a5a570 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-songbook.png index 16834a00fd..8585a5a570 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/dynamics-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/fingering-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/fingering-default.png index 853c4b7d66..0552d0f109 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/fingering-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/fingering-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/fingering-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/fingering-songbook.png index 9f65f14109..c36f2b8b46 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/fingering-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/fingering-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/full-default-large.png b/packages/alphatab/test-data/visual-tests/notation-legend/full-default-large.png index 9d81c8b488..2fbb8933fc 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/full-default-large.png and b/packages/alphatab/test-data/visual-tests/notation-legend/full-default-large.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/full-default-small.png b/packages/alphatab/test-data/visual-tests/notation-legend/full-default-small.png index 1a4a80d299..63fbf5b7f8 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/full-default-small.png and b/packages/alphatab/test-data/visual-tests/notation-legend/full-default-small.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/full-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/full-default.png index a89108b21b..a8ef7c6a70 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/full-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/full-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/full-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/full-songbook.png index c422cce948..2b115d9f08 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/full-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/full-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/hammer-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/hammer-default.png index 43bd1922cc..e664c228c9 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/hammer-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/hammer-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/hammer-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/hammer-songbook.png index 43bd1922cc..e664c228c9 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/hammer-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/hammer-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-default.png index 2a3dec8f02..dd26573d21 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-songbook.png index 2a3dec8f02..dd26573d21 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/harmonics-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-default.png index d2c3c9fdbb..5995a6189b 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-songbook.png index 7cef85fed6..ef36b4b5be 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/let-ring-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/mixed-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/mixed-default.png index d49936179c..9bbd87100d 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/mixed-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/mixed-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/mixed-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/mixed-songbook.png index 663a37ba23..a38df7421e 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/mixed-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/mixed-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-default.png index bd2d6aa781..8544f275f2 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-songbook.png index bd2d6aa781..8544f275f2 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/multi-voice-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-default.png index b7069f4e5d..03316475df 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-songbook.png index b7069f4e5d..03316475df 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/ottavia-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-default.png index 18e03dd7eb..b222837c7a 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-songbook.png index 18e03dd7eb..b222837c7a 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/pick-stroke-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1300.png b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1300.png index 9d0ad0da38..2f79c16428 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1300.png and b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1500.png b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1500.png index 366dd41595..5a7667e4e8 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1500.png and b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-1500.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-500.png b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-500.png index ac5b7d1855..f0542dd12c 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-500.png and b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-500.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-800.png b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-800.png index 9e4756ad4b..ff330677d6 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-800.png and b/packages/alphatab/test-data/visual-tests/notation-legend/resize-sequence-800.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/slash-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/slash-default.png index 83bd1256c3..9f895dee9f 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/slash-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/slash-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/slash-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/slash-songbook.png index 83bd1256c3..9f895dee9f 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/slash-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/slash-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/smufl-petaluma-1300.png b/packages/alphatab/test-data/visual-tests/notation-legend/smufl-petaluma-1300.png index 79343f0d47..68f3142b16 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/smufl-petaluma-1300.png and b/packages/alphatab/test-data/visual-tests/notation-legend/smufl-petaluma-1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-default.png index 8e9713a525..2d197d4f75 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-songbook.png index 8e9713a525..2d197d4f75 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/staccatissimo-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/sweep-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/sweep-default.png index 669202bcd0..97ed25550f 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/sweep-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/sweep-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/sweep-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/sweep-songbook.png index 669202bcd0..97ed25550f 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/sweep-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/sweep-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-default.png index 3d88a01daf..aed1e9573a 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-songbook.png index 3d88a01daf..aed1e9573a 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/tap-riff-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/text-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/text-default.png index 292bf484e7..3f0472ec80 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/text-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/text-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/text-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/text-songbook.png index 292bf484e7..3f0472ec80 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/text-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/text-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png index 1b44b2ef0f..5fd16ae8e3 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png index 265adbb51f..bfe6b1baf7 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-default.png index 22a4e42069..445f308a27 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-songbook.png index 22a4e42069..445f308a27 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/triplet-feel-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/wah-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/wah-default.png index ca4e474810..265219896e 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/wah-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/wah-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/wah-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/wah-songbook.png index ca4e474810..265219896e 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/wah-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/wah-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/whammy-default.png b/packages/alphatab/test-data/visual-tests/notation-legend/whammy-default.png index 7067c223d0..5ee2faf3b1 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/whammy-default.png and b/packages/alphatab/test-data/visual-tests/notation-legend/whammy-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/notation-legend/whammy-songbook.png b/packages/alphatab/test-data/visual-tests/notation-legend/whammy-songbook.png index 0f3fcce787..21bcc1a954 100644 Binary files a/packages/alphatab/test-data/visual-tests/notation-legend/whammy-songbook.png and b/packages/alphatab/test-data/visual-tests/notation-legend/whammy-songbook.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-alto-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-alto-F3.png index ad82719299..955a08662f 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-alto-F3.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-alto-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-bass-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-bass-G2.png index ec519ab021..3dd86419f9 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-bass-G2.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-bass-G2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-default.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-default.png index e4a7bdaecf..652f539a46 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-default.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-1.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-1.png index 7738f79936..c864b502c2 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-1.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-2.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-2.png index d801ad4695..26c41f1e27 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-2.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-3.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-3.png index 000be0c991..3a552c60f6 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-3.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-4.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-4.png index e0686cbd33..59e6cb8e67 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-4.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-5.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-5.png index 51e5c0fb61..57f1a72d91 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-5.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-staff-lines-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-tenor-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-tenor-D3.png index 11e2550dbd..c57e138136 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-tenor-D3.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-tenor-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-treble-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-treble-E4.png index b376fe9177..c7be007b59 100644 Binary files a/packages/alphatab/test-data/visual-tests/rest-position/rest-position-treble-E4.png and b/packages/alphatab/test-data/visual-tests/rest-position/rest-position-treble-E4.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-coverage/beat-effects-above-and-below.png b/packages/alphatab/test-data/visual-tests/skyline-coverage/beat-effects-above-and-below.png index 9f0e05a386..09d539489f 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-coverage/beat-effects-above-and-below.png and b/packages/alphatab/test-data/visual-tests/skyline-coverage/beat-effects-above-and-below.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-coverage/mixed-staves.png b/packages/alphatab/test-data/visual-tests/skyline-coverage/mixed-staves.png index 4ec2c617cd..a2db2bc1b4 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-coverage/mixed-staves.png and b/packages/alphatab/test-data/visual-tests/skyline-coverage/mixed-staves.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-coverage/slash-rhythm.png b/packages/alphatab/test-data/visual-tests/skyline-coverage/slash-rhythm.png index 9e4e03b90d..2f2329fb40 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-coverage/slash-rhythm.png and b/packages/alphatab/test-data/visual-tests/skyline-coverage/slash-rhythm.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w1300.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w1300.png index b098bc6f88..8a6879b3b2 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w1300.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w700.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w700.png index a732807949..1f47fcf931 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w700.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/beamed-eighths-w700.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w1300.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w1300.png index 8be4170fc8..513d568f1e 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w1300.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w500.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w500.png index bfaf78460d..01fa57e477 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w500.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w500.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w800.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w800.png index 72a9ff9439..6a4f143fa3 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w800.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/mixed-content-w800.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w1300.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w1300.png index d491fb58d2..bec2c8581c 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w1300.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w700.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w700.png index 5c72a9e4db..e201e22825 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w700.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/slash-rhythm-w700.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w1300.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w1300.png index e6eec85590..8fafde55f5 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w1300.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w700.png b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w700.png index 06f21b88b8..9a43db067d 100644 Binary files a/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w700.png and b/packages/alphatab/test-data/visual-tests/skyline-resize-coverage/tuplet-w700.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/beaming-anacrusis.png b/packages/alphatab/test-data/visual-tests/special-notes/beaming-anacrusis.png index 0d0c454608..69bfd58e11 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/beaming-anacrusis.png and b/packages/alphatab/test-data/visual-tests/special-notes/beaming-anacrusis.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/beaming-mode.png b/packages/alphatab/test-data/visual-tests/special-notes/beaming-mode.png index 04c5c5b6cb..c4d3ad4f0d 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/beaming-mode.png and b/packages/alphatab/test-data/visual-tests/special-notes/beaming-mode.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/dead-notes.png b/packages/alphatab/test-data/visual-tests/special-notes/dead-notes.png index 9ca887e922..686a5c7f07 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/dead-notes.png and b/packages/alphatab/test-data/visual-tests/special-notes/dead-notes.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/ghost-notes.png b/packages/alphatab/test-data/visual-tests/special-notes/ghost-notes.png index 3307b024e0..a448c40c08 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/ghost-notes.png and b/packages/alphatab/test-data/visual-tests/special-notes/ghost-notes.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300-2.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300-2.png index 8dc1b6e457..76eb0efa17 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300-2.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300.png index 5ba53cd6fd..695c22138a 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-1300.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-800.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-800.png index 9b56e4e8a9..f4eb3d38d1 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-800.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced-800.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced.png index 5ba53cd6fd..695c22138a 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-advanced.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-alignment.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-alignment.png index 7afb18e2e6..606aaa3a10 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-alignment.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes-alignment.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes.png b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes.png index 3defbf5f77..ccb544eaea 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-notes/grace-notes.png and b/packages/alphatab/test-data/visual-tests/special-notes/grace-notes.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-tracks/grand-staff.png b/packages/alphatab/test-data/visual-tests/special-tracks/grand-staff.png index 1a671e92e6..794a96626b 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-tracks/grand-staff.png and b/packages/alphatab/test-data/visual-tests/special-tracks/grand-staff.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-tracks/numbered-tuplets.png b/packages/alphatab/test-data/visual-tests/special-tracks/numbered-tuplets.png index 23658dd8e2..5e1a059232 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-tracks/numbered-tuplets.png and b/packages/alphatab/test-data/visual-tests/special-tracks/numbered-tuplets.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-tracks/numbered.png b/packages/alphatab/test-data/visual-tests/special-tracks/numbered.png index 67e9a255cf..70ecf8970c 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-tracks/numbered.png and b/packages/alphatab/test-data/visual-tests/special-tracks/numbered.png differ diff --git a/packages/alphatab/test-data/visual-tests/special-tracks/slash.png b/packages/alphatab/test-data/visual-tests/special-tracks/slash.png index e7b00ff374..5bc9fa74b6 100644 Binary files a/packages/alphatab/test-data/visual-tests/special-tracks/slash.png and b/packages/alphatab/test-data/visual-tests/special-tracks/slash.png differ diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png index 5e40bb66b8..16b0f0fdd6 100644 Binary files a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png and b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png differ diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png index 555f08dd6c..7f838678f4 100644 Binary files a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png and b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png differ diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-slash.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-slash.png index 32261849be..319b79200d 100644 Binary files a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-slash.png and b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-slash.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/power-law-spacing-ratio-tight.png b/packages/alphatab/test-data/visual-tests/system-spacing/power-law-spacing-ratio-tight.png index f7e22c5514..c5b1454159 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/power-law-spacing-ratio-tight.png and b/packages/alphatab/test-data/visual-tests/system-spacing/power-law-spacing-ratio-tight.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/power-law-stretch-force-orthogonal-low.png b/packages/alphatab/test-data/visual-tests/system-spacing/power-law-stretch-force-orthogonal-low.png index 0eb63f2ae1..106ff02c75 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/power-law-stretch-force-orthogonal-low.png and b/packages/alphatab/test-data/visual-tests/system-spacing/power-law-stretch-force-orthogonal-low.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-aligns-same-duration-notes.png b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-aligns-same-duration-notes.png index 6b2fecedf0..59bff34826 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-aligns-same-duration-notes.png and b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-aligns-same-duration-notes.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-horizontal-preserves-local.png b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-horizontal-preserves-local.png index 46dbf47267..5602b37712 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-horizontal-preserves-local.png and b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-horizontal-preserves-local.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-page-automatic.png b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-page-automatic.png index 852e097194..9116e8d94e 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-page-automatic.png and b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-page-automatic.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-shorter-note-first.png b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-shorter-note-first.png index d1af6d8dbe..a6d57be037 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-shorter-note-first.png and b/packages/alphatab/test-data/visual-tests/system-spacing/shared-min-duration-shorter-note-first.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-grace-notes-excluded.png b/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-grace-notes-excluded.png index f866b3ffb7..b6cd63d8fc 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-grace-notes-excluded.png and b/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-grace-notes-excluded.png differ diff --git a/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-multi-track-aggregation.png b/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-multi-track-aggregation.png index ab26acaa25..36018023bd 100644 Binary files a/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-multi-track-aggregation.png and b/packages/alphatab/test-data/visual-tests/system-spacing/system-min-duration-multi-track-aggregation.png differ diff --git a/packages/alphatab/test/rendering/BarLayoutingInfo.test.ts b/packages/alphatab/test/rendering/BarLayoutingInfo.test.ts index b61e56f439..3f40f5a65d 100644 --- a/packages/alphatab/test/rendering/BarLayoutingInfo.test.ts +++ b/packages/alphatab/test/rendering/BarLayoutingInfo.test.ts @@ -198,6 +198,25 @@ describe('BarLayoutingInfoPowerLawFormula', () => { expect(phi).toBeCloseTo(Math.pow(0.5, Math.log2(1.5)), 6); }); + it('minimum stretch force covers post + beat padding + next pre, but not the first pre', () => { + // the first spring's pre-beat width is a fixed offset in front of the springs and + // must not be stretched in; adjacent beats keep the beat content padding apart. + const info = new BarLayoutingInfo(Math.SQRT2, 5); + info.addSpring(0, 960, 0, 3, 4); + info.addSpring(960, 960, 0, 6, 2); + info.finish(); + const k = info.springs.get(0)!.springConstant; + expect(info.minStretchForce).toBeCloseTo((4 + 5 + 6) * k, 10); + }); + + it('minimum stretch force covers post + barline padding for the last beat', () => { + const info = new BarLayoutingInfo(Math.SQRT2, 5, 7); + info.addSpring(0, 960, 0, 3, 4); + info.finish(); + const k = info.springs.get(0)!.springConstant; + expect(info.minStretchForce).toBeCloseTo((4 + 7) * k, 10); + }); + describe('spacingExponentFromRatio clamps to documented range', () => { it('returns log2(r) for r in range', () => { expect(BarLayoutingInfo.spacingExponentFromRatio(1.5)).toBeCloseTo(Math.log2(1.5), 10); diff --git a/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts b/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts index 0e2d48c0be..8a9e641e49 100644 --- a/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts +++ b/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts @@ -619,6 +619,35 @@ describe('EffectsAndAnnotationsTests', () => { it('chord-with-chain', async () => await test('chord-with-chain', ':4 (5.3{h} 5.4 5.5) (7.3{h} 7.4 7.5) (5.3 5.4 5.5) r')); + // Chords: a single slur outside the chord, centered on the outer noteheads (Behind Bars) + // destination chord with accidentals must not move the end anchor + it('chord-slide-accidentals', async () => + await test('chord-slide-accidentals', ':4 (14.1{sl} 11.3{sl}) (16.1 13.3) r r')); + // stems up: slur below the chord + it('chord-stems-up', async () => await test('chord-stems-up', ':4 (3.5{h} 2.6{h}) (5.5 3.6) r r')); + // opposite stem directions: slur ends at the stem end of the destination + it('chord-opposite-stems', async () => + await test('chord-opposite-stems', ':4 (2.3{sl} 2.4{sl}) (14.3 14.4) r r')); + // chains of different length within the chord: one slur over the longest chain + it('chord-different-chain-lengths', async () => + await test('chord-different-chain-lengths', ':8 (5.1{h} 5.3{h}) (7.1{h} 7.3) (8.1 7.3) r r.2')); + // hammer-on and legato slide in one chord: still a single slur + it('chord-mixed-kinds', async () => await test('chord-mixed-kinds', ':4 (5.1{h} 5.3{sl}) (7.1 9.3) r r')); + // slur on the outer notes, tie on the inner notes + it('chord-with-tie', async () => await test('chord-with-tie', ':4 (5.1{h} 5.3) (7.1 -.3) r r')); + // chain continues across a beat played on another string: a single slur + it('chain-across-other-string', async () => + await test('chain-across-other-string', ':8 5.5{h} 9.5{h} 12.5{h} 7.3 9.5{h} 12.5 r.4')); + + // Multi-voice: one slur per voice at the stem end (Behind Bars: double-stemmed writing) + it('multi-voice', async () => + await test('multi-voice', '\\voice :4 5.1{h} 7.1 r.2 | \\voice :4 5.4{h} 7.4 r.2 |')); + it('multi-voice-beamed', async () => + await test( + 'multi-voice-beamed', + '\\voice :8 5.1{h} 7.1 5.1{h} 7.1 r.2 | \\voice :8 5.4{h} 7.4 5.4{h} 7.4 r.2 |' + )); + // Score-only — confirms ScoreSlurGlyph paints labels even // without the tab staff present. it('score-only', async () => diff --git a/packages/alphatab/test/visualTests/issues/BrokenRenders.test.ts b/packages/alphatab/test/visualTests/issues/BrokenRenders.test.ts index 26f0a017a6..743fdc0321 100644 --- a/packages/alphatab/test/visualTests/issues/BrokenRenders.test.ts +++ b/packages/alphatab/test/visualTests/issues/BrokenRenders.test.ts @@ -6,6 +6,25 @@ import { XmlDocument } from '@coderline/alphatab/xml/XmlDocument'; import { ScoreLoader } from '@coderline/alphatab/importer/ScoreLoader'; import type { RenderFinishedEventArgs } from '@coderline/alphatab/rendering/RenderFinishedEventArgs'; import { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer'; +import { type ILogger, Logger } from '@coderline/alphatab/Logger'; +import { LogLevel } from '@coderline/alphatab/LogLevel'; + +/** + * @internal + */ +class WarningCollectingLogger implements ILogger { + public warnings: string[] = []; + + public debug(_category: string, _msg: string, ..._details: unknown[]): void {} + + public warning(_category: string, msg: string, ..._details: unknown[]): void { + this.warnings.push(msg); + } + + public info(_category: string, _msg: string, ..._details: unknown[]): void {} + + public error(_category: string, _msg: string, ..._details: unknown[]): void {} +} describe('BrokenRendersTests', () => { it('let-ring-empty-voice', async () => { @@ -89,6 +108,72 @@ describe('BrokenRendersTests', () => { } }); + // https://github.com/CoderLine/alphaTab/issues/2904 + const squeezedLegatoTex = ` + \\staff {score tabs} + \\tuning e4 b3 g3 d3 a2 e2 + \\ts 4 4 + (14.1{sl} 11.3{sl}).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 + (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 + (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 + (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 | + `; + + it('squeezed-legato-slur', () => { + const settings = new Settings(); + settings.core.engine = 'svg'; + settings.core.enableLazyLoading = false; + + const score = ScoreLoader.loadAlphaTex(squeezedLegatoTex); + + for (const width of [400, 300]) { + const api = new ScoreRenderer(settings); + const results: string[] = []; + api.partialRenderFinished.on(e => { + if (e.renderResult !== null) { + results.push(e.renderResult as string); + } + }); + api.width = width; + api.renderScore(score, [0]); + + expect(results.length).toBeGreaterThan(0); + for (const r of results) { + expect(r.includes('NaN'), `NaN in SVG at width ${width}`).toBe(false); + } + } + }); + + it('squeezed-bar-warning', () => { + const settings = new Settings(); + settings.core.engine = 'svg'; + settings.core.enableLazyLoading = false; + const score = ScoreLoader.loadAlphaTex(squeezedLegatoTex); + + const originalLogger = Logger.log; + const originalLogLevel = Logger.logLevel; + Logger.logLevel = LogLevel.Warning; + try { + const render = (width: number) => { + const logger = new WarningCollectingLogger(); + Logger.log = logger; + const api = new ScoreRenderer(settings); + api.width = width; + api.renderScore(score, [0]); + return logger.warnings.filter(w => w.includes('not fit into the available width')); + }; + + const narrow = render(400); + expect(narrow.length).toBe(1); + expect(narrow[0]).toContain('Bar 1 does not fit'); + + expect(render(1200).length).toBe(0); + } finally { + Logger.log = originalLogger; + Logger.logLevel = originalLogLevel; + } + }); + describe('no-label-padding-left', () => { it('no-padding', async () => { await VisualTestHelper.runVisualTestTex(