From 8abe8f37c41198dadd7a142dd6912a0e54a2d3ae Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Mon, 15 Dec 2025 18:15:13 +0100 Subject: [PATCH 1/2] feat: in-score chord diagram model extensions --- .../model/RenderStylesheetSerializer.ts | 4 + .../alphatab/src/importer/BinaryStylesheet.ts | 8 + .../alphatab/src/importer/MusicXmlImporter.ts | 19 +- .../alphaTex/AlphaTex1LanguageDefinitions.ts | 1123 +++++++++++++---- .../alphaTex/AlphaTex1LanguageHandler.ts | 10 + .../alphatab/src/model/RenderStylesheet.ts | 5 + .../guitarpro8/show-diagrams-in-score.gp | Bin 0 -> 12692 bytes .../test/importer/AlphaTexImporter.test.ts | 23 + .../test/importer/Gp8Importer.test.ts | 8 + packages/alphatex/src/definitions.ts | 4 +- .../metadata/score/chordDiagramsInScore.ts | 33 + 11 files changed, 978 insertions(+), 259 deletions(-) create mode 100644 packages/alphatab/test-data/guitarpro8/show-diagrams-in-score.gp create mode 100644 packages/alphatex/src/metadata/score/chordDiagramsInScore.ts diff --git a/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts b/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts index c111ed9ef..4ac08c97c 100644 --- a/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts +++ b/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts @@ -43,6 +43,7 @@ export class RenderStylesheetSerializer { m.set(k.toString(), v); } } + o.set("globaldisplaychorddiagramsinscore", obj.globalDisplayChordDiagramsInScore); o.set("singletracktracknamepolicy", obj.singleTrackTrackNamePolicy as number); o.set("multitracktracknamepolicy", obj.multiTrackTrackNamePolicy as number); o.set("firstsystemtracknamemode", obj.firstSystemTrackNameMode as number); @@ -89,6 +90,9 @@ export class RenderStylesheetSerializer { obj.perTrackChordDiagramsOnTop!.set(Number.parseInt(k), v as boolean); }); return true; + case "globaldisplaychorddiagramsinscore": + obj.globalDisplayChordDiagramsInScore = v! as boolean; + return true; case "singletracktracknamepolicy": obj.singleTrackTrackNamePolicy = JsonHelper.parseEnum(v, TrackNamePolicy)!; return true; diff --git a/packages/alphatab/src/importer/BinaryStylesheet.ts b/packages/alphatab/src/importer/BinaryStylesheet.ts index 8fe7370c0..ace358467 100644 --- a/packages/alphatab/src/importer/BinaryStylesheet.ts +++ b/packages/alphatab/src/importer/BinaryStylesheet.ts @@ -150,6 +150,9 @@ export class BinaryStylesheet { case 'Global/DrawChords': score.stylesheet.globalDisplayChordDiagramsOnTop = value as boolean; break; + case 'System/drawChordInScore': + score.stylesheet.globalDisplayChordDiagramsInScore = value as boolean; + break; case 'System/showTrackNameSingle': if (!(value as boolean)) { score.stylesheet.singleTrackTrackNamePolicy = TrackNamePolicy.Hidden; @@ -460,6 +463,11 @@ export class BinaryStylesheet { score.stylesheet.globalDisplayChordDiagramsOnTop, DataType.Boolean ); + binaryStylesheet.addValue( + 'System/drawChordInScore', + score.stylesheet.globalDisplayChordDiagramsInScore, + DataType.Boolean + ); switch (score.stylesheet.singleTrackTrackNamePolicy) { case TrackNamePolicy.Hidden: diff --git a/packages/alphatab/src/importer/MusicXmlImporter.ts b/packages/alphatab/src/importer/MusicXmlImporter.ts index 83add730d..51c1ef281 100644 --- a/packages/alphatab/src/importer/MusicXmlImporter.ts +++ b/packages/alphatab/src/importer/MusicXmlImporter.ts @@ -1362,6 +1362,15 @@ export class MusicXmlImporter extends ScoreImporter { chord.name += degreeParenthesis ? `(${degree})` : degree; } + if (element.getAttribute('print-frame', 'no') === 'yes') { + chord.showDiagram = true; + this._score.stylesheet.globalDisplayChordDiagramsInScore = true; + } + + if (element.getAttribute('print-object', 'yes') === 'yes') { + chord.showDiagram = true; + } + if (this._nextBeatChord === null) { this._nextBeatChord = chord; } @@ -2703,8 +2712,10 @@ export class MusicXmlImporter extends ScoreImporter { } private static readonly _b4Value = 71; - private _estimateBeamDirection(note: Note): BeamDirection { - return note.calculateRealValue(false, false) < MusicXmlImporter._b4Value ? BeamDirection.Down : BeamDirection.Up; + private _estimateBeamDirection(note: Note): BeamDirection { + return note.calculateRealValue(false, false) < MusicXmlImporter._b4Value + ? BeamDirection.Down + : BeamDirection.Up; } private _parseNoteHead(element: XmlNode, note: Note, beatDuration: Duration, beamDirection: BeamDirection) { @@ -3297,7 +3308,7 @@ export class MusicXmlImporter extends ScoreImporter { } } - private _parseArpeggiate(element: XmlNode, beat: Beat) { + private _parseArpeggiate(element: XmlNode, beat: Beat) { const direction = element.getAttribute('direction', 'down'); switch (direction) { case 'down': @@ -3607,7 +3618,7 @@ export class MusicXmlImporter extends ScoreImporter { } } - private _parseTied(element: XmlNode, note: Note, staff: Staff): void { + private _parseTied(element: XmlNode, note: Note, staff: Staff): void { const type = element.getAttribute('type'); const number = element.getAttribute('number', ''); diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts index 273e26bed..1461dd28e 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts @@ -3,19 +3,11 @@ import type { ArgumentListParseTypesMode } from '@coderline/alphatab/importer/al /** * @target web */ -type SimpleAlphaTexParameterDefinition = [ - AlphaTexNodeType[], - ArgumentListParseTypesMode -] | [ - AlphaTexNodeType[], - ArgumentListParseTypesMode, - string[] -] | [ - AlphaTexNodeType[], - ArgumentListParseTypesMode, - string[] | null, - string[] -] | null; +type SimpleAlphaTexParameterDefinition = + | [AlphaTexNodeType[], ArgumentListParseTypesMode] + | [AlphaTexNodeType[], ArgumentListParseTypesMode, string[]] + | [AlphaTexNodeType[], ArgumentListParseTypesMode, string[] | null, string[]] + | null; /** * @record * @internal @@ -45,41 +37,38 @@ export class AlphaTex1LanguageDefinitions { return { expectedTypes: new Set(simple[0]), parseMode: simple[1], - allowedValues: simple.length > 2 && simple[2] && simple[2]!.length > 0 ? new Set(simple[2]!) : undefined, - reservedIdentifiers: simple.length > 3 && simple[3] && simple[3]!.length > 0 ? new Set(simple[3]!) : undefined + allowedValues: + simple.length > 2 && simple[2] && simple[2]!.length > 0 ? new Set(simple[2]!) : undefined, + reservedIdentifiers: + simple.length > 3 && simple[3] && simple[3]!.length > 0 ? new Set(simple[3]!) : undefined }; } - private static _simple(signature: (SimpleAlphaTexParameterDefinition | null)[][] | null): AlphaTexSignatureDefinition[] | null { + private static _simple( + signature: (SimpleAlphaTexParameterDefinition | null)[][] | null + ): AlphaTexSignatureDefinition[] | null { if (signature == null) { return null; } - return signature.map(s => ({ - isStrict: s.length > 0 && s[0] === null, - parameters: s.map(AlphaTex1LanguageDefinitions._param).filter(p => p !== null) - }) as AlphaTexSignatureDefinition); + return signature.map( + s => + ({ + isStrict: s.length > 0 && s[0] === null, + parameters: s.map(AlphaTex1LanguageDefinitions._param).filter(p => p !== null) + }) as AlphaTexSignatureDefinition + ); } - private static _metaProps(props: [ - string, - [ - string, - SimpleAlphaTexParameterDefinition[][] | null - ][] | null - ][]) { - return new Map(props.map(p => [ - p[0], - p[1] === null ? null : new Map(p[1]!.map(p => [p[0], AlphaTex1LanguageDefinitions._simple(p[1])])) - ])); + private static _metaProps(props: [string, [string, SimpleAlphaTexParameterDefinition[][] | null][] | null][]) { + return new Map( + props.map(p => [ + p[0], + p[1] === null ? null : new Map(p[1]!.map(p => [p[0], AlphaTex1LanguageDefinitions._simple(p[1])])) + ]) + ); } - private static _props(props: [ - string, - SimpleAlphaTexParameterDefinition[][] | null - ][]) { + private static _props(props: [string, SimpleAlphaTexParameterDefinition[][] | null][]) { return new Map(props.map(p => [p[0], AlphaTex1LanguageDefinitions._simple(p[1])])); } - private static _signatures(signatures: [ - string, - SimpleAlphaTexParameterDefinition[][] | null - ][]) { + private static _signatures(signatures: [string, SimpleAlphaTexParameterDefinition[][] | null][]) { return new Map(signatures.map(s => [s[0], AlphaTex1LanguageDefinitions._simple(s[1])])); } // The following definitions age auto-generated from the central definitions in @@ -87,138 +76,517 @@ export class AlphaTex1LanguageDefinitions { // to reduce code size, the parameter types are specified as number values and then // translated inside AlphaTex1LanguageDefinitions._signatures during runtime public static readonly scoreMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([ - ["title", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["subtitle", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["artist", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["album", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["words", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["music", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["wordsandmusic", [[[[17], 0], [[10, 17], 1, ["left", "center", "right"]]]]], - ["copyright", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["copyright2", [[[[17], 0], [[10, 17], 1, ["left", "center", "right"]]]]], - ["instructions", [[[[17, 10], 0]]]], - ["notices", [[[[17, 10], 0]]]], - ["tab", [[[[17, 10], 0], [[17], 1], [[10, 17], 1, ["left", "center", "right"]]]]], - ["systemslayout", [[[[16], 5]]]], - ["defaultsystemslayout", [[[[16], 0]]]], - ["showdynamics", null], - ["hidedynamics", null], - ["usesystemsignseparator", null], - ["multibarrest", null], - ["bracketextendmode", [[[[10, 17], 0, ["nobrackets", "groupstaves", "groupsimilarinstruments"]]]]], - ["singletracktracknamepolicy", [[[[10, 17], 0, ["hidden", "firstsystem", "allsystems"]]]]], - ["multitracktracknamepolicy", [[[[10, 17], 0, ["hidden", "firstsystem", "allsystems"]]]]], - ["firstsystemtracknamemode", [[[[10, 17], 0, ["fullname", "shortname"]]]]], - ["othersystemstracknamemode", [[[[10, 17], 0, ["fullname", "shortname"]]]]], - ["firstsystemtracknameorientation", [[[[10, 17], 0, ["horizontal", "vertical"]]]]], - ["othersystemstracknameorientation", [[[[10, 17], 0, ["horizontal", "vertical"]]]]], - ["extendbarlines", null] + [ + 'title', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'subtitle', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'artist', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'album', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'words', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'music', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'wordsandmusic', + [ + [ + [[17], 0], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'copyright', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + [ + 'copyright2', + [ + [ + [[17], 0], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + ['instructions', [[[[17, 10], 0]]]], + ['notices', [[[[17, 10], 0]]]], + [ + 'tab', + [ + [ + [[17, 10], 0], + [[17], 1], + [[10, 17], 1, ['left', 'center', 'right']] + ] + ] + ], + ['systemslayout', [[[[16], 5]]]], + ['defaultsystemslayout', [[[[16], 0]]]], + ['showdynamics', null], + ['hidedynamics', null], + ['usesystemsignseparator', null], + ['multibarrest', null], + ['bracketextendmode', [[[[10, 17], 0, ['nobrackets', 'groupstaves', 'groupsimilarinstruments']]]]], + ['singletracktracknamepolicy', [[[[10, 17], 0, ['hidden', 'firstsystem', 'allsystems']]]]], + ['multitracktracknamepolicy', [[[[10, 17], 0, ['hidden', 'firstsystem', 'allsystems']]]]], + ['firstsystemtracknamemode', [[[[10, 17], 0, ['fullname', 'shortname']]]]], + ['othersystemstracknamemode', [[[[10, 17], 0, ['fullname', 'shortname']]]]], + ['firstsystemtracknameorientation', [[[[10, 17], 0, ['horizontal', 'vertical']]]]], + ['othersystemstracknameorientation', [[[[10, 17], 0, ['horizontal', 'vertical']]]]], + ['extendbarlines', null], + ['chorddiagramsinscore', [[[[10], 1, ['true', 'false']]]]] ]); public static readonly staffMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([ - ["tuning", [[[[10, 17], 0, ["piano", "none", "voice"]]], [[[10, 17], 5]]]], - ["chord", [[[[17, 10], 0], [[10, 17, 16], 5]]]], - ["capo", [[[[16], 0]]]], - ["lyrics", [[[[17], 0]], [[[16], 0], [[17], 0]]]], - ["articulation", [[[[10], 0, ["defaults"]]], [[[17, 10], 0], [[16], 0]]]], - ["displaytranspose", [[[[16], 0]]]], - ["transpose", [[[[16], 0]]]], - ["instrument", [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ["percussion"]]]]] + ['tuning', [[[[10, 17], 0, ['piano', 'none', 'voice']]], [[[10, 17], 5]]]], + [ + 'chord', + [ + [ + [[17, 10], 0], + [[10, 17, 16], 5] + ] + ] + ], + ['capo', [[[[16], 0]]]], + [ + 'lyrics', + [ + [[[17], 0]], + [ + [[16], 0], + [[17], 0] + ] + ] + ], + [ + 'articulation', + [ + [[[10], 0, ['defaults']]], + [ + [[17, 10], 0], + [[16], 0] + ] + ] + ], + ['displaytranspose', [[[[16], 0]]]], + ['transpose', [[[[16], 0]]]], + ['instrument', [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ['percussion']]]]] ]); public static readonly structuralMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([ - ["track", [[[[17], 1], [[17], 1]]]], - ["staff", null], - ["voice", null] + [ + 'track', + [ + [ + [[17], 1], + [[17], 1] + ] + ] + ], + ['staff', null], + ['voice', null] ]); public static readonly barMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([ - ["ts", [[[[10, 17], 0, ["common"]]], [[[16], 0], [[16], 0]]]], - ["ro", null], - ["rc", [[[[16], 0]]]], - ["ae", [[[[16, 13], 4]]]], - ["ks", [[[[10, 17], 0, ["cb", "gb", "db", "ab", "eb", "bb", "f", "c", "g", "d", "a", "e", "b", "f#", "c#", "cbmajor", "abminor", "gbmajor", "ebminor", "dbmajor", "bbminor", "abmajor", "fminor", "ebmajor", "cminor", "bbmajor", "gminor", "fmajor", "dminor", "cmajor", "aminor", "gmajor", "eminor", "dmajor", "bminor", "amajor", "f#minor", "emajor", "c#minor", "bmajor", "g#minor", "f#major", "d#minor", "f#", "c#major", "a#minor", "c#"]]]]], - ["clef", [[[[10, 16, 17], 0, ["neutral", "c3", "c4", "f4", "g2", "n", "alto", "tenor", "bass", "treble"]]]]], - ["ottava", [[[[10, 17], 0, ["15ma", "8va", "regular", "8vb", "15mb", "15ma", "8va", "8vb", "15mb"]]]]], - ["tempo", [[[[16], 2], [[17], 1]], [null, [[16], 2], [[17], 0], [[16], 1], [[10], 1, ["hide"]]]]], - ["tf", [[[[10, 16, 17], 0, ["none", "triplet16th", "triplet8th", "dotted16th", "dotted8th", "scottish16th", "scottish8th", "none", "no", "notripletfeel", "t16", "triplet-16th", "t8", "triplet-8th", "d16", "dotted-16th", "d8", "dotted-8th", "s16", "scottish-16th", "s8", "scottish-8th"]]]]], - ["ac", null], - ["section", [[[[17, 10], 0]], [[[17, 10], 0], [[17, 10], 0, null, ["x", "-", "r"]]]]], - ["jump", [[[[10, 17], 0, ["fine", "segno", "segnosegno", "coda", "doublecoda", "dacapo", "dacapoalcoda", "dacapoaldoublecoda", "dacapoalfine", "dalsegno", "dalsegnoalcoda", "dalsegnoaldoublecoda", "dalsegnoalfine", "dalsegnosegno", "dalsegnosegnoalcoda", "dalsegnosegnoaldoublecoda", "dalsegnosegnoalfine", "dacoda", "dadoublecoda"]]]]], - ["ft", null], - ["simile", [[[[10, 17], 0, ["none", "simple", "firstofdouble", "secondofdouble"]]]]], - ["barlineleft", [[[[10, 17], 0, ["automatic", "dashed", "dotted", "heavy", "heavyheavy", "heavylight", "lightheavy", "lightlight", "none", "regular", "short", "tick"]]]]], - ["barlineright", [[[[10, 17], 0, ["automatic", "dashed", "dotted", "heavy", "heavyheavy", "heavylight", "lightheavy", "lightlight", "none", "regular", "short", "tick"]]]]], - ["scale", [[[[16], 2]]]], - ["width", [[[[16], 2]]]], - ["sync", [[[[16], 0], [[16], 0], [[16], 0], [[16], 3]]]], - ["accidentals", [[[[10, 17], 0, ["auto", "explicit"]]]]], - ["spd", [[[[16], 2]]]], - ["sph", [[[[16], 2]]]], - ["spu", [[[[16], 2]]]], - ["db", null], - ["voicemode", [[[[10, 17], 0, ["staffwise", "barwise"]]]]] + [ + 'ts', + [ + [[[10, 17], 0, ['common']]], + [ + [[16], 0], + [[16], 0] + ] + ] + ], + ['ro', null], + ['rc', [[[[16], 0]]]], + ['ae', [[[[16, 13], 4]]]], + [ + 'ks', + [ + [ + [ + [10, 17], + 0, + [ + 'cb', + 'gb', + 'db', + 'ab', + 'eb', + 'bb', + 'f', + 'c', + 'g', + 'd', + 'a', + 'e', + 'b', + 'f#', + 'c#', + 'cbmajor', + 'abminor', + 'gbmajor', + 'ebminor', + 'dbmajor', + 'bbminor', + 'abmajor', + 'fminor', + 'ebmajor', + 'cminor', + 'bbmajor', + 'gminor', + 'fmajor', + 'dminor', + 'cmajor', + 'aminor', + 'gmajor', + 'eminor', + 'dmajor', + 'bminor', + 'amajor', + 'f#minor', + 'emajor', + 'c#minor', + 'bmajor', + 'g#minor', + 'f#major', + 'd#minor', + 'f#', + 'c#major', + 'a#minor', + 'c#' + ] + ] + ] + ] + ], + ['clef', [[[[10, 16, 17], 0, ['neutral', 'c3', 'c4', 'f4', 'g2', 'n', 'alto', 'tenor', 'bass', 'treble']]]]], + ['ottava', [[[[10, 17], 0, ['15ma', '8va', 'regular', '8vb', '15mb', '15ma', '8va', '8vb', '15mb']]]]], + [ + 'tempo', + [ + [ + [[16], 2], + [[17], 1] + ], + [null, [[16], 2], [[17], 0], [[16], 1], [[10], 1, ['hide']]] + ] + ], + [ + 'tf', + [ + [ + [ + [10, 16, 17], + 0, + [ + 'none', + 'triplet16th', + 'triplet8th', + 'dotted16th', + 'dotted8th', + 'scottish16th', + 'scottish8th', + 'none', + 'no', + 'notripletfeel', + 't16', + 'triplet-16th', + 't8', + 'triplet-8th', + 'd16', + 'dotted-16th', + 'd8', + 'dotted-8th', + 's16', + 'scottish-16th', + 's8', + 'scottish-8th' + ] + ] + ] + ] + ], + ['ac', null], + [ + 'section', + [ + [[[17, 10], 0]], + [ + [[17, 10], 0], + [[17, 10], 0, null, ['x', '-', 'r']] + ] + ] + ], + [ + 'jump', + [ + [ + [ + [10, 17], + 0, + [ + 'fine', + 'segno', + 'segnosegno', + 'coda', + 'doublecoda', + 'dacapo', + 'dacapoalcoda', + 'dacapoaldoublecoda', + 'dacapoalfine', + 'dalsegno', + 'dalsegnoalcoda', + 'dalsegnoaldoublecoda', + 'dalsegnoalfine', + 'dalsegnosegno', + 'dalsegnosegnoalcoda', + 'dalsegnosegnoaldoublecoda', + 'dalsegnosegnoalfine', + 'dacoda', + 'dadoublecoda' + ] + ] + ] + ] + ], + ['ft', null], + ['simile', [[[[10, 17], 0, ['none', 'simple', 'firstofdouble', 'secondofdouble']]]]], + [ + 'barlineleft', + [ + [ + [ + [10, 17], + 0, + [ + 'automatic', + 'dashed', + 'dotted', + 'heavy', + 'heavyheavy', + 'heavylight', + 'lightheavy', + 'lightlight', + 'none', + 'regular', + 'short', + 'tick' + ] + ] + ] + ] + ], + [ + 'barlineright', + [ + [ + [ + [10, 17], + 0, + [ + 'automatic', + 'dashed', + 'dotted', + 'heavy', + 'heavyheavy', + 'heavylight', + 'lightheavy', + 'lightlight', + 'none', + 'regular', + 'short', + 'tick' + ] + ] + ] + ] + ], + ['scale', [[[[16], 2]]]], + ['width', [[[[16], 2]]]], + [ + 'sync', + [ + [ + [[16], 0], + [[16], 0], + [[16], 0], + [[16], 3] + ] + ] + ], + ['accidentals', [[[[10, 17], 0, ['auto', 'explicit']]]]], + ['spd', [[[[16], 2]]]], + ['sph', [[[[16], 2]]]], + ['spu', [[[[16], 2]]]], + ['db', null], + ['voicemode', [[[[10, 17], 0, ['staffwise', 'barwise']]]]] ]); public static readonly metaDataProperties = AlphaTex1LanguageDefinitions._metaProps([ - ["track", [["color", [[[[17], 0]]]], ["systemslayout", [[[[16], 5]]]], ["defaultsystemslayout", [[[[16], 0]]]], ["solo", null], ["mute", null], ["volume", [[[[16], 0]]]], ["balance", [[[[16], 0]]]], ["instrument", [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ["percussion"]]]]], ["bank", [[[[16], 0]]]], ["multibarrest", null]]], - ["staff", [["score", [[[[16], 1]]]], ["tabs", null], ["slash", null], ["numbered", null]]], - ["voice", null], - ["title", null], - ["subtitle", null], - ["artist", null], - ["album", null], - ["words", null], - ["music", null], - ["wordsandmusic", null], - ["copyright", null], - ["copyright2", null], - ["instructions", null], - ["notices", null], - ["tab", null], - ["systemslayout", null], - ["defaultsystemslayout", null], - ["showdynamics", null], - ["hidedynamics", null], - ["usesystemsignseparator", null], - ["multibarrest", null], - ["bracketextendmode", null], - ["singletracktracknamepolicy", null], - ["multitracktracknamepolicy", null], - ["firstsystemtracknamemode", null], - ["othersystemstracknamemode", null], - ["firstsystemtracknameorientation", null], - ["othersystemstracknameorientation", null], - ["extendbarlines", null], - ["tuning", [["hide", null], ["label", [[[[17], 0]]]]]], - ["chord", [["firstfret", [[[[16], 0]]]], ["barre", [[[[16], 5]]]], ["showdiagram", [[], [[[17], 0, ["true", "false"]]], [[[10], 0, ["true", "false"]]], [[[16], 0, ["1", "0"]]]]], ["showfingering", [[], [[[17], 0, ["true", "false"]]], [[[10], 0, ["true", "false"]]], [[[16], 0, ["1", "0"]]]]], ["showname", [[], [[[17], 0, ["true", "false"]]], [[[10], 0, ["true", "false"]]], [[[16], 0, ["1", "0"]]]]]]], - ["capo", null], - ["lyrics", null], - ["articulation", null], - ["displaytranspose", null], - ["transpose", null], - ["instrument", null], - ["ts", null], - ["ro", null], - ["rc", null], - ["ae", null], - ["ks", null], - ["clef", null], - ["ottava", null], - ["tempo", null], - ["tf", null], - ["ac", null], - ["section", null], - ["jump", null], - ["ft", null], - ["simile", null], - ["barlineleft", null], - ["barlineright", null], - ["scale", null], - ["width", null], - ["sync", null], - ["accidentals", null], - ["spd", null], - ["sph", null], - ["spu", null], - ["db", null], - ["voicemode", null] + [ + 'track', + [ + ['color', [[[[17], 0]]]], + ['systemslayout', [[[[16], 5]]]], + ['defaultsystemslayout', [[[[16], 0]]]], + ['solo', null], + ['mute', null], + ['volume', [[[[16], 0]]]], + ['balance', [[[[16], 0]]]], + ['instrument', [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ['percussion']]]]], + ['bank', [[[[16], 0]]]], + ['multibarrest', null] + ] + ], + [ + 'staff', + [ + ['score', [[[[16], 1]]]], + ['tabs', null], + ['slash', null], + ['numbered', null] + ] + ], + ['voice', null], + ['title', null], + ['subtitle', null], + ['artist', null], + ['album', null], + ['words', null], + ['music', null], + ['wordsandmusic', null], + ['copyright', null], + ['copyright2', null], + ['instructions', null], + ['notices', null], + ['tab', null], + ['systemslayout', null], + ['defaultsystemslayout', null], + ['showdynamics', null], + ['hidedynamics', null], + ['usesystemsignseparator', null], + ['multibarrest', null], + ['bracketextendmode', null], + ['singletracktracknamepolicy', null], + ['multitracktracknamepolicy', null], + ['firstsystemtracknamemode', null], + ['othersystemstracknamemode', null], + ['firstsystemtracknameorientation', null], + ['othersystemstracknameorientation', null], + ['extendbarlines', null], + ['chorddiagramsinscore', null], + [ + 'tuning', + [ + ['hide', null], + ['label', [[[[17], 0]]]] + ] + ], + [ + 'chord', + [ + ['firstfret', [[[[16], 0]]]], + ['barre', [[[[16], 5]]]], + [ + 'showdiagram', + [[], [[[17], 0, ['true', 'false']]], [[[10], 0, ['true', 'false']]], [[[16], 0, ['1', '0']]]] + ], + [ + 'showfingering', + [[], [[[17], 0, ['true', 'false']]], [[[10], 0, ['true', 'false']]], [[[16], 0, ['1', '0']]]] + ], + [ + 'showname', + [[], [[[17], 0, ['true', 'false']]], [[[10], 0, ['true', 'false']]], [[[16], 0, ['1', '0']]]] + ] + ] + ], + ['capo', null], + ['lyrics', null], + ['articulation', null], + ['displaytranspose', null], + ['transpose', null], + ['instrument', null], + ['ts', null], + ['ro', null], + ['rc', null], + ['ae', null], + ['ks', null], + ['clef', null], + ['ottava', null], + ['tempo', null], + ['tf', null], + ['ac', null], + ['section', null], + ['jump', null], + ['ft', null], + ['simile', null], + ['barlineleft', null], + ['barlineright', null], + ['scale', null], + ['width', null], + ['sync', null], + ['accidentals', null], + ['spd', null], + ['sph', null], + ['spu', null], + ['db', null], + ['voicemode', null] ]); public static readonly metaDataSignatures = [ AlphaTex1LanguageDefinitions.scoreMetaDataSignatures, @@ -227,100 +595,347 @@ export class AlphaTex1LanguageDefinitions { AlphaTex1LanguageDefinitions.barMetaDataSignatures ]; public static readonly durationChangeProperties = AlphaTex1LanguageDefinitions._props([ - ["tu", [[[[16], 0, ["3", "5", "6", "7", "9", "10", "12"]]], [[[16], 0], [[16], 0]]]] + [ + 'tu', + [ + [[[16], 0, ['3', '5', '6', '7', '9', '10', '12']]], + [ + [[16], 0], + [[16], 0] + ] + ] + ] ]); public static readonly beatProperties = AlphaTex1LanguageDefinitions._props([ - ["f", null], - ["fo", null], - ["vs", null], - ["v", null], - ["vw", null], - ["s", null], - ["p", null], - ["tt", null], - ["d", null], - ["dd", null], - ["su", null], - ["sd", null], - ["cre", null], - ["dec", null], - ["spd", null], - ["sph", null], - ["spu", null], - ["spe", null], - ["slashed", null], - ["ds", null], - ["glpf", null], - ["glpt", null], - ["waho", null], - ["wahc", null], - ["legatoorigin", null], - ["timer", null], - ["tu", [[[[16], 0, ["3", "5", "6", "7", "9", "10", "12"]]], [[[16], 0], [[16], 0]]]], - ["txt", [[[[17, 10], 0]]]], - ["lyrics", [[[[17], 0]], [[[16], 0], [[17], 0]]]], - ["tb", [[[[16], 5]], [[[10, 17], 0, ["custom", "dive", "dip", "hold", "predive", "predivedive"]], [[16], 5]], [[[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]], [[[10, 17], 0, ["custom", "dive", "dip", "hold", "predive", "predivedive"]], [[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]]]], - ["tbe", [[[[16], 5]], [[[10, 17], 0, ["custom", "dive", "dip", "hold", "predive", "predivedive"]], [[16], 5]], [[[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]], [[[10, 17], 0, ["custom", "dive", "dip", "hold", "predive", "predivedive"]], [[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]]]], - ["bu", [[[[16], 1]]]], - ["bd", [[[[16], 1]]]], - ["au", [[[[16], 1]]]], - ["ad", [[[[16], 1]]]], - ["ch", [[[[17, 10], 0]]]], - ["gr", [[[[10, 17], 1, ["onbeat", "beforebeat", "bendgrace", "ob", "bb", "b"]]]]], - ["dy", [[[[10, 17], 0, ["ppp", "pp", "p", "mp", "mf", "f", "ff", "fff", "pppp", "ppppp", "pppppp", "ffff", "fffff", "ffffff", "sf", "sfp", "sfpp", "fp", "rf", "rfz", "sfz", "sffz", "fz", "n", "pf", "sfzp"]]]]], - ["tempo", [[[[16], 0], [[10], 1, ["hide"]]], [[[16], 0], [[17], 0], [[10], 1, ["hide"]]]]], - ["volume", [[[[16], 0]]]], - ["balance", [[[[16], 0]]]], - ["tp", [[[[16], 0, ["8", "16", "32"]]]]], - ["barre", [[[[16], 0], [[10, 17], 1, ["full", "half"]]]]], - ["rasg", [[[[10, 17], 0, ["ii", "mi", "miitriplet", "miianapaest", "pmptriplet", "pmpanapaest", "peitriplet", "peianapaest", "paitriplet", "paianapaest", "amitriplet", "amianapaest", "ppp", "amii", "amip", "eami", "eamii", "peami"]]]]], - ["ot", [[[[10, 17], 0, ["15ma", "8va", "regular", "8vb", "15mb", "15ma", "8va", "8vb", "15mb"]]]]], - ["instrument", [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ["percussion"]]]]], - ["bank", [[[[16], 0]]]], - ["fermata", [[[[10, 17], 0, ["short", "medium", "long"]], [[16], 3]]]], - ["beam", [[[[10, 17], 0, ["invert", "up", "down", "auto", "split", "merge", "splitsecondary"]]]]] + ['f', null], + ['fo', null], + ['vs', null], + ['v', null], + ['vw', null], + ['s', null], + ['p', null], + ['tt', null], + ['d', null], + ['dd', null], + ['su', null], + ['sd', null], + ['cre', null], + ['dec', null], + ['spd', null], + ['sph', null], + ['spu', null], + ['spe', null], + ['slashed', null], + ['ds', null], + ['glpf', null], + ['glpt', null], + ['waho', null], + ['wahc', null], + ['legatoorigin', null], + ['timer', null], + [ + 'tu', + [ + [[[16], 0, ['3', '5', '6', '7', '9', '10', '12']]], + [ + [[16], 0], + [[16], 0] + ] + ] + ], + ['txt', [[[[17, 10], 0]]]], + [ + 'lyrics', + [ + [[[17], 0]], + [ + [[16], 0], + [[17], 0] + ] + ] + ], + [ + 'tb', + [ + [[[16], 5]], + [ + [[10, 17], 0, ['custom', 'dive', 'dip', 'hold', 'predive', 'predivedive']], + [[16], 5] + ], + [ + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ], + [ + [[10, 17], 0, ['custom', 'dive', 'dip', 'hold', 'predive', 'predivedive']], + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ] + ] + ], + [ + 'tbe', + [ + [[[16], 5]], + [ + [[10, 17], 0, ['custom', 'dive', 'dip', 'hold', 'predive', 'predivedive']], + [[16], 5] + ], + [ + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ], + [ + [[10, 17], 0, ['custom', 'dive', 'dip', 'hold', 'predive', 'predivedive']], + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ] + ] + ], + ['bu', [[[[16], 1]]]], + ['bd', [[[[16], 1]]]], + ['au', [[[[16], 1]]]], + ['ad', [[[[16], 1]]]], + ['ch', [[[[17, 10], 0]]]], + ['gr', [[[[10, 17], 1, ['onbeat', 'beforebeat', 'bendgrace', 'ob', 'bb', 'b']]]]], + [ + 'dy', + [ + [ + [ + [10, 17], + 0, + [ + 'ppp', + 'pp', + 'p', + 'mp', + 'mf', + 'f', + 'ff', + 'fff', + 'pppp', + 'ppppp', + 'pppppp', + 'ffff', + 'fffff', + 'ffffff', + 'sf', + 'sfp', + 'sfpp', + 'fp', + 'rf', + 'rfz', + 'sfz', + 'sffz', + 'fz', + 'n', + 'pf', + 'sfzp' + ] + ] + ] + ] + ], + [ + 'tempo', + [ + [ + [[16], 0], + [[10], 1, ['hide']] + ], + [ + [[16], 0], + [[17], 0], + [[10], 1, ['hide']] + ] + ] + ], + ['volume', [[[[16], 0]]]], + ['balance', [[[[16], 0]]]], + ['tp', [[[[16], 0, ['8', '16', '32']]]]], + [ + 'barre', + [ + [ + [[16], 0], + [[10, 17], 1, ['full', 'half']] + ] + ] + ], + [ + 'rasg', + [ + [ + [ + [10, 17], + 0, + [ + 'ii', + 'mi', + 'miitriplet', + 'miianapaest', + 'pmptriplet', + 'pmpanapaest', + 'peitriplet', + 'peianapaest', + 'paitriplet', + 'paianapaest', + 'amitriplet', + 'amianapaest', + 'ppp', + 'amii', + 'amip', + 'eami', + 'eamii', + 'peami' + ] + ] + ] + ] + ], + ['ot', [[[[10, 17], 0, ['15ma', '8va', 'regular', '8vb', '15mb', '15ma', '8va', '8vb', '15mb']]]]], + ['instrument', [[[[16], 0]], [[[17, 10], 0]], [[[10], 0, ['percussion']]]]], + ['bank', [[[[16], 0]]]], + [ + 'fermata', + [ + [ + [[10, 17], 0, ['short', 'medium', 'long']], + [[16], 3] + ] + ] + ], + ['beam', [[[[10, 17], 0, ['invert', 'up', 'down', 'auto', 'split', 'merge', 'splitsecondary']]]]] ]); public static readonly noteProperties = AlphaTex1LanguageDefinitions._props([ - ["nh", null], - ["ah", [[[[16], 1]]]], - ["th", [[[[16], 1]]]], - ["ph", [[[[16], 1]]]], - ["sh", [[[[16], 1]]]], - ["fh", [[[[16], 1]]]], - ["v", null], - ["vw", null], - ["sl", null], - ["ss", null], - ["sib", null], - ["sia", null], - ["sou", null], - ["sod", null], - ["psu", null], - ["psd", null], - ["h", null], - ["lht", null], - ["g", null], - ["ac", null], - ["hac", null], - ["ten", null], - ["tr", [[[[16], 0], [[16], 1, ["16", "32", "64"]]]]], - ["pm", null], - ["st", null], - ["lr", null], - ["x", null], - ["t", null], - ["turn", null], - ["iturn", null], - ["umordent", null], - ["lmordent", null], - ["string", null], - ["hide", null], - ["b", [[[[16], 5]], [[[10, 17], 0, ["custom", "bend", "release", "bendrelease", "hold", "prebend", "prebendbend", "prebendrelease"]], [[16], 5]], [[[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]], [[[10, 17], 0, ["custom", "bend", "release", "bendrelease", "hold", "prebend", "prebendbend", "prebendrelease"]], [[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]]]], - ["be", [[[[16], 5]], [[[10, 17], 0, ["custom", "bend", "release", "bendrelease", "hold", "prebend", "prebendbend", "prebendrelease"]], [[16], 5]], [[[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]], [[[10, 17], 0, ["custom", "bend", "release", "bendrelease", "hold", "prebend", "prebendbend", "prebendrelease"]], [[10, 17], 0, ["default", "gradual", "fast"]], [[16], 5]]]], - ["lf", [[[[16], 0, ["1", "2", "3", "4", "5"]]]]], - ["rf", [[[[16], 0, ["1", "2", "3", "4", "5"]]]]], - ["acc", [[[[10, 17], 0, ["default", "forcenone", "forcenatural", "forcesharp", "forcedoublesharp", "forceflat", "forcedoubleflat", "d", "-", "n", "#", "##", "x", "b", "bb"]]]]], - ["slur", [[[[17], 0]], [[[10], 0]]]], - ["-", null] + ['nh', null], + ['ah', [[[[16], 1]]]], + ['th', [[[[16], 1]]]], + ['ph', [[[[16], 1]]]], + ['sh', [[[[16], 1]]]], + ['fh', [[[[16], 1]]]], + ['v', null], + ['vw', null], + ['sl', null], + ['ss', null], + ['sib', null], + ['sia', null], + ['sou', null], + ['sod', null], + ['psu', null], + ['psd', null], + ['h', null], + ['lht', null], + ['g', null], + ['ac', null], + ['hac', null], + ['ten', null], + [ + 'tr', + [ + [ + [[16], 0], + [[16], 1, ['16', '32', '64']] + ] + ] + ], + ['pm', null], + ['st', null], + ['lr', null], + ['x', null], + ['t', null], + ['turn', null], + ['iturn', null], + ['umordent', null], + ['lmordent', null], + ['string', null], + ['hide', null], + [ + 'b', + [ + [[[16], 5]], + [ + [ + [10, 17], + 0, + ['custom', 'bend', 'release', 'bendrelease', 'hold', 'prebend', 'prebendbend', 'prebendrelease'] + ], + [[16], 5] + ], + [ + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ], + [ + [ + [10, 17], + 0, + ['custom', 'bend', 'release', 'bendrelease', 'hold', 'prebend', 'prebendbend', 'prebendrelease'] + ], + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ] + ] + ], + [ + 'be', + [ + [[[16], 5]], + [ + [ + [10, 17], + 0, + ['custom', 'bend', 'release', 'bendrelease', 'hold', 'prebend', 'prebendbend', 'prebendrelease'] + ], + [[16], 5] + ], + [ + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ], + [ + [ + [10, 17], + 0, + ['custom', 'bend', 'release', 'bendrelease', 'hold', 'prebend', 'prebendbend', 'prebendrelease'] + ], + [[10, 17], 0, ['default', 'gradual', 'fast']], + [[16], 5] + ] + ] + ], + ['lf', [[[[16], 0, ['1', '2', '3', '4', '5']]]]], + ['rf', [[[[16], 0, ['1', '2', '3', '4', '5']]]]], + [ + 'acc', + [ + [ + [ + [10, 17], + 0, + [ + 'default', + 'forcenone', + 'forcenatural', + 'forcesharp', + 'forcedoublesharp', + 'forceflat', + 'forcedoubleflat', + 'd', + '-', + 'n', + '#', + '##', + 'x', + 'b', + 'bb' + ] + ] + ] + ] + ], + ['slur', [[[[17], 0]], [[[10], 0]]]], + ['-', null] ]); } diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts index 13ebb462b..fab749e45 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageHandler.ts @@ -259,6 +259,12 @@ export class AlphaTex1LanguageHandler implements IAlphaTexLanguageImportHandler } score.stylesheet.otherSystemsTrackNameOrientation = otherSystemsTrackNameOrientation!; return ApplyNodeResult.Applied; + case 'chorddiagramsinscore': + score.stylesheet.globalDisplayChordDiagramsInScore = metaData.arguments + ? AlphaTex1LanguageHandler._booleanLikeValue(metaData.arguments!.arguments, 0) + : true; + return ApplyNodeResult.Applied; + default: return ApplyNodeResult.NotAppliedUnrecognizedMarker; } @@ -2488,6 +2494,10 @@ export class AlphaTex1LanguageHandler implements IAlphaTexLanguageImportHandler nodes.push(Atnf.meta('extendBarLines')); } + if (stylesheet.globalDisplayChordDiagramsInScore) { + nodes.push(Atnf.meta('chordDiagramsInScore')); + } + // Unsupported: // 'globaldisplaychorddiagramsontop', // 'pertrackchorddiagramsontop', diff --git a/packages/alphatab/src/model/RenderStylesheet.ts b/packages/alphatab/src/model/RenderStylesheet.ts index 70a8c31e5..83825cbe2 100644 --- a/packages/alphatab/src/model/RenderStylesheet.ts +++ b/packages/alphatab/src/model/RenderStylesheet.ts @@ -115,6 +115,11 @@ export class RenderStylesheet { */ public perTrackChordDiagramsOnTop: Map | null = null; + /** + * Whether to show the chord diagrams in score. + */ + public globalDisplayChordDiagramsInScore: boolean = false; + /** * The policy where to show track names when a single track is rendered. */ diff --git a/packages/alphatab/test-data/guitarpro8/show-diagrams-in-score.gp b/packages/alphatab/test-data/guitarpro8/show-diagrams-in-score.gp new file mode 100644 index 0000000000000000000000000000000000000000..ed2e0c232182ff4d618d043a63605289a35a1742 GIT binary patch literal 12692 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
  • b7nMm}mDORf!Z+>i-r2dF~!u2&33Ht&^Asqle8KiuIuI$j4 zSS3@xrgv*teLSf|HPZqVv8clih_Jz)_NHjBr-WN~<@zB5{GBggx3n#6wq-GioGYEV z=U|-YW>d~yFHiIG0u?J}?wDfXU|~`&2as%tM(B9kxvDP-y6XFIdH#u_r)Tcw{`%n) zd3SwZD#pgnGsMG7wZ0CX{HyDQqo>boUO?mkIvqoX=N{(rX}2R{i3N3+EyP6yq`Sm$ zdftaUa-xt}dxVJG*H6O=u(s=_g^Lj~MDonPe73)czw8oKVdJ}YxZvx5W_N!LJlSAf z!NFDczj02NMn4#|mW!0&FBolzz>W|>*OJuTH^D){hiJwv( zY3N%stWLH3S>YN@5boUJBj@Iwsj(u5G<(R!mX1QdZupS3XV7${92 z2nLgBWk&YBf+yId7fW{Ca=vZ+Yn3*rs0t2Ux&E*m8A-y#fjcLwxQqDS6KuBWDMhgh z=4aTH&JAlU)FCAfKr7{{{%>B97BZYurQKb~Y?X~=n3vz-}_5EF(8wZKASI8^1uO=H?el`_~ zAKE3DSyVaO5G6Ij+b^_%lt7buPd?EPeYS8-qWEHJiDM{&xyMm1?MAUP9C5SMJ)zlo zQgXM{6^grcajmq~b$BPx#iKH)eFl5Rv$QFlW&KH6;AAzRpeW)x@qQj!!rJ0~yZ^%CaouqQFZkUs7P{jOHGM|Mp=%*p(C!pySBfUGK41_2J{ z`68b0|8b za00u`;cDAvUIT&~T)|jX7E*o;7N^vC5#n$fuLJ}M8|FBw!VRfEY^(*M0uY=C47655 zP!=ZzQRuN+KTzCjz@9@Cl5)(I@FSTYuz%s?0hcl=OJz)x%f^&v+ z2`p|qaK^+mDrt;)N)9x6{OYf7jdS${w5dY6*}<69i^{caG34NR11<&*cRC8#!xq;q z(UrqmBJw1jiRDRQ(xTWm1n!(`oo=;9#QtbWIpvV7cjA1^*oh9YQCp8x>3Js1!uC>- zku@?w2s}Qw(y502YC1}NNM&X-qavmV-G7ue8C9FvCUvXIwG5Tsk_dDhKwPmna z*EllV#;6{u*?2Na>I%I}R>4EZaT93psU(-&$l=pd9qZ4c@R$p@gj0+rAn@X8665+l zetSypHAGih8JmmxywfxYzPD)LVyzK#qc$kEr{U{jy_ymFIj}aWh=R-sY}G9%u(@KY zvT`l98^3yxUtZ|;Gk=N8ZQ~DvhQ6@5>l*V0^jGMcy!;B$6Np%TY+gLRY-@y^m?Mh} zHQPW9+4O+1Cv;(sK~!Ed3v8}kKJes$hofT;mz4O5*j$Zl(-W0Fh#Q>+>n$T%}}UchQK~) zes(LMytqt;ph1=%2?}9qto;>SCqdaC>5-QY+g8FP)|lm7%7<<~YekLZ@%vWxwS6NO z4eV??tud1V|2dzDCOwki{%k3hIq#2yZKP0@Y|vlWiO= z!<)R>A^SlQ<2ja?{ce)5S`Cg?p)^WitcwkdMD?pL)B*v{#V?rLei$m&5EDFZzw^`N0lLU^G^a+1q58|AcRY zFSHUJVG^ez74EF89d2`eeSw|OgMyLCteRoQ9-_$9eYQ*0ebvV;ORDGyz6?ngo0D|h zSreX=%hk3cJFV2$NUCJ^*Z?6mdqMIzVeQj{0M11bUxr z1iFS$Jv3QC_Bb@z^5Le4a&+Ico@#3Qpd?4|?UV}EhIBIeRs1k}^`m~;0!41_LZJA$ zC$BqcHH0rzHAnFX#f9g2u!r~Uy+@}aQ{DK{1&IgWleBv$lPZ7sLSOY<$cAtEqx+gK zXf;Kr_@(EyiOsKFWp};@Et_9E9?zJaIo7{E8U-)xFj(~w^c_*p&N4Z!)%iq#VR8pP zclwQ`K=GAHS+e=8DcR+mFN9Wew%a(5Wt>9GV5F}O(5k;iR=ffeoQkh?vjG6|Fn^Vp zK)n4GR})oImXw!cSzrMGLQ&eUK;HI&{bf1>^>)<8#M$s~RJVNp%N{V`GO_IETS5o` z|64^MU;xN}e+B!k$eSSoUIpLRzrmb>^xtd!ekJ=Ih`+<|cPRc&m4Dl-Kl$6{?^=I; zLHo}tf282=@cg&E`uDzR|5o`ADE-eu@A&&2eZRZ)PH%tPt3L|HKZX7cq5oOtohQGu zf}KXBmR0>2yg9V)*A<#(|Buiixb zXMw+y=|9W7X#Epv{NDvV z2>%zszjJ{<3% { ).toMatchSnapshot(); }); }); + + it('inline-chord-diagrams', () =>{ + let score = parseTex(` + \\chordDiagramsInScore + \\chord ("E" 0 0 1 2 2 0) + (0.1 0.2 1.3 2.4 2.5 0.6){ch "E"} + `); + expect(score.stylesheet.globalDisplayChordDiagramsInScore).to.be.true; + + score = parseTex(` + \\chordDiagramsInScore true + \\chord ("E" 0 0 1 2 2 0) + (0.1 0.2 1.3 2.4 2.5 0.6){ch "E"} + `); + expect(score.stylesheet.globalDisplayChordDiagramsInScore).to.be.true; + + score = parseTex(` + \\chordDiagramsInScore false + \\chord ("E" 0 0 1 2 2 0) + (0.1 0.2 1.3 2.4 2.5 0.6){ch "E"} + `); + expect(score.stylesheet.globalDisplayChordDiagramsInScore).to.be.false; + }) }); diff --git a/packages/alphatab/test/importer/Gp8Importer.test.ts b/packages/alphatab/test/importer/Gp8Importer.test.ts index 1e12472f9..24ca35899 100644 --- a/packages/alphatab/test/importer/Gp8Importer.test.ts +++ b/packages/alphatab/test/importer/Gp8Importer.test.ts @@ -132,6 +132,14 @@ describe('Gp8ImporterTest', () => { expect(show.stylesheet.globalDisplayChordDiagramsOnTop).to.be.true; }); + it('show-chord-diagrams-in-score', async () => { + const hide = (await prepareImporterWithFile('guitarpro8/show-diagrams-in-score.gp')).readScore(); + expect(hide.stylesheet.globalDisplayChordDiagramsInScore).to.be.true; + + const show = (await prepareImporterWithFile('guitarpro8/directions.gp')).readScore(); + expect(show.stylesheet.globalDisplayChordDiagramsInScore).to.be.false; + }); + it('beaming-mode', async () => { const score = (await prepareImporterWithFile('guitarpro8/beaming-mode.gp')).readScore(); diff --git a/packages/alphatex/src/definitions.ts b/packages/alphatex/src/definitions.ts index b1056b6ba..0ffb4163d 100644 --- a/packages/alphatex/src/definitions.ts +++ b/packages/alphatex/src/definitions.ts @@ -148,6 +148,7 @@ import { x } from '@coderline/alphatab-alphatex//properties/note/x'; import { metadata, properties } from '@coderline/alphatab-alphatex/common'; import { db } from '@coderline/alphatab-alphatex/metadata/bar/db'; import { voiceMode } from '@coderline/alphatab-alphatex/metadata/bar/voiceMode'; +import { chordDiagramsInScore } from '@coderline/alphatab-alphatex/metadata/score/chordDiagramsInScore'; import { extendBarLines } from '@coderline/alphatab-alphatex/metadata/score/extendbarlines'; import { instrumentMeta } from '@coderline/alphatab-alphatex/metadata/staff/instrument'; import type { AlphaTexExample, WithDescription, WithSignatures } from '@coderline/alphatab-alphatex/types'; @@ -179,7 +180,8 @@ export const scoreMetaData = metadata( otherSystemsTrackNameMode, firstSystemTrackNameOrientation, otherSystemsTrackNameOrientation, - extendBarLines + extendBarLines, + chordDiagramsInScore ); export const staffMetaData = metadata( diff --git a/packages/alphatex/src/metadata/score/chordDiagramsInScore.ts b/packages/alphatex/src/metadata/score/chordDiagramsInScore.ts new file mode 100644 index 000000000..71039463f --- /dev/null +++ b/packages/alphatex/src/metadata/score/chordDiagramsInScore.ts @@ -0,0 +1,33 @@ +import * as alphaTab from '@coderline/alphatab'; +import type { MetadataTagDefinition } from '@coderline/alphatab-alphatex/types'; + +export const chordDiagramsInScore: MetadataTagDefinition = { + tag: '\\chordDiagramsInScore', + snippet: '\\chordDiagramsInScore', + shortDescription: 'Show inline chord diagrams in score.', + longDescription: `Configures whether chord diagrams are shown inline in the score..`, + signatures: [ + { + parameters: [ + { + name: 'visibility', + shortDescription: 'The visibility of the diagrams', + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional, + defaultValue: 'true', + type: alphaTab.importer.alphaTex.AlphaTexNodeType.Ident, + values: [ + { name: 'true', snippet: 'true', shortDescription: 'Show the diagrams' }, + { name: 'false', snippet: 'false', shortDescription: 'Hide the diagrams' } + ] + } + ] + } + ], + examples: [ + ` + \\chordDiagramsInScore + \\chord ("E" 0 0 1 2 2 0) + (0.1 0.2 1.3 2.4 2.5 0.6){ch "E"} + ` + ] +}; From 6f6235c6d9d8a8c4da5ea981c3c483f7a2eb2e4c Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Mon, 15 Dec 2025 18:24:38 +0100 Subject: [PATCH 2/2] feat: render inline chord diagrams --- .../src/rendering/effects/ChordsEffectInfo.ts | 6 +++++- .../src/rendering/glyphs/ChordDiagramGlyph.ts | 15 +++++++++++---- .../inscore-chord-diagrams.png | Bin 0 -> 22669 bytes .../features/EffectsAndAnnotations.test.ts | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 packages/alphatab/test-data/visual-tests/effects-and-annotations/inscore-chord-diagrams.png diff --git a/packages/alphatab/src/rendering/effects/ChordsEffectInfo.ts b/packages/alphatab/src/rendering/effects/ChordsEffectInfo.ts index 7e5475212..cad5e1d6f 100644 --- a/packages/alphatab/src/rendering/effects/ChordsEffectInfo.ts +++ b/packages/alphatab/src/rendering/effects/ChordsEffectInfo.ts @@ -7,6 +7,7 @@ import { TextGlyph } from '@coderline/alphatab/rendering/glyphs/TextGlyph'; import { EffectInfo } from '@coderline/alphatab/rendering/EffectInfo'; import type { Settings } from '@coderline/alphatab/Settings'; import { NotationElement } from '@coderline/alphatab/NotationSettings'; +import { ChordDiagramGlyph } from '@coderline/alphatab/rendering/glyphs/ChordDiagramGlyph'; /** * @internal @@ -33,7 +34,10 @@ export class ChordsEffectInfo extends EffectInfo { } public createNewGlyph(renderer: BarRendererBase, beat: Beat): EffectGlyph { - return new TextGlyph(0, 0, beat.chord!.name, renderer.resources.effectFont, TextAlign.Center); + const showDiagram = beat.voice.bar.staff.track.score.stylesheet.globalDisplayChordDiagramsInScore; + return showDiagram + ? new ChordDiagramGlyph(0, 0, beat.chord!, true) + : new TextGlyph(0, 0, beat.chord!.name, renderer.resources.effectFont, TextAlign.Center); } public canExpand(_from: Beat, _to: Beat): boolean { diff --git a/packages/alphatab/src/rendering/glyphs/ChordDiagramGlyph.ts b/packages/alphatab/src/rendering/glyphs/ChordDiagramGlyph.ts index 271499580..136deae87 100644 --- a/packages/alphatab/src/rendering/glyphs/ChordDiagramGlyph.ts +++ b/packages/alphatab/src/rendering/glyphs/ChordDiagramGlyph.ts @@ -14,10 +14,12 @@ export class ChordDiagramGlyph extends EffectGlyph { private _textRow: number = 0; private _fretRow: number = 0; private _firstFretSpacing: number = 0; + private _center: boolean; - public constructor(x: number, y: number, chord: Chord) { + public constructor(x: number, y: number, chord: Chord, center: boolean = false) { super(x, y); this._chord = chord; + this._center = center; } public override doLayout(): void { @@ -44,6 +46,10 @@ export class ChordDiagramGlyph extends EffectGlyph { public override paint(cx: number, cy: number, canvas: ICanvas): void { cx += this.x + this.renderer.smuflMetrics.chordDiagramPaddingX + this._firstFretSpacing; cy += this.y; + if (this._center) { + cx -= this.width / 2; + } + const stringSpacing: number = this.renderer.smuflMetrics.chordDiagramStringSpacing; const fretSpacing: number = this.renderer.smuflMetrics.chordDiagramFretSpacing; const res: RenderingResources = this.renderer.resources; @@ -72,9 +78,9 @@ export class ChordDiagramGlyph extends EffectGlyph { const y: number = cy + this._fretRow / 2; let fret: number = this._chord.strings[this._chord.strings.length - i - 1]; if (fret < 0) { - CanvasHelper.fillMusicFontSymbolSafe(canvas,x, y + xTopOffset, 1, MusicFontSymbol.FretboardX, true); + CanvasHelper.fillMusicFontSymbolSafe(canvas, x, y + xTopOffset, 1, MusicFontSymbol.FretboardX, true); } else if (fret === 0) { - CanvasHelper.fillMusicFontSymbolSafe(canvas,x, y + oTopOffset, 1, MusicFontSymbol.FretboardO, true); + CanvasHelper.fillMusicFontSymbolSafe(canvas, x, y + oTopOffset, 1, MusicFontSymbol.FretboardO, true); } else { fret -= this._chord.firstFret - 1; canvas.fillText(fret.toString(), x, y); @@ -126,7 +132,8 @@ export class ChordDiagramGlyph extends EffectGlyph { } const y: number = cy + fret * fretSpacing + fretSpacing / 2 + 0.5; const x: number = cx + (this._chord.strings.length - guitarString - 1) * stringSpacing + lineWidth / 2; - CanvasHelper.fillMusicFontSymbolSafe(canvas, + CanvasHelper.fillMusicFontSymbolSafe( + canvas, x, y + circleTopOffset - circleHeight / 2, 1, diff --git a/packages/alphatab/test-data/visual-tests/effects-and-annotations/inscore-chord-diagrams.png b/packages/alphatab/test-data/visual-tests/effects-and-annotations/inscore-chord-diagrams.png new file mode 100644 index 0000000000000000000000000000000000000000..c07a31dca4e3d8e4893b7f72259fcf538ca663d7 GIT binary patch literal 22669 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 literal 0 HcmV?d00001 diff --git a/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts b/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts index 1fd58f3b7..46183dadd 100644 --- a/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts +++ b/packages/alphatab/test/visualTests/features/EffectsAndAnnotations.test.ts @@ -305,4 +305,18 @@ describe('EffectsAndAnnotationsTests', () => { 'test-data/visual-tests/effects-and-annotations/legato.png' ); }); + + it('inscore-chord-diagrams', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\chordDiagramsInScore true + \\chord ("E" 0 0 1 2 2 0) + \\chord ("C" 0 1 0 2 3 x) + + (0.1 0.2 1.3 2.4 2.5 0.6){ch "E"} r r r | + (0.1 1.2 0.3 2.4 3.5){ch "C"} r r r | + `, + 'test-data/visual-tests/effects-and-annotations/inscore-chord-diagrams.png' + ); + }); });