From e9349c86262e8221211f24367852ef543100444f Mon Sep 17 00:00:00 2001 From: danielku15 Date: Thu, 8 Oct 2026 13:15:50 +0200 Subject: [PATCH] fix(alphatex): accept fractional harmonic values The value of ah/th/ph/sh/fh was declared as an integer parameter, so a fractional value like {ah 2.4} written by the exporter failed to parse on re-import (AT206/AT202). Declare it as an optional float. Fixes #2896 --- .../alphaTex/AlphaTex1LanguageDefinitions.ts | 10 +++++----- .../test/importer/AlphaTexImporter.test.ts | 18 ++++++++++++++++++ packages/alphatex/src/properties/note/ah.ts | 2 +- packages/alphatex/src/properties/note/fh.ts | 2 +- packages/alphatex/src/properties/note/ph.ts | 2 +- packages/alphatex/src/properties/note/sh.ts | 2 +- packages/alphatex/src/properties/note/th.ts | 2 +- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts index 48e3da2fe4..175ef83784 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts @@ -843,11 +843,11 @@ export class AlphaTex1LanguageDefinitions { ]); public static readonly noteProperties = AlphaTex1LanguageDefinitions._props([ ['nh', null], - ['ah', [[[[106], 1]]]], - ['th', [[[[106], 1]]]], - ['ph', [[[[106], 1]]]], - ['sh', [[[[106], 1]]]], - ['fh', [[[[106], 1]]]], + ['ah', [[[[106], 3]]]], + ['th', [[[[106], 3]]]], + ['ph', [[[[106], 3]]]], + ['sh', [[[[106], 3]]]], + ['fh', [[[[106], 3]]]], ['v', null], ['vw', null], ['sl', null], diff --git a/packages/alphatab/test/importer/AlphaTexImporter.test.ts b/packages/alphatab/test/importer/AlphaTexImporter.test.ts index deb82633ee..cd240cdd66 100644 --- a/packages/alphatab/test/importer/AlphaTexImporter.test.ts +++ b/packages/alphatab/test/importer/AlphaTexImporter.test.ts @@ -1775,6 +1775,24 @@ describe('AlphaTexImporterTest', () => { testExportRoundtrip(score); }); + it('harmonic-values-fractional', () => { + const score = parseTex(` + 2.3{ah 2.4} 2.3{th 2.7} 2.3{ph 3.5} 2.3{sh 8.5} 2.3{fh 2.4} + `); + const beats = score.tracks[0].staves[0].bars[0].voices[0].beats; + expect(beats[0].notes[0].harmonicType).toBe(HarmonicType.Artificial); + expect(beats[0].notes[0].harmonicValue).toBe(2.4); + expect(beats[1].notes[0].harmonicType).toBe(HarmonicType.Tap); + expect(beats[1].notes[0].harmonicValue).toBe(2.7); + expect(beats[2].notes[0].harmonicType).toBe(HarmonicType.Pinch); + expect(beats[2].notes[0].harmonicValue).toBe(3.5); + expect(beats[3].notes[0].harmonicType).toBe(HarmonicType.Semi); + expect(beats[3].notes[0].harmonicValue).toBe(8.5); + expect(beats[4].notes[0].harmonicType).toBe(HarmonicType.Feedback); + expect(beats[4].notes[0].harmonicValue).toBe(2.4); + testExportRoundtrip(score); + }); + it('time-signature-commons', () => { const score = parseTex(` \\ts common diff --git a/packages/alphatex/src/properties/note/ah.ts b/packages/alphatex/src/properties/note/ah.ts index 6fb02c3e73..d1bc0478c2 100644 --- a/packages/alphatex/src/properties/note/ah.ts +++ b/packages/alphatex/src/properties/note/ah.ts @@ -41,7 +41,7 @@ export const ah: PropertyDefinition = { shortDescription: 'The harmonic value', longDescription: harmonicValueDocs, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number, - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.OptionalAsFloat } ] } diff --git a/packages/alphatex/src/properties/note/fh.ts b/packages/alphatex/src/properties/note/fh.ts index c73f910911..58f8ded41c 100644 --- a/packages/alphatex/src/properties/note/fh.ts +++ b/packages/alphatex/src/properties/note/fh.ts @@ -16,7 +16,7 @@ export const fh: PropertyDefinition = { shortDescription: 'The harmonic value', longDescription: harmonicValueDocs, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number, - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.OptionalAsFloat } ] } diff --git a/packages/alphatex/src/properties/note/ph.ts b/packages/alphatex/src/properties/note/ph.ts index afcf64f875..65e3d2e140 100644 --- a/packages/alphatex/src/properties/note/ph.ts +++ b/packages/alphatex/src/properties/note/ph.ts @@ -16,7 +16,7 @@ export const ph: PropertyDefinition = { shortDescription: 'The harmonic value', longDescription: harmonicValueDocs, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number, - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.OptionalAsFloat } ] } diff --git a/packages/alphatex/src/properties/note/sh.ts b/packages/alphatex/src/properties/note/sh.ts index 88c2e5e4a8..fde229ffd3 100644 --- a/packages/alphatex/src/properties/note/sh.ts +++ b/packages/alphatex/src/properties/note/sh.ts @@ -15,7 +15,7 @@ export const sh: PropertyDefinition = { shortDescription: 'The harmonic value', longDescription: harmonicValueDocs, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number, - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.OptionalAsFloat } ] } diff --git a/packages/alphatex/src/properties/note/th.ts b/packages/alphatex/src/properties/note/th.ts index 09149d3ea5..8455b4161c 100644 --- a/packages/alphatex/src/properties/note/th.ts +++ b/packages/alphatex/src/properties/note/th.ts @@ -16,7 +16,7 @@ export const th: PropertyDefinition = { shortDescription: 'The harmonic value', longDescription: harmonicValueDocs, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number, - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Optional + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.OptionalAsFloat } ] }