diff --git a/packages/alphatab/src/generated/model/BeatCloner.ts b/packages/alphatab/src/generated/model/BeatCloner.ts index ec16d076c..10beecd91 100644 --- a/packages/alphatab/src/generated/model/BeatCloner.ts +++ b/packages/alphatab/src/generated/model/BeatCloner.ts @@ -39,6 +39,8 @@ export class BeatCloner { clone.text = original.text; clone.slashed = original.slashed; clone.deadSlapped = original.deadSlapped; + clone.restDisplayTone = original.restDisplayTone; + clone.restDisplayOctave = original.restDisplayOctave; clone.brushType = original.brushType; clone.brushDuration = original.brushDuration; clone.tupletDenominator = original.tupletDenominator; diff --git a/packages/alphatab/src/generated/model/BeatSerializer.ts b/packages/alphatab/src/generated/model/BeatSerializer.ts index bcc414c25..018184faf 100644 --- a/packages/alphatab/src/generated/model/BeatSerializer.ts +++ b/packages/alphatab/src/generated/model/BeatSerializer.ts @@ -16,6 +16,7 @@ import { Ottavia } from "@coderline/alphatab/model/Ottavia"; import { Duration } from "@coderline/alphatab/model/Duration"; import { Automation } from "@coderline/alphatab/model/Automation"; import { FadeType } from "@coderline/alphatab/model/FadeType"; +import { Tone } from "@coderline/alphatab/model/Tone"; import { BrushType } from "@coderline/alphatab/model/BrushType"; import { WhammyType } from "@coderline/alphatab/model/WhammyType"; import { BendPoint } from "@coderline/alphatab/model/BendPoint"; @@ -64,6 +65,8 @@ export class BeatSerializer { o.set("text", obj.text); o.set("slashed", obj.slashed); o.set("deadslapped", obj.deadSlapped); + o.set("restdisplaytone", obj.restDisplayTone as number | null); + o.set("restdisplayoctave", obj.restDisplayOctave); o.set("brushtype", obj.brushType as number); o.set("brushduration", obj.brushDuration); o.set("tupletdenominator", obj.tupletDenominator); @@ -165,6 +168,12 @@ export class BeatSerializer { case "deadslapped": obj.deadSlapped = v! as boolean; return true; + case "restdisplaytone": + obj.restDisplayTone = JsonHelper.parseEnum(v, Tone) ?? null; + return true; + case "restdisplayoctave": + obj.restDisplayOctave = v! as number; + return true; case "brushtype": obj.brushType = JsonHelper.parseEnum(v, BrushType)!; return true; diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts index 8e84fe7ed..c3db411d2 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts @@ -664,6 +664,7 @@ export class AlphaTex1LanguageDefinitions { ] ], ['txt', [[[[17, 10], 0]]]], + ['restdisplaypitch', [[[[10, 17], 0]]]], [ 'lyrics', [ diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts index 4b38647d0..85055f7ba 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts @@ -70,6 +70,7 @@ import { NoteAccidentalMode } from '@coderline/alphatab/model/NoteAccidentalMode import { NoteOrnament } from '@coderline/alphatab/model/NoteOrnament'; import { Ottavia } from '@coderline/alphatab/model/Ottavia'; import { PercussionMapper } from '@coderline/alphatab/model/PercussionMapper'; +import { Tone } from '@coderline/alphatab/model/Tone'; import { PickStroke } from '@coderline/alphatab/model/PickStroke'; import { BarNumberDisplay, type RenderStylesheet } from '@coderline/alphatab/model/RenderStylesheet'; import { HeaderFooterStyle, Score, ScoreStyle, ScoreSubElement } from '@coderline/alphatab/model/Score'; @@ -1616,6 +1617,25 @@ export class AlphaTex1LanguageHandler implements IAlphaTexLanguageImportHandler case 'txt': beat.text = (p.arguments!.arguments[0] as AlphaTexTextNode).text; return ApplyNodeResult.Applied; + case 'restdisplaypitch': { + const pitchText = (p.arguments!.arguments[0] as AlphaTexTextNode).text.toUpperCase(); + const toneChar = pitchText[0] as keyof typeof Tone; + const octave = parseInt(pitchText.slice(1)); + if (toneChar in Tone && !isNaN(octave)) { + beat.restDisplayTone = Tone[toneChar]; + beat.restDisplayOctave = octave; + } else { + importer.addSemanticDiagnostic({ + code: AlphaTexDiagnosticCode.AT212, + message: `Invalid pitch value '${pitchText}', expected format like 'C5' or 'G4'`, + severity: AlphaTexDiagnosticsSeverity.Error, + start: p.arguments!.arguments[0].start, + end: p.arguments!.arguments[0].end + }); + return ApplyNodeResult.NotAppliedSemanticError; + } + return ApplyNodeResult.Applied; + } case 'lyrics': let lyricsLine = 0; let lyricsText = ''; diff --git a/packages/alphatab/src/model/Beat.ts b/packages/alphatab/src/model/Beat.ts index a0cbf8df0..8208bd8b7 100644 --- a/packages/alphatab/src/model/Beat.ts +++ b/packages/alphatab/src/model/Beat.ts @@ -12,6 +12,7 @@ import type { Fermata } from '@coderline/alphatab/model/Fermata'; import { GraceType } from '@coderline/alphatab/model/GraceType'; import { Note } from '@coderline/alphatab/model/Note'; import { Ottavia } from '@coderline/alphatab/model/Ottavia'; +import { Tone } from '@coderline/alphatab/model/Tone'; import { PickStroke } from '@coderline/alphatab/model/PickStroke'; import type { Slur } from '@coderline/alphatab/model/Slur'; import { TupletGroup } from '@coderline/alphatab/model/TupletGroup'; @@ -424,6 +425,18 @@ export class Beat { */ public deadSlapped: boolean = false; + /** + * Gets or sets the tone of the pitch at which this rest should be displayed. + * Use values from the {@link Tone} enum. Null means use the default position formula. + */ + public restDisplayTone: Tone | null = null; + + /** + * Gets or sets the octave at which this rest should be displayed. + * Only relevant when {@link restDisplayTone} is set. -1 means use the default position formula. + */ + public restDisplayOctave: number = -1; + /** * Gets or sets the brush type applied to the notes of this beat. */ diff --git a/packages/alphatab/src/model/Tone.ts b/packages/alphatab/src/model/Tone.ts new file mode 100644 index 000000000..e1d0e95c0 --- /dev/null +++ b/packages/alphatab/src/model/Tone.ts @@ -0,0 +1,14 @@ +/** + * Represents the diatonic tone (note name) within an octave. + * Used as the value for {@link Beat.restDisplayTone} to specify where a rest should be displayed on the staff. + * @public + */ +export enum Tone { + C = 0, + D = 2, + E = 4, + F = 5, + G = 7, + A = 9, + B = 11 +} diff --git a/packages/alphatab/src/model/_barrel.ts b/packages/alphatab/src/model/_barrel.ts index c5c0e1a6a..c6b017564 100644 --- a/packages/alphatab/src/model/_barrel.ts +++ b/packages/alphatab/src/model/_barrel.ts @@ -42,6 +42,7 @@ export { Note, NoteSubElement, NoteStyle } from '@coderline/alphatab/model/Note' export { NoteAccidentalMode } from '@coderline/alphatab/model/NoteAccidentalMode'; export { NoteOrnament } from '@coderline/alphatab/model/NoteOrnament'; export { Ottavia } from '@coderline/alphatab/model/Ottavia'; +export { Tone } from '@coderline/alphatab/model/Tone'; export { PickStroke } from '@coderline/alphatab/model/PickStroke'; export { PlaybackInformation } from '@coderline/alphatab/model/PlaybackInformation'; export { Rasgueado } from '@coderline/alphatab/model/Rasgueado'; diff --git a/packages/alphatab/src/rendering/glyphs/ScoreBeatGlyph.ts b/packages/alphatab/src/rendering/glyphs/ScoreBeatGlyph.ts index 695fd2478..d687599b8 100644 --- a/packages/alphatab/src/rendering/glyphs/ScoreBeatGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/ScoreBeatGlyph.ts @@ -1,5 +1,6 @@ import { Logger } from '@coderline/alphatab/Logger'; import { AccentuationType } from '@coderline/alphatab/model/AccentuationType'; +import { AccidentalHelper } from '@coderline/alphatab/rendering/utils/AccidentalHelper'; import { BeatSubElement } from '@coderline/alphatab/model/Beat'; import { Duration } from '@coderline/alphatab/model/Duration'; import { GraceType } from '@coderline/alphatab/model/GraceType'; @@ -301,17 +302,20 @@ export class ScoreBeatGlyph extends BeatOnNoteGlyphBase { private _createRestGlyphs() { const sr = this.renderer as ScoreBarRenderer; + const beat = this.container.beat; + const lineCount = this.renderer.bar.staff.standardNotationLineCount; - let steps = Math.ceil((this.renderer.bar.staff.standardNotationLineCount - 1) / 2) * 2; + let steps: number; + if (beat.restDisplayTone !== null && beat.restDisplayOctave !== -1) { + steps = AccidentalHelper.calculateRestDisplaySteps(sr.bar, beat.restDisplayTone, beat.restDisplayOctave); + } else { + steps = Math.ceil((lineCount - 1) / 2) * 2; + } // this positioning is quite strange, for most staff line counts // the whole/rest are aligned as half below the whole rest. // but for staff line count 1 and 3 they are aligned centered on the same line. - if ( - this.container.beat.duration === Duration.Whole && - this.renderer.bar.staff.standardNotationLineCount !== 1 && - this.renderer.bar.staff.standardNotationLineCount !== 3 - ) { + if (beat.duration === Duration.Whole && lineCount !== 1 && lineCount !== 3) { steps -= 2; } diff --git a/packages/alphatab/src/rendering/utils/AccidentalHelper.ts b/packages/alphatab/src/rendering/utils/AccidentalHelper.ts index 23490e441..98150e1ca 100644 --- a/packages/alphatab/src/rendering/utils/AccidentalHelper.ts +++ b/packages/alphatab/src/rendering/utils/AccidentalHelper.ts @@ -5,6 +5,7 @@ import type { Clef } from '@coderline/alphatab/model/Clef'; import { ModelUtils, type ResolvedSpelling } from '@coderline/alphatab/model/ModelUtils'; import type { Note } from '@coderline/alphatab/model/Note'; import { NoteAccidentalMode } from '@coderline/alphatab/model/NoteAccidentalMode'; +import { Ottavia } from '@coderline/alphatab/model/Ottavia'; import { PercussionMapper } from '@coderline/alphatab/model/PercussionMapper'; import type { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; import type { ScoreBarRenderer } from '@coderline/alphatab/rendering/ScoreBarRenderer'; @@ -267,6 +268,28 @@ export class AccidentalHelper { return steps; } + public static calculateRestDisplaySteps(bar: Bar, tone: number, octave: number): number { + + let noteValue = (octave + 1) * 12 + tone; + switch (bar.clefOttava) { + case Ottavia._15ma: + noteValue -= 24; + break; + case Ottavia._8va: + noteValue -= 12; + break; + case Ottavia._8vb: + noteValue += 12; + break; + case Ottavia._15mb: + noteValue += 24; + break; + } + + const spelling = ModelUtils.resolveSpelling(bar.keySignature, noteValue, NoteAccidentalMode.Default); + return AccidentalHelper.calculateNoteSteps(bar.clef, spelling) + 0.5; + } + public getNoteSteps(n: Note): number { return this._appliedScoreSteps.get(n.id)!; } diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-both-set.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-both-set.png new file mode 100644 index 000000000..5965a7203 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-both-set.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-default.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-default.png new file mode 100644 index 000000000..b017acf75 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-main-only-D4-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-main-only-D4-space-3.png new file mode 100644 index 000000000..95d8f8152 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-main-only-D4-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-secondary-only-F3-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-secondary-only-F3-line-1.png new file mode 100644 index 000000000..c971d842a Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-multi-voice-secondary-only-F3-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A3-line-2.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A3-line-2.png new file mode 100644 index 000000000..20c7b2778 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A3-line-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A4-space-5.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A4-space-5.png new file mode 100644 index 000000000..34dcd93a3 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-A4-space-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-B3-space-2.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-B3-space-2.png new file mode 100644 index 000000000..816342fc5 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-B3-space-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-C4-line-3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-C4-line-3.png new file mode 100644 index 000000000..fe61423a1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-C4-line-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-D4-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-D4-space-3.png new file mode 100644 index 000000000..f1ed9a50c Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-D4-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-E4-line-4.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-E4-line-4.png new file mode 100644 index 000000000..ee7e84b06 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-E4-line-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F3-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F3-line-1.png new file mode 100644 index 000000000..733a1dde6 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F3-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F4-space-4.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F4-space-4.png new file mode 100644 index 000000000..f5170a3a5 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-F4-space-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G3-space-1.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G3-space-1.png new file mode 100644 index 000000000..4aaa366e6 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G3-space-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G4-line-5.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G4-line-5.png new file mode 100644 index 000000000..60e84248f Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-pitch-G4-line-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-1-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-1-F3.png new file mode 100644 index 000000000..4fc893b21 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-1-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-2-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-2-F3.png new file mode 100644 index 000000000..ca6dbaec0 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-2-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-3-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-3-F3.png new file mode 100644 index 000000000..c720bf234 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-3-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-4-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-4-F3.png new file mode 100644 index 000000000..a4ffd1414 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-4-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-5-F3.png b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-5-F3.png new file mode 100644 index 000000000..8caaae73e Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/alto/rest-position-staff-lines-5-F3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-both-set.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-both-set.png new file mode 100644 index 000000000..aad6756a6 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-both-set.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-default.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-default.png new file mode 100644 index 000000000..1431f8176 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-main-only-E3-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-main-only-E3-space-3.png new file mode 100644 index 000000000..c03aae037 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-main-only-E3-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-secondary-only-G2-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-secondary-only-G2-line-1.png new file mode 100644 index 000000000..7f715896b Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-multi-voice-secondary-only-G2-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A2-space-1.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A2-space-1.png new file mode 100644 index 000000000..7d730b451 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A2-space-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A3-line-5.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A3-line-5.png new file mode 100644 index 000000000..702a4bce6 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-A3-line-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B2-line-2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B2-line-2.png new file mode 100644 index 000000000..ad380264e Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B2-line-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B3-space-5.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B3-space-5.png new file mode 100644 index 000000000..0ed8163fa Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-B3-space-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-C3-space-2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-C3-space-2.png new file mode 100644 index 000000000..9745dd695 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-C3-space-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-D3-line-3.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-D3-line-3.png new file mode 100644 index 000000000..bfcbba40c Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-D3-line-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-E3-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-E3-space-3.png new file mode 100644 index 000000000..37ebd7c1e Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-E3-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-F3-line-4.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-F3-line-4.png new file mode 100644 index 000000000..2c081beff Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-F3-line-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G2-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G2-line-1.png new file mode 100644 index 000000000..b2797f9c1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G2-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G3-space-4.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G3-space-4.png new file mode 100644 index 000000000..b362121fe Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-pitch-G3-space-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-1-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-1-G2.png new file mode 100644 index 000000000..50604f65d Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-1-G2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-2-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-2-G2.png new file mode 100644 index 000000000..c8212355f Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-2-G2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-3-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-3-G2.png new file mode 100644 index 000000000..128f1e2a0 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-3-G2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-4-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-4-G2.png new file mode 100644 index 000000000..aad3318ab Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-4-G2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-5-G2.png b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-5-G2.png new file mode 100644 index 000000000..ff55bb5c5 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/bass/rest-position-staff-lines-5-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 new file mode 100644 index 000000000..3dab563be Binary files /dev/null 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/tenor/rest-position-multi-voice-both-set.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-both-set.png new file mode 100644 index 000000000..0892e93b9 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-both-set.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-default.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-default.png new file mode 100644 index 000000000..c306d9632 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-main-only-B3-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-main-only-B3-space-3.png new file mode 100644 index 000000000..4e9a85945 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-main-only-B3-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-secondary-only-D3-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-secondary-only-D3-line-1.png new file mode 100644 index 000000000..5ccdeabdd Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-multi-voice-secondary-only-D3-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-A3-line-3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-A3-line-3.png new file mode 100644 index 000000000..d07d191ac Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-A3-line-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-B3-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-B3-space-3.png new file mode 100644 index 000000000..4ce5bc020 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-B3-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-C4-line-4.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-C4-line-4.png new file mode 100644 index 000000000..4511ed091 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-C4-line-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D3-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D3-line-1.png new file mode 100644 index 000000000..3dff966fc Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D3-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D4-space-4.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D4-space-4.png new file mode 100644 index 000000000..e4a834b18 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-D4-space-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E3-space-1.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E3-space-1.png new file mode 100644 index 000000000..59118bc65 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E3-space-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E4-line-5.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E4-line-5.png new file mode 100644 index 000000000..b8884e97a Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-E4-line-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F3-line-2.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F3-line-2.png new file mode 100644 index 000000000..130001201 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F3-line-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F4-space-5.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F4-space-5.png new file mode 100644 index 000000000..d7736d412 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-F4-space-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-G3-space-2.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-G3-space-2.png new file mode 100644 index 000000000..44b3df4a1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-pitch-G3-space-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-1-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-1-D3.png new file mode 100644 index 000000000..903a36cbd Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-1-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-2-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-2-D3.png new file mode 100644 index 000000000..4e1e30157 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-2-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-3-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-3-D3.png new file mode 100644 index 000000000..930f60c87 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-3-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-4-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-4-D3.png new file mode 100644 index 000000000..5febfb648 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-4-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-5-D3.png b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-5-D3.png new file mode 100644 index 000000000..47e42ff48 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/tenor/rest-position-staff-lines-5-D3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-both-set.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-both-set.png new file mode 100644 index 000000000..5e9a6a30d Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-both-set.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-default.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-default.png new file mode 100644 index 000000000..4eae9e566 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-default.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-main-only-C5-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-main-only-C5-space-3.png new file mode 100644 index 000000000..398fbb1ad Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-main-only-C5-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-secondary-only-E4-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-secondary-only-E4-line-1.png new file mode 100644 index 000000000..aae357d88 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-multi-voice-secondary-only-E4-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-A4-space-2.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-A4-space-2.png new file mode 100644 index 000000000..62df81dd1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-A4-space-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-B4-line-3.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-B4-line-3.png new file mode 100644 index 000000000..c621dcd60 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-B4-line-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-C5-space-3.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-C5-space-3.png new file mode 100644 index 000000000..36f78b9e7 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-C5-space-3.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-D5-line-4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-D5-line-4.png new file mode 100644 index 000000000..7d611ddde Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-D5-line-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E4-line-1.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E4-line-1.png new file mode 100644 index 000000000..a920b65f5 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E4-line-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E5-space-4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E5-space-4.png new file mode 100644 index 000000000..8e5a2be66 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-E5-space-4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F4-space-1.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F4-space-1.png new file mode 100644 index 000000000..c314577b6 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F4-space-1.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F5-line-5.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F5-line-5.png new file mode 100644 index 000000000..0bb26bdbe Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-F5-line-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G4-line-2.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G4-line-2.png new file mode 100644 index 000000000..2d5821133 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G4-line-2.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G5-space-5.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G5-space-5.png new file mode 100644 index 000000000..043c5ae2b Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-pitch-G5-space-5.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-1-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-1-E4.png new file mode 100644 index 000000000..6b87bdf24 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-1-E4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-2-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-2-E4.png new file mode 100644 index 000000000..d896126f1 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-2-E4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-3-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-3-E4.png new file mode 100644 index 000000000..eb21ceacd Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-3-E4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-4-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-4-E4.png new file mode 100644 index 000000000..e07298237 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-4-E4.png differ diff --git a/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-5-E4.png b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-5-E4.png new file mode 100644 index 000000000..9613f5621 Binary files /dev/null and b/packages/alphatab/test-data/visual-tests/rest-position/treble/rest-position-staff-lines-5-E4.png differ diff --git a/packages/alphatab/test/visualTests/features/RestPosition.test.ts b/packages/alphatab/test/visualTests/features/RestPosition.test.ts new file mode 100644 index 000000000..03ba168e0 --- /dev/null +++ b/packages/alphatab/test/visualTests/features/RestPosition.test.ts @@ -0,0 +1,184 @@ +import { describe, it } from 'vitest'; +import { VisualTestHelper } from 'test/visualTests/VisualTestHelper'; + +type ClefData = { + tex: string; + filler: string; + positions: [string, string][]; + primaryFiller: string; + secondaryFiller: string; + multiVoicePrimary: [string, string]; + multiVoiceSecondary: [string, string]; +}; + +// Staff positions from bottom to top for each clef: [pitch, label] +const clefs: Record = { + treble: { + tex: '', + filler: 'b4', + positions: [ + ['E4', 'Line 1'], + ['F4', 'Space 1'], + ['G4', 'Line 2'], + ['A4', 'Space 2'], + ['B4', 'Line 3'], + ['C5', 'Space 3'], + ['D5', 'Line 4'], + ['E5', 'Space 4'], + ['F5', 'Line 5'], + ['G5', 'Space 5'], + ], + primaryFiller: 'e5', + secondaryFiller: 'e4', + multiVoicePrimary: ['C5', 'Space 3'], + multiVoiceSecondary: ['E4', 'Line 1'], + }, + // Bass clef (F4): G2=Line1 .. A3=Line5 + bass: { + tex: '\\clef bass', + filler: 'd3', + positions: [ + ['G2', 'Line 1'], + ['A2', 'Space 1'], + ['B2', 'Line 2'], + ['C3', 'Space 2'], + ['D3', 'Line 3'], + ['E3', 'Space 3'], + ['F3', 'Line 4'], + ['G3', 'Space 4'], + ['A3', 'Line 5'], + ['B3', 'Space 5'], + ], + primaryFiller: 'a3', + secondaryFiller: 'g2', + multiVoicePrimary: ['E3', 'Space 3'], + multiVoiceSecondary: ['G2', 'Line 1'], + }, + // Alto clef (C3 in alphaTab = C clef on line 3): F3=Line1 .. G4=Line5 + alto: { + tex: '\\clef alto', + filler: 'c4', + positions: [ + ['F3', 'Line 1'], + ['G3', 'Space 1'], + ['A3', 'Line 2'], + ['B3', 'Space 2'], + ['C4', 'Line 3'], + ['D4', 'Space 3'], + ['E4', 'Line 4'], + ['F4', 'Space 4'], + ['G4', 'Line 5'], + ['A4', 'Space 5'], + ], + primaryFiller: 'g4', + secondaryFiller: 'f3', + multiVoicePrimary: ['D4', 'Space 3'], + multiVoiceSecondary: ['F3', 'Line 1'], + }, + // Tenor clef (C4 in alphaTab = C clef on line 4): D3=Line1 .. E4=Line5 + tenor: { + tex: '\\clef tenor', + filler: 'a3', + positions: [ + ['D3', 'Line 1'], + ['E3', 'Space 1'], + ['F3', 'Line 2'], + ['G3', 'Space 2'], + ['A3', 'Line 3'], + ['B3', 'Space 3'], + ['C4', 'Line 4'], + ['D4', 'Space 4'], + ['E4', 'Line 5'], + ['F4', 'Space 5'], + ], + primaryFiller: 'e4', + secondaryFiller: 'd3', + multiVoicePrimary: ['B3', 'Space 3'], + multiVoiceSecondary: ['D3', 'Line 1'], + }, +}; + +const restBeat = (pitch: string, label: string, duration: string, showLabel: boolean = true) => + showLabel + ? `r.${duration}{restDisplayPitch ${pitch} txt "${label}"}` + : `r.${duration}{restDisplayPitch ${pitch}}`; + +const clefPrimaryDurations = (tex: string, filler: string, pitch: string, label: string) => { + const prefix = tex ? `${tex} ` : ''; + return `${prefix}${restBeat(pitch, label, '1')} | ${restBeat(pitch, label, '2')} ${filler}.2 | ${restBeat(pitch, label, '4')} ${filler}.4 *3 | ${restBeat(pitch, label, '8')} ${filler}.8 *7 | ${restBeat(pitch, label, '16')} ${filler}.16 *15 | ${restBeat(pitch, label, '32')} ${filler}.32 *31`; +}; + +const voicePrimaryDurations = (filler: string, pitch: string, label: string) => + `${restBeat(pitch, label, '1')} | ${restBeat(pitch, label, '2')} ${filler}.2 | ${restBeat(pitch, label, '4')} ${filler}.4 *3 | ${restBeat(pitch, label, '8')} ${filler}.8 *7 | ${restBeat(pitch, label, '16')} ${filler}.16 *15 | ${restBeat(pitch, label, '32')} ${filler}.32 *31`; + +const voiceSecondaryDurations = (filler: string, pitch: string, label: string) => + `${filler}.1 | ${filler}.2 ${restBeat(pitch, label, '2')} | ${filler}.4 *3 ${restBeat(pitch, label, '4')} | ${filler}.8 *7 ${restBeat(pitch, label, '8')} | ${filler}.16 *15 ${restBeat(pitch, label, '16')} | ${filler}.32 *31 ${restBeat(pitch, label, '32')}`; + +const voiceDefaultPrimary = (filler: string) => + `r.1 | r.2 ${filler}.2 | r.4 ${filler}.4 *3 | r.8 ${filler}.8 *7 | r.16 ${filler}.16 *15 | r.32 ${filler}.32 *31`; + +const voiceDefaultSecondary = (filler: string) => + `${filler}.1 | ${filler}.2 r.2 | ${filler}.4 *3 r.4 | ${filler}.8 *7 r.8 | ${filler}.16 *15 r.16 | ${filler}.32 *31 r.32`; + +describe('RestPositionTests', () => { + it('rest-position-default', async () => { + await VisualTestHelper.runVisualTestTex( + `r.1 | r.2 e5.2 | r.4 e5.4 *3 | r.8 e5.8 *7 | r.16 e5.16 *15 | r.32 e5.32 *31`, + 'test-data/visual-tests/rest-position/rest-position-default.png' + ); + }); + + for (const [clef, { tex, filler, positions, primaryFiller, secondaryFiller, multiVoicePrimary, multiVoiceSecondary }] of Object.entries(clefs)) { + describe(`rest-position-${clef}`, () => { + const prefix = tex ? `${tex} ` : ''; + + for (const [pitch, label] of positions) { + it(`position-${pitch} - ${label}`, async () => { + await VisualTestHelper.runVisualTestTex( + clefPrimaryDurations(tex, filler, pitch, label), + `test-data/visual-tests/rest-position/${clef}/rest-position-pitch-${pitch}-${label.toLowerCase().replace(' ', '-')}.png` + ); + }); + } + + it('multi-voice-default', async () => { + await VisualTestHelper.runVisualTestTex( + `${prefix}\\voice ${voiceDefaultPrimary(primaryFiller)} \\voice ${voiceDefaultSecondary(secondaryFiller)}`, + `test-data/visual-tests/rest-position/${clef}/rest-position-multi-voice-default.png` + ); + }); + + it('multi-voice-both-set', async () => { + await VisualTestHelper.runVisualTestTex( + `${prefix}\\voice ${voicePrimaryDurations(primaryFiller, ...multiVoicePrimary)} \\voice ${voiceSecondaryDurations(secondaryFiller, ...multiVoiceSecondary)}`, + `test-data/visual-tests/rest-position/${clef}/rest-position-multi-voice-both-set.png` + ); + }); + + it('multi-voice-main-only', async () => { + await VisualTestHelper.runVisualTestTex( + `${prefix}\\voice ${voicePrimaryDurations(primaryFiller, ...multiVoicePrimary)} \\voice ${voiceDefaultSecondary(secondaryFiller)}`, + `test-data/visual-tests/rest-position/${clef}/rest-position-multi-voice-main-only-${multiVoicePrimary[0]}-${multiVoicePrimary[1].toLowerCase().replace(' ', '-')}.png` + ); + }); + + it('multi-voice-secondary-only', async () => { + await VisualTestHelper.runVisualTestTex( + `${prefix}\\voice ${voiceDefaultPrimary(primaryFiller)} \\voice ${voiceSecondaryDurations(secondaryFiller, ...multiVoiceSecondary)}`, + `test-data/visual-tests/rest-position/${clef}/rest-position-multi-voice-secondary-only-${multiVoiceSecondary[0]}-${multiVoiceSecondary[1].toLowerCase().replace(' ', '-')}.png` + ); + }); + + describe('staff-lines', () => { + for (const lineCount of [1, 2, 3, 4, 5]) { + it(`linecount-${lineCount}`, async () => { + await VisualTestHelper.runVisualTestTex( + `${prefix}\\staff { score ${lineCount} } ${restBeat(multiVoiceSecondary[0], multiVoiceSecondary[1], '1', false)} | ${restBeat(multiVoiceSecondary[0], multiVoiceSecondary[1], '2', false)} ${secondaryFiller}.2 | ${restBeat(multiVoiceSecondary[0], multiVoiceSecondary[1], '4', false)} ${secondaryFiller}.4 *3`, + `test-data/visual-tests/rest-position/${clef}/rest-position-staff-lines-${lineCount}-${multiVoiceSecondary[0]}.png` + ); + }); + } + }); + }); + } +});