From cd44f1cc5bff97a8a975c51b070349862c55ad6c Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Tue, 16 Jun 2026 22:05:27 +0200 Subject: [PATCH 1/3] feat(rendering): configurable staff element display --- packages/alphatab/scripts/CloneEmitter.ts | 4 +- packages/alphatab/scripts/EmitterBase.ts | 11 +- .../scripts/JsonDeclarationEmitter.ts | 16 +- .../alphatab/scripts/Serializer.fromJson.ts | 4 +- .../scripts/Serializer.setProperty.ts | 52 ++-- .../alphatab/scripts/Serializer.toJson.ts | 36 ++- packages/alphatab/scripts/TypeSchema.ts | 80 +++++- packages/alphatab/src/Environment.ts | 34 +-- packages/alphatab/src/RenderingResources.ts | 9 + .../src/generated/CoreSettingsSerializer.ts | 2 +- .../generated/DisplaySettingsSerializer.ts | 2 +- .../generated/EngravingSettingsSerializer.ts | 2 +- .../generated/EngravingStemInfoSerializer.ts | 2 +- .../generated/ExporterSettingsSerializer.ts | 2 +- .../generated/ImporterSettingsSerializer.ts | 2 +- .../generated/NotationSettingsSerializer.ts | 2 +- .../src/generated/PlayerSettingsSerializer.ts | 2 +- .../src/generated/RenderingResourcesJson.ts | 76 +++++- .../generated/RenderingResourcesSerializer.ts | 29 ++- .../src/generated/SettingsSerializer.ts | 2 +- .../SlidePlaybackSettingsSerializer.ts | 2 +- .../VibratoPlaybackSettingsSerializer.ts | 2 +- .../generated/model/AutomationSerializer.ts | 2 +- .../generated/model/BackingTrackSerializer.ts | 2 +- .../src/generated/model/BarSerializer.ts | 54 +++- .../src/generated/model/BarStyleSerializer.ts | 2 +- .../generated/model/BeamingRulesSerializer.ts | 2 +- .../src/generated/model/BeatSerializer.ts | 8 +- .../generated/model/BeatStyleSerializer.ts | 2 +- .../generated/model/BendPointSerializer.ts | 2 +- .../src/generated/model/ChordSerializer.ts | 2 +- .../model/ElementDisplaySerializer.ts | 44 ++++ .../src/generated/model/FermataSerializer.ts | 2 +- .../model/HeaderFooterStyleSerializer.ts | 2 +- .../model/InstrumentArticulationSerializer.ts | 2 +- .../generated/model/MasterBarSerializer.ts | 10 +- .../src/generated/model/NoteSerializer.ts | 2 +- .../generated/model/NoteStyleSerializer.ts | 2 +- .../model/NumberedBarOverrideSerializer.ts | 49 ++++ .../model/NumberedStaffConfigSerializer.ts | 49 ++++ .../model/PlaybackInformationSerializer.ts | 2 +- .../model/RenderStylesheetSerializer.ts | 22 +- .../model/ScoreBarOverrideSerializer.ts | 75 ++++++ .../src/generated/model/ScoreSerializer.ts | 2 +- .../model/ScoreStaffConfigSerializer.ts | 75 ++++++ .../generated/model/ScoreStyleSerializer.ts | 2 +- .../src/generated/model/SectionSerializer.ts | 2 +- .../model/SlashBarOverrideSerializer.ts | 62 +++++ .../model/SlashStaffConfigSerializer.ts | 62 +++++ .../src/generated/model/StaffSerializer.ts | 54 +++- .../model/SustainPedalMarkerSerializer.ts | 2 +- .../model/SyncPointDataSerializer.ts | 2 +- .../model/TabBarOverrideSerializer.ts | 62 +++++ .../model/TabStaffConfigSerializer.ts | 80 ++++++ .../src/generated/model/TrackSerializer.ts | 2 +- .../generated/model/TrackStyleSerializer.ts | 2 +- .../model/TremoloPickingEffectSerializer.ts | 2 +- .../src/generated/model/TuningSerializer.ts | 2 +- .../src/generated/model/VoiceSerializer.ts | 2 +- .../generated/model/VoiceStyleSerializer.ts | 2 +- packages/alphatab/src/model/Bar.ts | 63 ++++- packages/alphatab/src/model/BarOverrides.ts | 50 ++++ packages/alphatab/src/model/Beat.ts | 2 + packages/alphatab/src/model/ElementDisplay.ts | 67 +++++ packages/alphatab/src/model/MasterBar.ts | 2 + .../alphatab/src/model/RenderStylesheet.ts | 62 ++++- packages/alphatab/src/model/Staff.ts | 26 ++ packages/alphatab/src/model/StaffConfigs.ts | 55 ++++ packages/alphatab/src/model/_barrel.ts | 17 ++ .../alphatab/src/rendering/BarRendererBase.ts | 4 +- .../src/rendering/BarRendererFactory.ts | 7 + .../alphatab/src/rendering/LineBarRenderer.ts | 32 ++- .../src/rendering/NumberedBarRenderer.ts | 37 ++- .../rendering/NumberedBarRendererFactory.ts | 6 +- .../src/rendering/ScoreBarRenderer.ts | 73 ++++-- .../src/rendering/ScoreBarRendererFactory.ts | 6 +- .../src/rendering/SlashBarRenderer.ts | 34 ++- .../src/rendering/SlashBarRendererFactory.ts | 6 +- .../alphatab/src/rendering/TabBarRenderer.ts | 72 +++-- .../src/rendering/TabBarRendererFactory.ts | 6 +- .../src/rendering/staves/RenderStaff.ts | 13 + .../rendering/staves/StaffDisplayResolver.ts | 73 ++++++ .../staff-display-config/cascade-all-four.png | Bin 0 -> 18028 bytes .../cascade-numbered-only.png | Bin 0 -> 5705 bytes .../cascade-score-tab.png | Bin 0 -> 15596 bytes .../cascade-slash-numbered.png | Bin 0 -> 8193 bytes .../staff-display-config/cascade-tab-only.png | Bin 0 -> 10053 bytes .../cascade-tab-slash.png | Bin 0 -> 12647 bytes .../override-l1-ks-change-hide.png | Bin 0 -> 10035 bytes .../override-l1-ts-hide-firstbar.png | Bin 0 -> 14161 bytes .../override-l2-score-clef-hide.png | Bin 0 -> 7665 bytes .../override-l2-tab-ts-hide.png | Bin 0 -> 8794 bytes .../MusicXmlImporter.test.ts.snap | 96 +++++++ .../test/model/StaffConfiguration.test.ts | 246 ++++++++++++++++++ .../rendering/StaffDisplayResolver.test.ts | 132 ++++++++++ .../features/StaffDisplayConfig.test.ts | 159 +++++++++++ .../csharp/src/AlphaTab.Test/Test/Globals.cs | 47 ++++ 97 files changed, 2318 insertions(+), 202 deletions(-) create mode 100644 packages/alphatab/src/generated/model/ElementDisplaySerializer.ts create mode 100644 packages/alphatab/src/generated/model/NumberedBarOverrideSerializer.ts create mode 100644 packages/alphatab/src/generated/model/NumberedStaffConfigSerializer.ts create mode 100644 packages/alphatab/src/generated/model/ScoreBarOverrideSerializer.ts create mode 100644 packages/alphatab/src/generated/model/ScoreStaffConfigSerializer.ts create mode 100644 packages/alphatab/src/generated/model/SlashBarOverrideSerializer.ts create mode 100644 packages/alphatab/src/generated/model/SlashStaffConfigSerializer.ts create mode 100644 packages/alphatab/src/generated/model/TabBarOverrideSerializer.ts create mode 100644 packages/alphatab/src/generated/model/TabStaffConfigSerializer.ts create mode 100644 packages/alphatab/src/model/BarOverrides.ts create mode 100644 packages/alphatab/src/model/ElementDisplay.ts create mode 100644 packages/alphatab/src/model/StaffConfigs.ts create mode 100644 packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-numbered-only.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-score-tab.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-only.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-slash.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ts-hide-firstbar.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png create mode 100644 packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-tab-ts-hide.png create mode 100644 packages/alphatab/test/model/StaffConfiguration.test.ts create mode 100644 packages/alphatab/test/rendering/StaffDisplayResolver.test.ts create mode 100644 packages/alphatab/test/visualTests/features/StaffDisplayConfig.test.ts diff --git a/packages/alphatab/scripts/CloneEmitter.ts b/packages/alphatab/scripts/CloneEmitter.ts index af1f1933e..43f0caed0 100644 --- a/packages/alphatab/scripts/CloneEmitter.ts +++ b/packages/alphatab/scripts/CloneEmitter.ts @@ -260,7 +260,7 @@ function generateClonePropertyStatements( function generateCloneBody( program: ts.Program, - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, importer: (name: string, module: string) => void ): ts.Block { const propertiesToSerialize = input.members @@ -299,7 +299,7 @@ function generateCloneBody( function createCloneMethod( program: ts.Program, - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, importer: (name: string, module: string) => void ) { return ts.factory.createMethodDeclaration( diff --git a/packages/alphatab/scripts/EmitterBase.ts b/packages/alphatab/scripts/EmitterBase.ts index f38fa3a95..929be40d3 100644 --- a/packages/alphatab/scripts/EmitterBase.ts +++ b/packages/alphatab/scripts/EmitterBase.ts @@ -61,8 +61,8 @@ export function generateFile(program: ts.Program, sourceFile: ts.SourceFile, fil export function generateClass( program: ts.Program, - classDeclaration: ts.ClassDeclaration, - generate: (program: ts.Program, classDeclaration: ts.ClassDeclaration) => ts.SourceFile + classDeclaration: ts.ClassDeclaration | ts.InterfaceDeclaration, + generate: (program: ts.Program, classDeclaration: ts.ClassDeclaration | ts.InterfaceDeclaration) => ts.SourceFile ) { const sourceFileName = path.relative( path.join(path.dirname(program.getCompilerOptions().configFilePath as string), 'src'), @@ -83,11 +83,14 @@ export function generateClass( export default function createEmitter( jsDocMarker: string, - generate: (program: ts.Program, classDeclaration: ts.ClassDeclaration) => ts.SourceFile + generate: (program: ts.Program, classDeclaration: ts.ClassDeclaration | ts.InterfaceDeclaration) => ts.SourceFile ) { function scanSourceFile(program: ts.Program, sourceFile: ts.SourceFile) { for (const stmt of sourceFile.statements) { - if (ts.isClassDeclaration(stmt) && ts.getJSDocTags(stmt).some(t => t.tagName.text === jsDocMarker)) { + if ( + (ts.isClassDeclaration(stmt) || ts.isInterfaceDeclaration(stmt)) && + ts.getJSDocTags(stmt).some(t => t.tagName.text === jsDocMarker) + ) { generateClass(program, stmt, generate); } } diff --git a/packages/alphatab/scripts/JsonDeclarationEmitter.ts b/packages/alphatab/scripts/JsonDeclarationEmitter.ts index ec1fbdd36..43ef66788 100644 --- a/packages/alphatab/scripts/JsonDeclarationEmitter.ts +++ b/packages/alphatab/scripts/JsonDeclarationEmitter.ts @@ -129,7 +129,7 @@ function cloneJsDoc(node: T, source: ts.Node, additionalTags: function createJsonMember( program: ts.Program, - input: ts.PropertyDeclaration, + input: ts.PropertyDeclaration | ts.GetAccessorDeclaration, importer: (name: string, module: string) => void ): ts.TypeElement { const typeInfo = getTypeWithNullableInfo(program, input.type ?? program.getTypeChecker().getTypeAtLocation(input.name), true, false, undefined); @@ -147,17 +147,21 @@ function createJsonMember( function createJsonMembers( program: ts.Program, - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, importer: (name: string, module: string) => void ): ts.TypeElement[] { + const hasMatchingSetter = (name: string): boolean => + input.members.some(m => ts.isSetAccessorDeclaration(m) && (m.name as ts.Identifier).text === name); + return input.members .filter( m => - ts.isPropertyDeclaration(m) && - m.modifiers && - !m.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword) + (ts.isPropertyDeclaration(m) || ts.isGetAccessorDeclaration(m)) && + !m.modifiers?.find(m => m.kind === ts.SyntaxKind.StaticKeyword) && + !ts.getJSDocTags(m).find(t => t.tagName.text === 'json_ignore') && + (!ts.isGetAccessorDeclaration(m) || hasMatchingSetter((m.name as ts.Identifier).text)) ) - .map(m => createJsonMember(program, m as ts.PropertyDeclaration, importer)); + .map(m => createJsonMember(program, m as ts.PropertyDeclaration | ts.GetAccessorDeclaration, importer)); } let allJsonTypes: Map = new Map(); diff --git a/packages/alphatab/scripts/Serializer.fromJson.ts b/packages/alphatab/scripts/Serializer.fromJson.ts index 605f47f9b..5466da4b6 100644 --- a/packages/alphatab/scripts/Serializer.fromJson.ts +++ b/packages/alphatab/scripts/Serializer.fromJson.ts @@ -3,7 +3,7 @@ import * as ts from 'typescript'; import type { TypeSchema } from './TypeSchema'; function generateFromJsonBody( - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, serializable: TypeSchema, importer: (name: string, module: string) => void ) { @@ -33,7 +33,7 @@ function generateFromJsonBody( } export function createFromJsonMethod( - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, serializable: TypeSchema, importer: (name: string, module: string) => void ) { diff --git a/packages/alphatab/scripts/Serializer.setProperty.ts b/packages/alphatab/scripts/Serializer.setProperty.ts index ff75b644f..f216d996a 100644 --- a/packages/alphatab/scripts/Serializer.setProperty.ts +++ b/packages/alphatab/scripts/Serializer.setProperty.ts @@ -342,13 +342,17 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri importer(itemSerializer, findSerializerModule(prop.type)); if (prop.type.isNullable || prop.type.isOptional) { - importer(prop.type.typeAsString, prop.type.modulePath); + if (!prop.type.isRecord) { + // @record types are constructed via `{}` object literal (not `new T()`), so no value-import is needed. + importer(prop.type.typeAsString, prop.type.modulePath); + } + const constructExpr = prop.type.isRecord ? '{}' : `new ${prop.type.typeAsString}()`; caseStatements.push( createNodeFromSource( ` - if (v) { - obj.${fieldName} = new ${prop.type.typeAsString}(); - ${itemSerializer}.fromJson(obj.${fieldName}, v); + if (v) { + obj.${fieldName} = ${constructExpr}; + ${itemSerializer}.fromJson(obj.${fieldName}, v); } else { obj.${fieldName} = ${prop.type.isNullable ? 'null' : 'undefined'} }`, @@ -379,7 +383,8 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri const itemSerializer = `${prop.type.typeAsString}Serializer`; importer(itemSerializer, findSerializerModule(prop.type)); - if (prop.type.isNullable || prop.type.isOptional) { + if ((prop.type.isNullable || prop.type.isOptional) && !prop.type.isRecord) { + // @record types are constructed via `{}` object literal (not `new T()`), so no value-import is needed. importer(prop.type.typeAsString, prop.type.modulePath); } @@ -427,11 +432,13 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri ts.factory.createBlock( [ assignField( - ts.factory.createNewExpression( - ts.factory.createIdentifier(prop.type.typeAsString), - undefined, - [] - ) + prop.type.isRecord + ? ts.factory.createObjectLiteralExpression([], false) + : ts.factory.createNewExpression( + ts.factory.createIdentifier(prop.type.typeAsString), + undefined, + [] + ) ), ts.factory.createExpressionStatement( ts.factory.createCallExpression( @@ -456,7 +463,16 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri ], true ), - ts.factory.createBlock([assignField(ts.factory.createNull())], true) + ts.factory.createBlock( + [ + assignField( + prop.type.isOptional + ? ts.factory.createIdentifier('undefined') + : ts.factory.createNull() + ) + ], + true + ) ), ts.factory.createReturnStatement(ts.factory.createTrue()) ], @@ -509,11 +525,13 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri ), ts.factory.createBlock([ assignField( - ts.factory.createNewExpression( - ts.factory.createIdentifier(prop.type.typeAsString), - [], - [] - ) + prop.type.isRecord + ? ts.factory.createObjectLiteralExpression([], false) + : ts.factory.createNewExpression( + ts.factory.createIdentifier(prop.type.typeAsString), + [], + [] + ) ) ]) )), @@ -604,7 +622,7 @@ function generateSetPropertyBody(serializable: TypeSchema, importer: (name: stri } export function createSetPropertyMethod( - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, serializable: TypeSchema, importer: (name: string, module: string) => void ) { diff --git a/packages/alphatab/scripts/Serializer.toJson.ts b/packages/alphatab/scripts/Serializer.toJson.ts index ed2c5656b..2d7c301b3 100644 --- a/packages/alphatab/scripts/Serializer.toJson.ts +++ b/packages/alphatab/scripts/Serializer.toJson.ts @@ -283,14 +283,30 @@ function generateToJsonBody(serializable: TypeSchema, importer: (name: string, m } else { const itemSerializer = `${prop.type.typeAsString}Serializer`; importer(itemSerializer, findSerializerModule(prop.type)); - propertyStatements.push( - createNodeFromSource( - ` - o.set(${JSON.stringify(jsonName)}, ${itemSerializer}.toJson(obj.${fieldName})); - `, - ts.SyntaxKind.ExpressionStatement - ) - ); + if (prop.type.isRecord && (prop.type.isNullable || prop.type.isOptional)) { + // @record-typed optional / nullable fields skip emission when unset, so the JSON + // output omits null entries rather than carrying a Map value the C# JS-style + // TypeOf shim would render as `undefined` (TypeHelper.cs:606+). + propertyStatements.push( + createNodeFromSource( + ` + if(obj.${fieldName}) { + o.set(${JSON.stringify(jsonName)}, ${itemSerializer}.toJson(obj.${fieldName})); + } + `, + ts.SyntaxKind.IfStatement + ) + ); + } else { + propertyStatements.push( + createNodeFromSource( + ` + o.set(${JSON.stringify(jsonName)}, ${itemSerializer}.toJson(obj.${fieldName})); + `, + ts.SyntaxKind.ExpressionStatement + ) + ); + } } if (prop.target) { @@ -314,13 +330,13 @@ function generateToJsonBody(serializable: TypeSchema, importer: (name: string, m } export function createToJsonMethod( - input: ts.ClassDeclaration, + input: ts.ClassDeclaration | ts.InterfaceDeclaration, serializable: TypeSchema, importer: (name: string, module: string) => void ) { const methodDecl = createNodeFromSource( `public class Serializer { - public static toJson(obj: ${input.name!.text} | null): Map | null { + public static toJson(obj: ${input.name!.text} | null | undefined): Map | null { } }`, ts.SyntaxKind.MethodDeclaration diff --git a/packages/alphatab/scripts/TypeSchema.ts b/packages/alphatab/scripts/TypeSchema.ts index dce37d296..1eddfa5ad 100644 --- a/packages/alphatab/scripts/TypeSchema.ts +++ b/packages/alphatab/scripts/TypeSchema.ts @@ -15,6 +15,7 @@ export type TypeWithNullableInfo = { readonly modulePath: string; readonly isCloneable: boolean; readonly isJsonImmutable: boolean; + readonly isRecord: boolean; readonly isNumberType: boolean; readonly isMap: boolean; readonly isSet: boolean; @@ -28,25 +29,42 @@ export type TypeWithNullableInfo = { type Writeable = { -readonly [P in keyof T]: T[P] }; -export function buildTypeSchema(program: ts.Program, input: ts.ClassDeclaration) { +export function buildTypeSchema(program: ts.Program, input: ts.ClassDeclaration | ts.InterfaceDeclaration) { const schema: TypeSchema = { properties: [], isStrict: !!ts.getJSDocTags(input).find(t => t.tagName.text === 'json_strict'), hasToJsonExtension: false, - hasSetPropertyExtension: false + hasSetPropertyExtension: false, + isRecord: !!ts.getJSDocTags(input).find(t => t.tagName.text === 'record') }; + const accessorHasSetter = (cls: ts.ClassDeclaration | ts.InterfaceDeclaration, name: string): boolean => + cls.members.some(m => ts.isSetAccessorDeclaration(m) && (m.name as ts.Identifier).text === name); + const handleMember = ( - member: ts.ClassDeclaration['members'][0], + cls: ts.ClassDeclaration | ts.InterfaceDeclaration, + member: ts.ClassElement | ts.TypeElement, typeArgumentMapping: Map | undefined ) => { - if (ts.isPropertyDeclaration(member)) { - const propertyDeclaration = member as ts.PropertyDeclaration; + if ( + ts.isPropertyDeclaration(member) || + ts.isPropertySignature(member) || + ts.isGetAccessorDeclaration(member) + ) { + // Only the getter side of an accessor pair contributes a schema entry; the setter is + // handled implicitly via the assignment generated by the serializer. A getter without + // a matching setter is a computed read-only property and is skipped — it cannot be + // assigned to and writing it via toJson would just duplicate underlying state. if ( - !propertyDeclaration.modifiers!.find( - m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.PrivateKeyword - ) + ts.isGetAccessorDeclaration(member) && + !accessorHasSetter(cls, (member.name as ts.Identifier).text) ) { + return; + } + const isStaticOrPrivate = !!member.modifiers?.some( + m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.PrivateKeyword + ); + if (!isStaticOrPrivate) { const jsonNames = [(member.name as ts.Identifier).text.toLowerCase()]; const jsDoc = ts.getJSDocTags(member); @@ -57,20 +75,42 @@ export function buildTypeSchema(program: ts.Program, input: ts.ClassDeclaration) if (!jsDoc.find(t => t.tagName.text === 'json_ignore')) { const asRaw = !!jsDoc.find(t => t.tagName.text === 'json_raw'); const isReadonly = !!jsDoc.find(t => t.tagName.text === 'json_read_only'); + const isAccessor = ts.isGetAccessorDeclaration(member); + const isOptional = + (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) && + !!member.questionToken; + + // Heuristic: a deprecated getter+setter pair is almost always a + // backwards-compat alias for a canonical property — round-tripping it via + // toJson would duplicate state. Surface a warning so a human can decide + // whether to add @json_read_only (input-only) or @json_ignore (drop entirely). + if ( + isAccessor && + !isReadonly && + jsDoc.some(t => t.tagName.text === 'deprecated') + ) { + const sourceFile = member.getSourceFile(); + const { line } = sourceFile.getLineAndCharacterOfPosition(member.getStart()); + console.warn( + `[serializer] ${sourceFile.fileName}:${line + 1} - deprecated accessor ${(member.name as ts.Identifier).text}: consider @json_read_only (input-only legacy alias) or @json_ignore (drop from JSON entirely).` + ); + } schema.properties.push({ jsonNames: jsonNames, asRaw, partialNames: !!jsDoc.find(t => t.tagName.text === 'json_partial_names'), target: jsDoc.find(t => t.tagName.text === 'target')?.comment as string, isJsonReadOnly: isReadonly, - isReadOnly: propertyDeclaration.modifiers!.some(m => m.kind == ts.SyntaxKind.ReadonlyKeyword), + isReadOnly: isAccessor + ? false + : !!member.modifiers?.some(m => m.kind == ts.SyntaxKind.ReadonlyKeyword), name: (member.name as ts.Identifier).text, jsDocTags: jsDoc, type: getTypeWithNullableInfo( program, member.type ?? program.getTypeChecker().getTypeAtLocation(member.name), asRaw || isReadonly, - !!member.questionToken, + isOptional, typeArgumentMapping ) }); @@ -88,12 +128,12 @@ export function buildTypeSchema(program: ts.Program, input: ts.ClassDeclaration) } }; - let hierarchy: ts.ClassDeclaration | undefined = input; + let hierarchy: ts.ClassDeclaration | ts.InterfaceDeclaration | undefined = input; let typeArgumentMapping: Map | undefined; const checker = program.getTypeChecker(); while (hierarchy) { for (const x of hierarchy.members) { - handleMember(x, typeArgumentMapping); + handleMember(hierarchy, x, typeArgumentMapping); } const extendsClause = hierarchy.heritageClauses?.find(c => c.token === ts.SyntaxKind.ExtendsKeyword); @@ -146,6 +186,7 @@ export function getTypeWithNullableInfo( typeAsString: '', modulePath: '', isJsonImmutable: false, + isRecord: false, isNumberType: false, isMap: false, isSet: false, @@ -158,7 +199,17 @@ export function getTypeWithNullableInfo( let mainType: ts.Type | undefined; const fillBaseInfoFrom = (tsType: ts.Type) => { - const valueDeclaration = tsType.symbol?.valueDeclaration; + // For interfaces (e.g. @record types), there is no valueDeclaration; fall back to + // the first declaration if it is an InterfaceDeclaration. We intentionally do NOT + // fall back for generic classes etc., because picking up arbitrary declarations + // would mis-resolve type parameters and break unrelated emitters. + let valueDeclaration: ts.Declaration | undefined = tsType.symbol?.valueDeclaration; + if (!valueDeclaration && tsType.symbol?.declarations) { + const interfaceDecl = tsType.symbol.declarations.find(d => ts.isInterfaceDeclaration(d)); + if (interfaceDecl) { + valueDeclaration = interfaceDecl; + } + } mainType = tsType; typeInfo.typeAsString = checker.typeToString(tsType, undefined, undefined); @@ -176,6 +227,7 @@ export function getTypeWithNullableInfo( if (typeInfo.jsDocTags) { typeInfo.isJsonImmutable = !!typeInfo.jsDocTags.find(t => t.tagName.text === 'json_immutable'); typeInfo.isCloneable = !!typeInfo.jsDocTags.find(t => t.tagName.text === 'cloneable'); + typeInfo.isRecord = !!typeInfo.jsDocTags.find(t => t.tagName.text === 'record'); } if (tsType.flags & ts.ObjectFlags.Reference) { @@ -216,6 +268,7 @@ export function getTypeWithNullableInfo( modulePath: '', isCloneable: false, isJsonImmutable: false, + isRecord: false, isNumberType: true, isMap: false, isSet: false, @@ -388,6 +441,7 @@ export interface TypeSchema { isStrict: boolean; hasToJsonExtension: boolean; hasSetPropertyExtension: boolean; + isRecord: boolean; properties: TypeProperty[]; } diff --git a/packages/alphatab/src/Environment.ts b/packages/alphatab/src/Environment.ts index 70cebd901..8388f3bd0 100644 --- a/packages/alphatab/src/Environment.ts +++ b/packages/alphatab/src/Environment.ts @@ -566,31 +566,15 @@ export class Environment { private static _createDefaultStaveProfiles(): Map> { const staveProfiles = new Map>(); - - // the general layout is repeating the same pattern across the different notation staffs: - // * general effects before notation renderer, shown also if notation renderer is hidden (`before-xxxx-always`) - // * effects specific to the notation renderer, hidden if the nottation renderer is hidden (`before-xxxx-hideable`) - // * the notation renderer itself, hidden based on settings (`xxxx`) - - staveProfiles.set( - StaveProfile.Default, - new Set([ - SlashBarRenderer.StaffId, - ScoreBarRenderer.StaffId, - NumberedBarRenderer.StaffId, - TabBarRenderer.StaffId - ]) - ); - staveProfiles.set( - StaveProfile.ScoreTab, - new Set([ - SlashBarRenderer.StaffId, - ScoreBarRenderer.StaffId, - NumberedBarRenderer.StaffId, - TabBarRenderer.StaffId - ]) - ); - + const all = new Set([ + SlashBarRenderer.StaffId, + ScoreBarRenderer.StaffId, + NumberedBarRenderer.StaffId, + TabBarRenderer.StaffId + ]); + + staveProfiles.set(StaveProfile.Default, all); + staveProfiles.set(StaveProfile.ScoreTab, all); staveProfiles.set(StaveProfile.Score, new Set([ScoreBarRenderer.StaffId])); staveProfiles.set(StaveProfile.Tab, new Set([TabBarRenderer.StaffId])); staveProfiles.set(StaveProfile.TabMixed, new Set([TabBarRenderer.StaffId])); diff --git a/packages/alphatab/src/RenderingResources.ts b/packages/alphatab/src/RenderingResources.ts index beb2338d0..872383276 100644 --- a/packages/alphatab/src/RenderingResources.ts +++ b/packages/alphatab/src/RenderingResources.ts @@ -87,6 +87,7 @@ export class RenderingResources { * @defaultValue `bold 12px Arial, sans-serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreCopyright} + * @json_read_only */ public get copyrightFont(): Font { return this.elementFonts.get(NotationElement.ScoreCopyright)!; @@ -103,6 +104,7 @@ export class RenderingResources { * @defaultValue `32px Georgia, serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreTitle} + * @json_read_only */ public get titleFont(): Font { return this.elementFonts.get(NotationElement.ScoreTitle)!; @@ -120,6 +122,7 @@ export class RenderingResources { * @defaultValue `20px Georgia, serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreSubTitle} + * @json_read_only */ public get subTitleFont(): Font { return this.elementFonts.get(NotationElement.ScoreSubTitle)!; @@ -137,6 +140,7 @@ export class RenderingResources { * @defaultValue `15px Arial, sans-serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreWords} + * @json_read_only */ public get wordsFont(): Font { return this.elementFonts.get(NotationElement.ScoreWords)!; @@ -154,6 +158,7 @@ export class RenderingResources { * @defaultValue `12px Georgia, serif` * @since 1.4.0 * @deprecated use {@link elementFonts} with {@link NotationElement.EffectBeatTimer} + * @json_read_only */ public get timerFont(): Font { return this.elementFonts.get(NotationElement.EffectBeatTimer)!; @@ -171,6 +176,7 @@ export class RenderingResources { * @defaultValue `14px Georgia, serif` * @since 1.4.0 * @deprecated use {@link elementFonts} with {@link NotationElement.EffectDirections} + * @json_read_only */ public get directionsFont(): Font { return this.elementFonts.get(NotationElement.EffectDirections)!; @@ -188,6 +194,7 @@ export class RenderingResources { * @defaultValue `11px Arial, sans-serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.ChordDiagramFretboardNumbers} + * @json_read_only */ public get fretboardNumberFont(): Font { return this.elementFonts.get(NotationElement.ChordDiagramFretboardNumbers)!; @@ -223,6 +230,7 @@ export class RenderingResources { * @defaultValue `bold 14px Georgia, serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.EffectMarker} + * @json_read_only */ public get markerFont(): Font { return this.elementFonts.get(NotationElement.EffectMarker)!; @@ -249,6 +257,7 @@ export class RenderingResources { * @defaultValue `11px Arial, sans-serif` * @since 0.9.6 * @deprecated use {@link elementFonts} with {@link NotationElement.BarNumber} + * @json_read_only */ public get barNumberFont(): Font { return this.elementFonts.get(NotationElement.BarNumber)!; diff --git a/packages/alphatab/src/generated/CoreSettingsSerializer.ts b/packages/alphatab/src/generated/CoreSettingsSerializer.ts index 5b1dd0127..474245f45 100644 --- a/packages/alphatab/src/generated/CoreSettingsSerializer.ts +++ b/packages/alphatab/src/generated/CoreSettingsSerializer.ts @@ -17,7 +17,7 @@ export class CoreSettingsSerializer { } JsonHelper.forEach(m, (v, k) => CoreSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: CoreSettings | null): Map | null { + public static toJson(obj: CoreSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/DisplaySettingsSerializer.ts b/packages/alphatab/src/generated/DisplaySettingsSerializer.ts index c07b064b7..9a677038f 100644 --- a/packages/alphatab/src/generated/DisplaySettingsSerializer.ts +++ b/packages/alphatab/src/generated/DisplaySettingsSerializer.ts @@ -19,7 +19,7 @@ export class DisplaySettingsSerializer { } JsonHelper.forEach(m, (v, k) => DisplaySettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: DisplaySettings | null): Map | null { + public static toJson(obj: DisplaySettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/EngravingSettingsSerializer.ts b/packages/alphatab/src/generated/EngravingSettingsSerializer.ts index 19cc823e4..f6aee68c8 100644 --- a/packages/alphatab/src/generated/EngravingSettingsSerializer.ts +++ b/packages/alphatab/src/generated/EngravingSettingsSerializer.ts @@ -19,7 +19,7 @@ export class EngravingSettingsSerializer { } JsonHelper.forEach(m, (v, k) => EngravingSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: EngravingSettings | null): Map | null { + public static toJson(obj: EngravingSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/EngravingStemInfoSerializer.ts b/packages/alphatab/src/generated/EngravingStemInfoSerializer.ts index a414a4001..2da211f64 100644 --- a/packages/alphatab/src/generated/EngravingStemInfoSerializer.ts +++ b/packages/alphatab/src/generated/EngravingStemInfoSerializer.ts @@ -15,7 +15,7 @@ export class EngravingStemInfoSerializer { } JsonHelper.forEach(m, (v, k) => EngravingStemInfoSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: EngravingStemInfo | null): Map | null { + public static toJson(obj: EngravingStemInfo | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/ExporterSettingsSerializer.ts b/packages/alphatab/src/generated/ExporterSettingsSerializer.ts index 4f6b6d46e..93821bb6c 100644 --- a/packages/alphatab/src/generated/ExporterSettingsSerializer.ts +++ b/packages/alphatab/src/generated/ExporterSettingsSerializer.ts @@ -15,7 +15,7 @@ export class ExporterSettingsSerializer { } JsonHelper.forEach(m, (v, k) => ExporterSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: ExporterSettings | null): Map | null { + public static toJson(obj: ExporterSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/ImporterSettingsSerializer.ts b/packages/alphatab/src/generated/ImporterSettingsSerializer.ts index 90545e615..66c17f71c 100644 --- a/packages/alphatab/src/generated/ImporterSettingsSerializer.ts +++ b/packages/alphatab/src/generated/ImporterSettingsSerializer.ts @@ -15,7 +15,7 @@ export class ImporterSettingsSerializer { } JsonHelper.forEach(m, (v, k) => ImporterSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: ImporterSettings | null): Map | null { + public static toJson(obj: ImporterSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/NotationSettingsSerializer.ts b/packages/alphatab/src/generated/NotationSettingsSerializer.ts index 2ef43f289..446885435 100644 --- a/packages/alphatab/src/generated/NotationSettingsSerializer.ts +++ b/packages/alphatab/src/generated/NotationSettingsSerializer.ts @@ -19,7 +19,7 @@ export class NotationSettingsSerializer { } JsonHelper.forEach(m, (v, k) => NotationSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: NotationSettings | null): Map | null { + public static toJson(obj: NotationSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/PlayerSettingsSerializer.ts b/packages/alphatab/src/generated/PlayerSettingsSerializer.ts index 60c6dd2a7..82f02505c 100644 --- a/packages/alphatab/src/generated/PlayerSettingsSerializer.ts +++ b/packages/alphatab/src/generated/PlayerSettingsSerializer.ts @@ -20,7 +20,7 @@ export class PlayerSettingsSerializer { } JsonHelper.forEach(m, (v, k) => PlayerSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: PlayerSettings | null): Map | null { + public static toJson(obj: PlayerSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/RenderingResourcesJson.ts b/packages/alphatab/src/generated/RenderingResourcesJson.ts index 52e6d6ad0..50a2d7a8d 100644 --- a/packages/alphatab/src/generated/RenderingResourcesJson.ts +++ b/packages/alphatab/src/generated/RenderingResourcesJson.ts @@ -38,29 +38,77 @@ export interface RenderingResourcesJson { */ engravingSettings?: EngravingSettingsJson; /** - * Unused, see deprecation note. - * @defaultValue `14px Georgia, serif` + * The font to use for displaying the songs copyright information in the header of the music sheet. + * @defaultValue `bold 12px Arial, sans-serif` + * @since 0.9.6 + * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreCopyright} + * @json_read_only + */ + copyrightFont?: FontJson; + /** + * The font to use for displaying the songs title in the header of the music sheet. + * @defaultValue `32px Georgia, serif` * @since 0.9.6 - * @deprecated Since 1.7.0 alphaTab uses the glyphs contained in the SMuFL font - * @json_ignore + * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreTitle} + * @json_read_only */ - fingeringFont?: FontJson; + titleFont?: FontJson; /** - * Unused, see deprecation note. + * The font to use for displaying the songs subtitle in the header of the music sheet. + * @defaultValue `20px Georgia, serif` + * @since 0.9.6 + * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreSubTitle} + * @json_read_only + */ + subTitleFont?: FontJson; + /** + * The font to use for displaying the lyrics information in the header of the music sheet. + * @defaultValue `15px Arial, sans-serif` + * @since 0.9.6 + * @deprecated use {@link elementFonts} with {@link NotationElement.ScoreWords} + * @json_read_only + */ + wordsFont?: FontJson; + /** + * The font to use for displaying beat time information in the music sheet. * @defaultValue `12px Georgia, serif` * @since 1.4.0 - * @deprecated Since 1.7.0 alphaTab uses the glyphs contained in the SMuFL font - * @json_ignore + * @deprecated use {@link elementFonts} with {@link NotationElement.EffectBeatTimer} + * @json_read_only + */ + timerFont?: FontJson; + /** + * The font to use for displaying the directions texts. + * @defaultValue `14px Georgia, serif` + * @since 1.4.0 + * @deprecated use {@link elementFonts} with {@link NotationElement.EffectDirections} + * @json_read_only */ - inlineFingeringFont?: FontJson; + directionsFont?: FontJson; /** - * Ununsed, see deprecation note. - * @defaultValue `italic 12px Georgia, serif` + * The font to use for displaying the fretboard numbers in chord diagrams. + * @defaultValue `11px Arial, sans-serif` + * @since 0.9.6 + * @deprecated use {@link elementFonts} with {@link NotationElement.ChordDiagramFretboardNumbers} + * @json_read_only + */ + fretboardNumberFont?: FontJson; + /** + * The font to use for section marker labels shown above the music sheet. + * @defaultValue `bold 14px Georgia, serif` + * @since 0.9.6 + * @deprecated use {@link elementFonts} with {@link NotationElement.EffectMarker} + * @json_read_only + */ + markerFont?: FontJson; + /** + * The font to use for displaying the bar numbers above the music sheet. + * @defaultValue `11px Arial, sans-serif` * @since 0.9.6 - * @deprecated use {@link elementFonts} with the respective - * @json_ignore + * @deprecated use {@link elementFonts} with {@link NotationElement.BarNumber} + * @json_read_only */ - effectFont?: FontJson; + barNumberFont?: FontJson; /** * The fonts used by individual elements. Check `defaultFonts` for the elements which have custom fonts. * Removing fonts from this map can lead to unexpected side effects and errors. Only update it with new values. diff --git a/packages/alphatab/src/generated/RenderingResourcesSerializer.ts b/packages/alphatab/src/generated/RenderingResourcesSerializer.ts index b43047b54..ddd732c3e 100644 --- a/packages/alphatab/src/generated/RenderingResourcesSerializer.ts +++ b/packages/alphatab/src/generated/RenderingResourcesSerializer.ts @@ -19,7 +19,7 @@ export class RenderingResourcesSerializer { } JsonHelper.forEach(m, (v, k) => RenderingResourcesSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: RenderingResources | null): Map | null { + public static toJson(obj: RenderingResources | null | undefined): Map | null { if (!obj) { return null; } @@ -50,6 +50,33 @@ export class RenderingResourcesSerializer { case "smuflfontfamilyname": obj.smuflFontFamilyName = v as string | undefined; return true; + case "copyrightfont": + obj.copyrightFont = Font.fromJson(v)!; + return true; + case "titlefont": + obj.titleFont = Font.fromJson(v)!; + return true; + case "subtitlefont": + obj.subTitleFont = Font.fromJson(v)!; + return true; + case "wordsfont": + obj.wordsFont = Font.fromJson(v)!; + return true; + case "timerfont": + obj.timerFont = Font.fromJson(v)!; + return true; + case "directionsfont": + obj.directionsFont = Font.fromJson(v)!; + return true; + case "fretboardnumberfont": + obj.fretboardNumberFont = Font.fromJson(v)!; + return true; + case "markerfont": + obj.markerFont = Font.fromJson(v)!; + return true; + case "barnumberfont": + obj.barNumberFont = Font.fromJson(v)!; + return true; case "elementfonts": JsonHelper.forEach(v, (v, k) => { obj.elementFonts.set(JsonHelper.parseEnum(k, NotationElement)!, Font.fromJson(v)!); diff --git a/packages/alphatab/src/generated/SettingsSerializer.ts b/packages/alphatab/src/generated/SettingsSerializer.ts index 091f7023f..1b65ccbec 100644 --- a/packages/alphatab/src/generated/SettingsSerializer.ts +++ b/packages/alphatab/src/generated/SettingsSerializer.ts @@ -21,7 +21,7 @@ export class SettingsSerializer { } JsonHelper.forEach(m, (v, k) => SettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Settings | null): Map | null { + public static toJson(obj: Settings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/SlidePlaybackSettingsSerializer.ts b/packages/alphatab/src/generated/SlidePlaybackSettingsSerializer.ts index 1d382a1b4..6b2b115d9 100644 --- a/packages/alphatab/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/packages/alphatab/src/generated/SlidePlaybackSettingsSerializer.ts @@ -15,7 +15,7 @@ export class SlidePlaybackSettingsSerializer { } JsonHelper.forEach(m, (v, k) => SlidePlaybackSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: SlidePlaybackSettings | null): Map | null { + public static toJson(obj: SlidePlaybackSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/VibratoPlaybackSettingsSerializer.ts b/packages/alphatab/src/generated/VibratoPlaybackSettingsSerializer.ts index 05033d0c3..4f56fc5d8 100644 --- a/packages/alphatab/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/packages/alphatab/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -15,7 +15,7 @@ export class VibratoPlaybackSettingsSerializer { } JsonHelper.forEach(m, (v, k) => VibratoPlaybackSettingsSerializer.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: VibratoPlaybackSettings | null): Map | null { + public static toJson(obj: VibratoPlaybackSettings | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/AutomationSerializer.ts b/packages/alphatab/src/generated/model/AutomationSerializer.ts index aa09881d4..1794f4c02 100644 --- a/packages/alphatab/src/generated/model/AutomationSerializer.ts +++ b/packages/alphatab/src/generated/model/AutomationSerializer.ts @@ -18,7 +18,7 @@ export class AutomationSerializer { } JsonHelper.forEach(m, (v, k) => AutomationSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Automation | null): Map | null { + public static toJson(obj: Automation | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/BackingTrackSerializer.ts b/packages/alphatab/src/generated/model/BackingTrackSerializer.ts index b2087d22e..a3fe746de 100644 --- a/packages/alphatab/src/generated/model/BackingTrackSerializer.ts +++ b/packages/alphatab/src/generated/model/BackingTrackSerializer.ts @@ -15,7 +15,7 @@ export class BackingTrackSerializer { } JsonHelper.forEach(m, (v, k) => BackingTrackSerializer.setProperty(obj, k, v)); } - public static toJson(obj: BackingTrack | null): Map | null { + public static toJson(obj: BackingTrack | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/BarSerializer.ts b/packages/alphatab/src/generated/model/BarSerializer.ts index fc757c6df..67bdce6e2 100644 --- a/packages/alphatab/src/generated/model/BarSerializer.ts +++ b/packages/alphatab/src/generated/model/BarSerializer.ts @@ -7,6 +7,10 @@ import { Bar } from "@coderline/alphatab/model/Bar"; import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; import { VoiceSerializer } from "@coderline/alphatab/generated/model/VoiceSerializer"; import { SustainPedalMarkerSerializer } from "@coderline/alphatab/generated/model/SustainPedalMarkerSerializer"; +import { ScoreBarOverrideSerializer } from "@coderline/alphatab/generated/model/ScoreBarOverrideSerializer"; +import { TabBarOverrideSerializer } from "@coderline/alphatab/generated/model/TabBarOverrideSerializer"; +import { SlashBarOverrideSerializer } from "@coderline/alphatab/generated/model/SlashBarOverrideSerializer"; +import { NumberedBarOverrideSerializer } from "@coderline/alphatab/generated/model/NumberedBarOverrideSerializer"; import { BarStyleSerializer } from "@coderline/alphatab/generated/model/BarStyleSerializer"; import { Clef } from "@coderline/alphatab/model/Clef"; import { Ottavia } from "@coderline/alphatab/model/Ottavia"; @@ -28,7 +32,7 @@ export class BarSerializer { } JsonHelper.forEach(m, (v, k) => BarSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Bar | null): Map | null { + public static toJson(obj: Bar | null | undefined): Map | null { if (!obj) { return null; } @@ -46,6 +50,18 @@ export class BarSerializer { o.set("keysignature", obj.keySignature as number); o.set("keysignaturetype", obj.keySignatureType as number); o.set("barnumberdisplay", obj.barNumberDisplay as number | undefined); + if (obj.scoreDisplay) { + o.set("scoredisplay", ScoreBarOverrideSerializer.toJson(obj.scoreDisplay)); + } + if (obj.tabDisplay) { + o.set("tabdisplay", TabBarOverrideSerializer.toJson(obj.tabDisplay)); + } + if (obj.slashDisplay) { + o.set("slashdisplay", SlashBarOverrideSerializer.toJson(obj.slashDisplay)); + } + if (obj.numberedDisplay) { + o.set("numbereddisplay", NumberedBarOverrideSerializer.toJson(obj.numberedDisplay)); + } if (obj.style) { o.set("style", BarStyleSerializer.toJson(obj.style)); } @@ -102,6 +118,42 @@ export class BarSerializer { case "barnumberdisplay": obj.barNumberDisplay = JsonHelper.parseEnum(v, BarNumberDisplay); return true; + case "scoredisplay": + if (v) { + obj.scoreDisplay = {}; + ScoreBarOverrideSerializer.fromJson(obj.scoreDisplay, v); + } + else { + obj.scoreDisplay = undefined; + } + return true; + case "tabdisplay": + if (v) { + obj.tabDisplay = {}; + TabBarOverrideSerializer.fromJson(obj.tabDisplay, v); + } + else { + obj.tabDisplay = undefined; + } + return true; + case "slashdisplay": + if (v) { + obj.slashDisplay = {}; + SlashBarOverrideSerializer.fromJson(obj.slashDisplay, v); + } + else { + obj.slashDisplay = undefined; + } + return true; + case "numbereddisplay": + if (v) { + obj.numberedDisplay = {}; + NumberedBarOverrideSerializer.fromJson(obj.numberedDisplay, v); + } + else { + obj.numberedDisplay = undefined; + } + return true; case "style": if (v) { obj.style = new BarStyle(); diff --git a/packages/alphatab/src/generated/model/BarStyleSerializer.ts b/packages/alphatab/src/generated/model/BarStyleSerializer.ts index f6cf52e04..24e2cb431 100644 --- a/packages/alphatab/src/generated/model/BarStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/BarStyleSerializer.ts @@ -17,7 +17,7 @@ export class BarStyleSerializer { } JsonHelper.forEach(m, (v, k) => BarStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: BarStyle | null): Map | null { + public static toJson(obj: BarStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/BeamingRulesSerializer.ts b/packages/alphatab/src/generated/model/BeamingRulesSerializer.ts index b0f7c779b..7afe3594d 100644 --- a/packages/alphatab/src/generated/model/BeamingRulesSerializer.ts +++ b/packages/alphatab/src/generated/model/BeamingRulesSerializer.ts @@ -16,7 +16,7 @@ export class BeamingRulesSerializer { } JsonHelper.forEach(m, (v, k) => BeamingRulesSerializer.setProperty(obj, k, v)); } - public static toJson(obj: BeamingRules | null): Map | null { + public static toJson(obj: BeamingRules | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/BeatSerializer.ts b/packages/alphatab/src/generated/model/BeatSerializer.ts index bcc414c25..d8e2461b9 100644 --- a/packages/alphatab/src/generated/model/BeatSerializer.ts +++ b/packages/alphatab/src/generated/model/BeatSerializer.ts @@ -42,7 +42,7 @@ export class BeatSerializer { } JsonHelper.forEach(m, (v, k) => BeatSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Beat | null): Map | null { + public static toJson(obj: Beat | null | undefined): Map | null { if (!obj) { return null; } @@ -141,6 +141,9 @@ export class BeatSerializer { case "dots": obj.dots = v! as number; return true; + case "fadein": + obj.fadeIn = v! as boolean; + return true; case "fade": obj.fade = JsonHelper.parseEnum(v, FadeType)!; return true; @@ -214,6 +217,9 @@ export class BeatSerializer { obj.tremoloPicking = undefined; } return true; + case "tremolospeed": + obj.tremoloSpeed = JsonHelper.parseEnum(v, Duration) ?? null; + return true; case "crescendo": obj.crescendo = JsonHelper.parseEnum(v, CrescendoType)!; return true; diff --git a/packages/alphatab/src/generated/model/BeatStyleSerializer.ts b/packages/alphatab/src/generated/model/BeatStyleSerializer.ts index 05535677d..26ffe404a 100644 --- a/packages/alphatab/src/generated/model/BeatStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/BeatStyleSerializer.ts @@ -17,7 +17,7 @@ export class BeatStyleSerializer { } JsonHelper.forEach(m, (v, k) => BeatStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: BeatStyle | null): Map | null { + public static toJson(obj: BeatStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/BendPointSerializer.ts b/packages/alphatab/src/generated/model/BendPointSerializer.ts index 69d28ef8e..d65aa43cf 100644 --- a/packages/alphatab/src/generated/model/BendPointSerializer.ts +++ b/packages/alphatab/src/generated/model/BendPointSerializer.ts @@ -15,7 +15,7 @@ export class BendPointSerializer { } JsonHelper.forEach(m, (v, k) => BendPointSerializer.setProperty(obj, k, v)); } - public static toJson(obj: BendPoint | null): Map | null { + public static toJson(obj: BendPoint | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/ChordSerializer.ts b/packages/alphatab/src/generated/model/ChordSerializer.ts index ceda18235..c329146d6 100644 --- a/packages/alphatab/src/generated/model/ChordSerializer.ts +++ b/packages/alphatab/src/generated/model/ChordSerializer.ts @@ -15,7 +15,7 @@ export class ChordSerializer { } JsonHelper.forEach(m, (v, k) => ChordSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Chord | null): Map | null { + public static toJson(obj: Chord | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/ElementDisplaySerializer.ts b/packages/alphatab/src/generated/model/ElementDisplaySerializer.ts new file mode 100644 index 000000000..d8283ff6f --- /dev/null +++ b/packages/alphatab/src/generated/model/ElementDisplaySerializer.ts @@ -0,0 +1,44 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { ElementDisplay } from "@coderline/alphatab/model/ElementDisplay"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { StaffPlacement } from "@coderline/alphatab/model/ElementDisplay"; +import { SystemDisplay } from "@coderline/alphatab/model/ElementDisplay"; +/** + * @internal + */ +export class ElementDisplaySerializer { + public static fromJson(obj: ElementDisplay, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => ElementDisplaySerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: ElementDisplay | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + o.set("isvisible", obj.isVisible); + o.set("staffplacement", obj.staffPlacement as number | undefined); + o.set("systemdisplay", obj.systemDisplay as number | undefined); + return o; + } + public static setProperty(obj: ElementDisplay, property: string, v: unknown): boolean { + switch (property) { + case "isvisible": + obj.isVisible = v as boolean | undefined; + return true; + case "staffplacement": + obj.staffPlacement = JsonHelper.parseEnum(v, StaffPlacement); + return true; + case "systemdisplay": + obj.systemDisplay = JsonHelper.parseEnum(v, SystemDisplay); + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/FermataSerializer.ts b/packages/alphatab/src/generated/model/FermataSerializer.ts index 1aa480951..30d6110da 100644 --- a/packages/alphatab/src/generated/model/FermataSerializer.ts +++ b/packages/alphatab/src/generated/model/FermataSerializer.ts @@ -16,7 +16,7 @@ export class FermataSerializer { } JsonHelper.forEach(m, (v, k) => FermataSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Fermata | null): Map | null { + public static toJson(obj: Fermata | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/HeaderFooterStyleSerializer.ts b/packages/alphatab/src/generated/model/HeaderFooterStyleSerializer.ts index 56b524ea2..7340aa43e 100644 --- a/packages/alphatab/src/generated/model/HeaderFooterStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/HeaderFooterStyleSerializer.ts @@ -16,7 +16,7 @@ export class HeaderFooterStyleSerializer { } JsonHelper.forEach(m, (v, k) => HeaderFooterStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: HeaderFooterStyle | null): Map | null { + public static toJson(obj: HeaderFooterStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/InstrumentArticulationSerializer.ts b/packages/alphatab/src/generated/model/InstrumentArticulationSerializer.ts index ba1fd5228..8dd1e61e6 100644 --- a/packages/alphatab/src/generated/model/InstrumentArticulationSerializer.ts +++ b/packages/alphatab/src/generated/model/InstrumentArticulationSerializer.ts @@ -17,7 +17,7 @@ export class InstrumentArticulationSerializer { } JsonHelper.forEach(m, (v, k) => InstrumentArticulationSerializer.setProperty(obj, k, v)); } - public static toJson(obj: InstrumentArticulation | null): Map | null { + public static toJson(obj: InstrumentArticulation | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/MasterBarSerializer.ts b/packages/alphatab/src/generated/model/MasterBarSerializer.ts index 4c9d2b9d5..824686884 100644 --- a/packages/alphatab/src/generated/model/MasterBarSerializer.ts +++ b/packages/alphatab/src/generated/model/MasterBarSerializer.ts @@ -9,6 +9,8 @@ import { BeamingRulesSerializer } from "@coderline/alphatab/generated/model/Beam import { SectionSerializer } from "@coderline/alphatab/generated/model/SectionSerializer"; import { AutomationSerializer } from "@coderline/alphatab/generated/model/AutomationSerializer"; import { FermataSerializer } from "@coderline/alphatab/generated/model/FermataSerializer"; +import { KeySignature } from "@coderline/alphatab/model/KeySignature"; +import { KeySignatureType } from "@coderline/alphatab/model/KeySignatureType"; import { BeamingRules } from "@coderline/alphatab/model/MasterBar"; import { TripletFeel } from "@coderline/alphatab/model/TripletFeel"; import { Section } from "@coderline/alphatab/model/Section"; @@ -25,7 +27,7 @@ export class MasterBarSerializer { } JsonHelper.forEach(m, (v, k) => MasterBarSerializer.setProperty(obj, k, v)); } - public static toJson(obj: MasterBar | null): Map | null { + public static toJson(obj: MasterBar | null | undefined): Map | null { if (!obj) { return null; } @@ -74,6 +76,12 @@ export class MasterBarSerializer { case "alternateendings": obj.alternateEndings = v! as number; return true; + case "keysignature": + obj.keySignature = JsonHelper.parseEnum(v, KeySignature)!; + return true; + case "keysignaturetype": + obj.keySignatureType = JsonHelper.parseEnum(v, KeySignatureType)!; + return true; case "isdoublebar": obj.isDoubleBar = v! as boolean; return true; diff --git a/packages/alphatab/src/generated/model/NoteSerializer.ts b/packages/alphatab/src/generated/model/NoteSerializer.ts index 559de5dc5..873f99277 100644 --- a/packages/alphatab/src/generated/model/NoteSerializer.ts +++ b/packages/alphatab/src/generated/model/NoteSerializer.ts @@ -31,7 +31,7 @@ export class NoteSerializer { } JsonHelper.forEach(m, (v, k) => NoteSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Note | null): Map | null { + public static toJson(obj: Note | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/NoteStyleSerializer.ts b/packages/alphatab/src/generated/model/NoteStyleSerializer.ts index defb596bf..6615c5bbc 100644 --- a/packages/alphatab/src/generated/model/NoteStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/NoteStyleSerializer.ts @@ -18,7 +18,7 @@ export class NoteStyleSerializer { } JsonHelper.forEach(m, (v, k) => NoteStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: NoteStyle | null): Map | null { + public static toJson(obj: NoteStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/NumberedBarOverrideSerializer.ts b/packages/alphatab/src/generated/model/NumberedBarOverrideSerializer.ts new file mode 100644 index 000000000..5e9b8dee3 --- /dev/null +++ b/packages/alphatab/src/generated/model/NumberedBarOverrideSerializer.ts @@ -0,0 +1,49 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { NumberedBarOverride } from "@coderline/alphatab/model/BarOverrides"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class NumberedBarOverrideSerializer { + public static fromJson(obj: NumberedBarOverride, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => NumberedBarOverrideSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: NumberedBarOverride | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: NumberedBarOverride, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/NumberedStaffConfigSerializer.ts b/packages/alphatab/src/generated/model/NumberedStaffConfigSerializer.ts new file mode 100644 index 000000000..c600eff1e --- /dev/null +++ b/packages/alphatab/src/generated/model/NumberedStaffConfigSerializer.ts @@ -0,0 +1,49 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { NumberedStaffConfig } from "@coderline/alphatab/model/StaffConfigs"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class NumberedStaffConfigSerializer { + public static fromJson(obj: NumberedStaffConfig, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => NumberedStaffConfigSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: NumberedStaffConfig | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: NumberedStaffConfig, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/PlaybackInformationSerializer.ts b/packages/alphatab/src/generated/model/PlaybackInformationSerializer.ts index 2535de92e..d53ddbb95 100644 --- a/packages/alphatab/src/generated/model/PlaybackInformationSerializer.ts +++ b/packages/alphatab/src/generated/model/PlaybackInformationSerializer.ts @@ -15,7 +15,7 @@ export class PlaybackInformationSerializer { } JsonHelper.forEach(m, (v, k) => PlaybackInformationSerializer.setProperty(obj, k, v)); } - public static toJson(obj: PlaybackInformation | null): Map | null { + public static toJson(obj: PlaybackInformation | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts b/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts index 10ac9a9ac..a3595739a 100644 --- a/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts +++ b/packages/alphatab/src/generated/model/RenderStylesheetSerializer.ts @@ -5,6 +5,10 @@ // import { RenderStylesheet } from "@coderline/alphatab/model/RenderStylesheet"; import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ScoreStaffConfigSerializer } from "@coderline/alphatab/generated/model/ScoreStaffConfigSerializer"; +import { TabStaffConfigSerializer } from "@coderline/alphatab/generated/model/TabStaffConfigSerializer"; +import { SlashStaffConfigSerializer } from "@coderline/alphatab/generated/model/SlashStaffConfigSerializer"; +import { NumberedStaffConfigSerializer } from "@coderline/alphatab/generated/model/NumberedStaffConfigSerializer"; import { BracketExtendMode } from "@coderline/alphatab/model/RenderStylesheet"; import { TrackNamePolicy } from "@coderline/alphatab/model/RenderStylesheet"; import { TrackNameMode } from "@coderline/alphatab/model/RenderStylesheet"; @@ -20,7 +24,7 @@ export class RenderStylesheetSerializer { } JsonHelper.forEach(m, (v, k) => RenderStylesheetSerializer.setProperty(obj, k, v)); } - public static toJson(obj: RenderStylesheet | null): Map | null { + public static toJson(obj: RenderStylesheet | null | undefined): Map | null { if (!obj) { return null; } @@ -64,6 +68,10 @@ export class RenderStylesheetSerializer { o.set("hideemptystavesinfirstsystem", obj.hideEmptyStavesInFirstSystem); o.set("showsinglestaffbrackets", obj.showSingleStaffBrackets); o.set("barnumberdisplay", obj.barNumberDisplay as number); + o.set("scoreconfig", ScoreStaffConfigSerializer.toJson(obj.scoreConfig)); + o.set("tabconfig", TabStaffConfigSerializer.toJson(obj.tabConfig)); + o.set("slashconfig", SlashStaffConfigSerializer.toJson(obj.slashConfig)); + o.set("numberedconfig", NumberedStaffConfigSerializer.toJson(obj.numberedConfig)); return o; } public static setProperty(obj: RenderStylesheet, property: string, v: unknown): boolean { @@ -137,6 +145,18 @@ export class RenderStylesheetSerializer { case "barnumberdisplay": obj.barNumberDisplay = JsonHelper.parseEnum(v, BarNumberDisplay)!; return true; + case "scoreconfig": + ScoreStaffConfigSerializer.fromJson(obj.scoreConfig, v); + return true; + case "tabconfig": + TabStaffConfigSerializer.fromJson(obj.tabConfig, v); + return true; + case "slashconfig": + SlashStaffConfigSerializer.fromJson(obj.slashConfig, v); + return true; + case "numberedconfig": + NumberedStaffConfigSerializer.fromJson(obj.numberedConfig, v); + return true; } return false; } diff --git a/packages/alphatab/src/generated/model/ScoreBarOverrideSerializer.ts b/packages/alphatab/src/generated/model/ScoreBarOverrideSerializer.ts new file mode 100644 index 000000000..30c2863d0 --- /dev/null +++ b/packages/alphatab/src/generated/model/ScoreBarOverrideSerializer.ts @@ -0,0 +1,75 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { ScoreBarOverride } from "@coderline/alphatab/model/BarOverrides"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class ScoreBarOverrideSerializer { + public static fromJson(obj: ScoreBarOverride, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => ScoreBarOverrideSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: ScoreBarOverride | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.clef) { + o.set("clef", ElementDisplaySerializer.toJson(obj.clef)); + } + if (obj.keySignature) { + o.set("keysignature", ElementDisplaySerializer.toJson(obj.keySignature)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: ScoreBarOverride, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["clef"].indexOf(property) >= 0) { + if (v) { + obj.clef = {}; + ElementDisplaySerializer.fromJson(obj.clef, v as Map); + } + else { + obj.clef = undefined; + } + return true; + } + if (["keysignature"].indexOf(property) >= 0) { + if (v) { + obj.keySignature = {}; + ElementDisplaySerializer.fromJson(obj.keySignature, v as Map); + } + else { + obj.keySignature = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/ScoreSerializer.ts b/packages/alphatab/src/generated/model/ScoreSerializer.ts index efd5c8400..c3f800f9b 100644 --- a/packages/alphatab/src/generated/model/ScoreSerializer.ts +++ b/packages/alphatab/src/generated/model/ScoreSerializer.ts @@ -24,7 +24,7 @@ export class ScoreSerializer { } JsonHelper.forEach(m, (v, k) => ScoreSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Score | null): Map | null { + public static toJson(obj: Score | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/ScoreStaffConfigSerializer.ts b/packages/alphatab/src/generated/model/ScoreStaffConfigSerializer.ts new file mode 100644 index 000000000..4b23e2e32 --- /dev/null +++ b/packages/alphatab/src/generated/model/ScoreStaffConfigSerializer.ts @@ -0,0 +1,75 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { ScoreStaffConfig } from "@coderline/alphatab/model/StaffConfigs"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class ScoreStaffConfigSerializer { + public static fromJson(obj: ScoreStaffConfig, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => ScoreStaffConfigSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: ScoreStaffConfig | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.clef) { + o.set("clef", ElementDisplaySerializer.toJson(obj.clef)); + } + if (obj.keySignature) { + o.set("keysignature", ElementDisplaySerializer.toJson(obj.keySignature)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: ScoreStaffConfig, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["clef"].indexOf(property) >= 0) { + if (v) { + obj.clef = {}; + ElementDisplaySerializer.fromJson(obj.clef, v as Map); + } + else { + obj.clef = undefined; + } + return true; + } + if (["keysignature"].indexOf(property) >= 0) { + if (v) { + obj.keySignature = {}; + ElementDisplaySerializer.fromJson(obj.keySignature, v as Map); + } + else { + obj.keySignature = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/ScoreStyleSerializer.ts b/packages/alphatab/src/generated/model/ScoreStyleSerializer.ts index 7176c5f96..7e512e71b 100644 --- a/packages/alphatab/src/generated/model/ScoreStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/ScoreStyleSerializer.ts @@ -19,7 +19,7 @@ export class ScoreStyleSerializer { } JsonHelper.forEach(m, (v, k) => ScoreStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: ScoreStyle | null): Map | null { + public static toJson(obj: ScoreStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/SectionSerializer.ts b/packages/alphatab/src/generated/model/SectionSerializer.ts index 75b14c19a..7e944c73e 100644 --- a/packages/alphatab/src/generated/model/SectionSerializer.ts +++ b/packages/alphatab/src/generated/model/SectionSerializer.ts @@ -15,7 +15,7 @@ export class SectionSerializer { } JsonHelper.forEach(m, (v, k) => SectionSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Section | null): Map | null { + public static toJson(obj: Section | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/SlashBarOverrideSerializer.ts b/packages/alphatab/src/generated/model/SlashBarOverrideSerializer.ts new file mode 100644 index 000000000..f9b073224 --- /dev/null +++ b/packages/alphatab/src/generated/model/SlashBarOverrideSerializer.ts @@ -0,0 +1,62 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { SlashBarOverride } from "@coderline/alphatab/model/BarOverrides"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class SlashBarOverrideSerializer { + public static fromJson(obj: SlashBarOverride, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => SlashBarOverrideSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: SlashBarOverride | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.keySignature) { + o.set("keysignature", ElementDisplaySerializer.toJson(obj.keySignature)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: SlashBarOverride, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["keysignature"].indexOf(property) >= 0) { + if (v) { + obj.keySignature = {}; + ElementDisplaySerializer.fromJson(obj.keySignature, v as Map); + } + else { + obj.keySignature = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/SlashStaffConfigSerializer.ts b/packages/alphatab/src/generated/model/SlashStaffConfigSerializer.ts new file mode 100644 index 000000000..a6fdba9bf --- /dev/null +++ b/packages/alphatab/src/generated/model/SlashStaffConfigSerializer.ts @@ -0,0 +1,62 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { SlashStaffConfig } from "@coderline/alphatab/model/StaffConfigs"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class SlashStaffConfigSerializer { + public static fromJson(obj: SlashStaffConfig, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => SlashStaffConfigSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: SlashStaffConfig | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.keySignature) { + o.set("keysignature", ElementDisplaySerializer.toJson(obj.keySignature)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: SlashStaffConfig, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["keysignature"].indexOf(property) >= 0) { + if (v) { + obj.keySignature = {}; + ElementDisplaySerializer.fromJson(obj.keySignature, v as Map); + } + else { + obj.keySignature = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/StaffSerializer.ts b/packages/alphatab/src/generated/model/StaffSerializer.ts index 2fefcc21d..5724ee38f 100644 --- a/packages/alphatab/src/generated/model/StaffSerializer.ts +++ b/packages/alphatab/src/generated/model/StaffSerializer.ts @@ -8,6 +8,10 @@ import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; import { BarSerializer } from "@coderline/alphatab/generated/model/BarSerializer"; import { ChordSerializer } from "@coderline/alphatab/generated/model/ChordSerializer"; import { TuningSerializer } from "@coderline/alphatab/generated/model/TuningSerializer"; +import { ScoreStaffConfigSerializer } from "@coderline/alphatab/generated/model/ScoreStaffConfigSerializer"; +import { TabStaffConfigSerializer } from "@coderline/alphatab/generated/model/TabStaffConfigSerializer"; +import { SlashStaffConfigSerializer } from "@coderline/alphatab/generated/model/SlashStaffConfigSerializer"; +import { NumberedStaffConfigSerializer } from "@coderline/alphatab/generated/model/NumberedStaffConfigSerializer"; import { Bar } from "@coderline/alphatab/model/Bar"; import { Chord } from "@coderline/alphatab/model/Chord"; /** @@ -20,7 +24,7 @@ export class StaffSerializer { } JsonHelper.forEach(m, (v, k) => StaffSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Staff | null): Map | null { + public static toJson(obj: Staff | null | undefined): Map | null { if (!obj) { return null; } @@ -41,6 +45,18 @@ export class StaffSerializer { o.set("shownumbered", obj.showNumbered); o.set("showtablature", obj.showTablature); o.set("showstandardnotation", obj.showStandardNotation); + if (obj.scoreConfig) { + o.set("scoreconfig", ScoreStaffConfigSerializer.toJson(obj.scoreConfig)); + } + if (obj.tabConfig) { + o.set("tabconfig", TabStaffConfigSerializer.toJson(obj.tabConfig)); + } + if (obj.slashConfig) { + o.set("slashconfig", SlashStaffConfigSerializer.toJson(obj.slashConfig)); + } + if (obj.numberedConfig) { + o.set("numberedconfig", NumberedStaffConfigSerializer.toJson(obj.numberedConfig)); + } o.set("ispercussion", obj.isPercussion); o.set("standardnotationlinecount", obj.standardNotationLineCount); return o; @@ -87,6 +103,42 @@ export class StaffSerializer { case "showstandardnotation": obj.showStandardNotation = v! as boolean; return true; + case "scoreconfig": + if (v) { + obj.scoreConfig = {}; + ScoreStaffConfigSerializer.fromJson(obj.scoreConfig, v); + } + else { + obj.scoreConfig = undefined; + } + return true; + case "tabconfig": + if (v) { + obj.tabConfig = {}; + TabStaffConfigSerializer.fromJson(obj.tabConfig, v); + } + else { + obj.tabConfig = undefined; + } + return true; + case "slashconfig": + if (v) { + obj.slashConfig = {}; + SlashStaffConfigSerializer.fromJson(obj.slashConfig, v); + } + else { + obj.slashConfig = undefined; + } + return true; + case "numberedconfig": + if (v) { + obj.numberedConfig = {}; + NumberedStaffConfigSerializer.fromJson(obj.numberedConfig, v); + } + else { + obj.numberedConfig = undefined; + } + return true; case "ispercussion": obj.isPercussion = v! as boolean; return true; diff --git a/packages/alphatab/src/generated/model/SustainPedalMarkerSerializer.ts b/packages/alphatab/src/generated/model/SustainPedalMarkerSerializer.ts index e5d7021f1..5bbf8026d 100644 --- a/packages/alphatab/src/generated/model/SustainPedalMarkerSerializer.ts +++ b/packages/alphatab/src/generated/model/SustainPedalMarkerSerializer.ts @@ -16,7 +16,7 @@ export class SustainPedalMarkerSerializer { } JsonHelper.forEach(m, (v, k) => SustainPedalMarkerSerializer.setProperty(obj, k, v)); } - public static toJson(obj: SustainPedalMarker | null): Map | null { + public static toJson(obj: SustainPedalMarker | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/SyncPointDataSerializer.ts b/packages/alphatab/src/generated/model/SyncPointDataSerializer.ts index 1feab991b..03829daaf 100644 --- a/packages/alphatab/src/generated/model/SyncPointDataSerializer.ts +++ b/packages/alphatab/src/generated/model/SyncPointDataSerializer.ts @@ -15,7 +15,7 @@ export class SyncPointDataSerializer { } JsonHelper.forEach(m, (v, k) => SyncPointDataSerializer.setProperty(obj, k, v)); } - public static toJson(obj: SyncPointData | null): Map | null { + public static toJson(obj: SyncPointData | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/TabBarOverrideSerializer.ts b/packages/alphatab/src/generated/model/TabBarOverrideSerializer.ts new file mode 100644 index 000000000..400634001 --- /dev/null +++ b/packages/alphatab/src/generated/model/TabBarOverrideSerializer.ts @@ -0,0 +1,62 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { TabBarOverride } from "@coderline/alphatab/model/BarOverrides"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +/** + * @internal + */ +export class TabBarOverrideSerializer { + public static fromJson(obj: TabBarOverride, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => TabBarOverrideSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: TabBarOverride | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.clef) { + o.set("clef", ElementDisplaySerializer.toJson(obj.clef)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + return o; + } + public static setProperty(obj: TabBarOverride, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + } + if (["clef"].indexOf(property) >= 0) { + if (v) { + obj.clef = {}; + ElementDisplaySerializer.fromJson(obj.clef, v as Map); + } + else { + obj.clef = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/TabStaffConfigSerializer.ts b/packages/alphatab/src/generated/model/TabStaffConfigSerializer.ts new file mode 100644 index 000000000..81a16251a --- /dev/null +++ b/packages/alphatab/src/generated/model/TabStaffConfigSerializer.ts @@ -0,0 +1,80 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { TabStaffConfig } from "@coderline/alphatab/model/StaffConfigs"; +import { JsonHelper } from "@coderline/alphatab/io/JsonHelper"; +import { ElementDisplaySerializer } from "@coderline/alphatab/generated/model/ElementDisplaySerializer"; +import { BarNumberDisplay } from "@coderline/alphatab/model/RenderStylesheet"; +import { TabRhythmMode } from "@coderline/alphatab/NotationSettings"; +/** + * @internal + */ +export class TabStaffConfigSerializer { + public static fromJson(obj: TabStaffConfig, m: unknown): void { + if (!m) { + return; + } + JsonHelper.forEach(m, (v, k) => TabStaffConfigSerializer.setProperty(obj, k.toLowerCase(), v)); + } + public static toJson(obj: TabStaffConfig | null | undefined): Map | null { + if (!obj) { + return null; + } + const o = new Map(); + if (obj.clef) { + o.set("clef", ElementDisplaySerializer.toJson(obj.clef)); + } + if (obj.timeSignature) { + o.set("timesignature", ElementDisplaySerializer.toJson(obj.timeSignature)); + } + o.set("barnumber", obj.barNumber as number | undefined); + o.set("rhythm", obj.rhythm as number | undefined); + if (obj.rests) { + o.set("rests", ElementDisplaySerializer.toJson(obj.rests)); + } + return o; + } + public static setProperty(obj: TabStaffConfig, property: string, v: unknown): boolean { + switch (property) { + case "barnumber": + obj.barNumber = JsonHelper.parseEnum(v, BarNumberDisplay); + return true; + case "rhythm": + obj.rhythm = JsonHelper.parseEnum(v, TabRhythmMode); + return true; + } + if (["clef"].indexOf(property) >= 0) { + if (v) { + obj.clef = {}; + ElementDisplaySerializer.fromJson(obj.clef, v as Map); + } + else { + obj.clef = undefined; + } + return true; + } + if (["timesignature"].indexOf(property) >= 0) { + if (v) { + obj.timeSignature = {}; + ElementDisplaySerializer.fromJson(obj.timeSignature, v as Map); + } + else { + obj.timeSignature = undefined; + } + return true; + } + if (["rests"].indexOf(property) >= 0) { + if (v) { + obj.rests = {}; + ElementDisplaySerializer.fromJson(obj.rests, v as Map); + } + else { + obj.rests = undefined; + } + return true; + } + return false; + } +} diff --git a/packages/alphatab/src/generated/model/TrackSerializer.ts b/packages/alphatab/src/generated/model/TrackSerializer.ts index 3f72b0a92..9965daa04 100644 --- a/packages/alphatab/src/generated/model/TrackSerializer.ts +++ b/packages/alphatab/src/generated/model/TrackSerializer.ts @@ -23,7 +23,7 @@ export class TrackSerializer { } JsonHelper.forEach(m, (v, k) => TrackSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Track | null): Map | null { + public static toJson(obj: Track | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/TrackStyleSerializer.ts b/packages/alphatab/src/generated/model/TrackStyleSerializer.ts index f0dfc7dd1..31862b2e0 100644 --- a/packages/alphatab/src/generated/model/TrackStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/TrackStyleSerializer.ts @@ -17,7 +17,7 @@ export class TrackStyleSerializer { } JsonHelper.forEach(m, (v, k) => TrackStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: TrackStyle | null): Map | null { + public static toJson(obj: TrackStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/TremoloPickingEffectSerializer.ts b/packages/alphatab/src/generated/model/TremoloPickingEffectSerializer.ts index 7150e3f7c..3f280b23d 100644 --- a/packages/alphatab/src/generated/model/TremoloPickingEffectSerializer.ts +++ b/packages/alphatab/src/generated/model/TremoloPickingEffectSerializer.ts @@ -16,7 +16,7 @@ export class TremoloPickingEffectSerializer { } JsonHelper.forEach(m, (v, k) => TremoloPickingEffectSerializer.setProperty(obj, k, v)); } - public static toJson(obj: TremoloPickingEffect | null): Map | null { + public static toJson(obj: TremoloPickingEffect | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/TuningSerializer.ts b/packages/alphatab/src/generated/model/TuningSerializer.ts index 6a81cf9ed..037ea0ed7 100644 --- a/packages/alphatab/src/generated/model/TuningSerializer.ts +++ b/packages/alphatab/src/generated/model/TuningSerializer.ts @@ -15,7 +15,7 @@ export class TuningSerializer { } JsonHelper.forEach(m, (v, k) => TuningSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Tuning | null): Map | null { + public static toJson(obj: Tuning | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/VoiceSerializer.ts b/packages/alphatab/src/generated/model/VoiceSerializer.ts index 1c717ff9f..88770df64 100644 --- a/packages/alphatab/src/generated/model/VoiceSerializer.ts +++ b/packages/alphatab/src/generated/model/VoiceSerializer.ts @@ -19,7 +19,7 @@ export class VoiceSerializer { } JsonHelper.forEach(m, (v, k) => VoiceSerializer.setProperty(obj, k, v)); } - public static toJson(obj: Voice | null): Map | null { + public static toJson(obj: Voice | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/generated/model/VoiceStyleSerializer.ts b/packages/alphatab/src/generated/model/VoiceStyleSerializer.ts index 2089e7739..6b9b148ce 100644 --- a/packages/alphatab/src/generated/model/VoiceStyleSerializer.ts +++ b/packages/alphatab/src/generated/model/VoiceStyleSerializer.ts @@ -17,7 +17,7 @@ export class VoiceStyleSerializer { } JsonHelper.forEach(m, (v, k) => VoiceStyleSerializer.setProperty(obj, k, v)); } - public static toJson(obj: VoiceStyle | null): Map | null { + public static toJson(obj: VoiceStyle | null | undefined): Map | null { if (!obj) { return null; } diff --git a/packages/alphatab/src/model/Bar.ts b/packages/alphatab/src/model/Bar.ts index 32c85e3cd..ef6e8d305 100644 --- a/packages/alphatab/src/model/Bar.ts +++ b/packages/alphatab/src/model/Bar.ts @@ -1,5 +1,11 @@ import { Clef } from '@coderline/alphatab/model/Clef'; import type { MasterBar } from '@coderline/alphatab/model/MasterBar'; +import type { + NumberedBarOverride, + ScoreBarOverride, + SlashBarOverride, + TabBarOverride +} from '@coderline/alphatab/model/BarOverrides'; import { Ottavia } from '@coderline/alphatab/model/Ottavia'; import { SimileMark } from '@coderline/alphatab/model/SimileMark'; import type { Staff } from '@coderline/alphatab/model/Staff'; @@ -399,10 +405,61 @@ export class Bar { public keySignatureType: KeySignatureType = KeySignatureType.Major; /** - * How bar numbers should be displayed. - * If specified, overrides the value from the stylesheet on score level. + * How bar numbers should be displayed on this specific bar. + * @deprecated Use {@link scoreDisplay}, {@link tabDisplay}, + * {@link slashDisplay}, or {@link numberedDisplay} `.barNumber` for + * per-staff-type per-bar control. The setter broadcasts the value + * to all four override bags (lazy-creating each); on `undefined` + * it clears `.barNumber` on each existing bag without removing it. */ - public barNumberDisplay?: BarNumberDisplay; + public get barNumberDisplay(): BarNumberDisplay | undefined { + return this.scoreDisplay?.barNumber; + } + public set barNumberDisplay(value: BarNumberDisplay | undefined) { + if (value !== undefined) { + this.scoreDisplay ??= {}; + this.scoreDisplay.barNumber = value; + this.tabDisplay ??= {}; + this.tabDisplay.barNumber = value; + this.slashDisplay ??= {}; + this.slashDisplay.barNumber = value; + this.numberedDisplay ??= {}; + this.numberedDisplay.barNumber = value; + } else { + if (this.scoreDisplay) { + this.scoreDisplay.barNumber = undefined; + } + if (this.tabDisplay) { + this.tabDisplay.barNumber = undefined; + } + if (this.slashDisplay) { + this.slashDisplay.barNumber = undefined; + } + if (this.numberedDisplay) { + this.numberedDisplay.barNumber = undefined; + } + } + } + + /** + * Per-bar override for the standard-notation staff's display. + */ + public scoreDisplay?: ScoreBarOverride; + + /** + * Per-bar override for the tablature staff's display. + */ + public tabDisplay?: TabBarOverride; + + /** + * Per-bar override for the slash staff's display. + */ + public slashDisplay?: SlashBarOverride; + + /** + * Per-bar override for the numbered (jianpu) staff's display. + */ + public numberedDisplay?: NumberedBarOverride; /** * The shortest duration contained across beats in this bar. diff --git a/packages/alphatab/src/model/BarOverrides.ts b/packages/alphatab/src/model/BarOverrides.ts new file mode 100644 index 000000000..21be724a5 --- /dev/null +++ b/packages/alphatab/src/model/BarOverrides.ts @@ -0,0 +1,50 @@ +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import type { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; + +/** + * Per-bar override for the standard-notation staff's display. + * @record + * @json + * @public + */ +export interface ScoreBarOverride { + clef?: ElementDisplay; + keySignature?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} + +/** + * Per-bar override for the tablature staff's display. + * @record + * @json + * @public + */ +export interface TabBarOverride { + clef?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} + +/** + * Per-bar override for the slash staff's display. + * @record + * @json + * @public + */ +export interface SlashBarOverride { + keySignature?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} + +/** + * Per-bar override for the numbered (jianpu) staff's display. + * @record + * @json + * @public + */ +export interface NumberedBarOverride { + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} diff --git a/packages/alphatab/src/model/Beat.ts b/packages/alphatab/src/model/Beat.ts index a0cbf8df0..c110b0190 100644 --- a/packages/alphatab/src/model/Beat.ts +++ b/packages/alphatab/src/model/Beat.ts @@ -364,6 +364,7 @@ export class Beat { /** * Gets a value indicating whether this beat is fade-in. * @deprecated Use `fade` + * @json_read_only */ public get fadeIn(): boolean { return this.fade === FadeType.FadeIn; @@ -551,6 +552,7 @@ export class Beat { /** * The speed of the tremolo. * @deprecated Set {@link tremoloPicking} instead. + * @json_read_only */ public get tremoloSpeed(): Duration | null { const tremolo = this.tremoloPicking; diff --git a/packages/alphatab/src/model/ElementDisplay.ts b/packages/alphatab/src/model/ElementDisplay.ts new file mode 100644 index 000000000..f62d1607c --- /dev/null +++ b/packages/alphatab/src/model/ElementDisplay.ts @@ -0,0 +1,67 @@ +/** + * Spatial selector for an element across the staves of a system. + * + * One axis of {@link ElementDisplay}. The renderer dispatches per-staff + * on this axis to decide which staves paint the element. + * @public + */ +export enum StaffPlacement { + /** + * Paint the element on every staff whose + * {@link ElementDisplay.isVisible} resolves to `true`. + */ + AllStaves = 0, + /** + * Paint only on the cascade-primary render-staff for each model + * {@link Staff}. Priority: `score → tab → slash → numbered`. + */ + Primary = 1 +} + +/** + * Temporal selector for an element across the systems of the score. + * + * One axis of {@link ElementDisplay}. Independent of + * {@link StaffPlacement}. + * @public + */ +export enum SystemDisplay { + /** + * Restate the element at the start of every system. + */ + AllSystems = 0, + /** + * Show only on the first system; subsequent systems do not restate. + */ + FirstSystemOnly = 1 +} + +/** + * Per-axis visibility / placement / system-display selector for an + * element on a staff type. Used as the value type for the clef, + * key signature, time signature, and rests entries on the per-staff-type + * configuration carriers. + * + * Each axis is independently optional. An `undefined` axis defers to + * the outer layer in the three-layer resolution chain (per-bar → + * per-staff → score-wide stylesheet). + * @record + * @json + * @public + */ +export interface ElementDisplay { + /** + * Whether to paint the element at all. + */ + isVisible?: boolean; + + /** + * Spatial selector across the staves of a system. + */ + staffPlacement?: StaffPlacement; + + /** + * Temporal selector across the systems of the score. + */ + systemDisplay?: SystemDisplay; +} diff --git a/packages/alphatab/src/model/MasterBar.ts b/packages/alphatab/src/model/MasterBar.ts index ed1982268..bd4473b12 100644 --- a/packages/alphatab/src/model/MasterBar.ts +++ b/packages/alphatab/src/model/MasterBar.ts @@ -211,6 +211,7 @@ export class MasterBar { /** * The key signature used on all bars. * @deprecated Use key signatures on bar level + * @json_read_only */ public get keySignature(): KeySignature { return this.score.tracks[0].staves[0].bars[this.index].keySignature; @@ -227,6 +228,7 @@ export class MasterBar { /** * The type of key signature (major/minor) * @deprecated Use key signatures on bar level + * @json_read_only */ public get keySignatureType(): KeySignatureType { return this.score.tracks[0].staves[0].bars[this.index].keySignatureType; diff --git a/packages/alphatab/src/model/RenderStylesheet.ts b/packages/alphatab/src/model/RenderStylesheet.ts index 81e4a4ad5..f5a74ca01 100644 --- a/packages/alphatab/src/model/RenderStylesheet.ts +++ b/packages/alphatab/src/model/RenderStylesheet.ts @@ -1,3 +1,11 @@ +import { TabRhythmMode } from '@coderline/alphatab/NotationSettings'; +import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import type { + NumberedStaffConfig, + ScoreStaffConfig, + SlashStaffConfig, + TabStaffConfig +} from '@coderline/alphatab/model/StaffConfigs'; import type { Track } from '@coderline/alphatab/model/Track'; /** @@ -205,7 +213,57 @@ export class RenderStylesheet { public showSingleStaffBrackets: boolean = false; /** - * How bar numbers should be displayed. + * How bar numbers should be displayed score-wide. + * @deprecated Use {@link scoreConfig}, {@link tabConfig}, + * {@link slashConfig}, or {@link numberedConfig} `.barNumber` for + * per-staff-type control. The setter broadcasts to all four + * staff-type entries. + */ + public get barNumberDisplay(): BarNumberDisplay { + return this.scoreConfig.barNumber!; + } + public set barNumberDisplay(value: BarNumberDisplay) { + this.scoreConfig.barNumber = value; + this.tabConfig.barNumber = value; + this.slashConfig.barNumber = value; + this.numberedConfig.barNumber = value; + } + + /** + * Score-wide display configuration for the standard-notation staff. + */ + public scoreConfig: ScoreStaffConfig = { + clef: { isVisible: true, staffPlacement: StaffPlacement.AllStaves, systemDisplay: SystemDisplay.AllSystems }, + keySignature: { isVisible: true, staffPlacement: StaffPlacement.AllStaves, systemDisplay: SystemDisplay.AllSystems }, + timeSignature: { isVisible: true, staffPlacement: StaffPlacement.AllStaves, systemDisplay: SystemDisplay.AllSystems }, + barNumber: BarNumberDisplay.AllBars + }; + + /** + * Score-wide display configuration for the tablature staff. + */ + public tabConfig: TabStaffConfig = { + clef: { isVisible: true, staffPlacement: StaffPlacement.AllStaves, systemDisplay: SystemDisplay.AllSystems }, + timeSignature: { isVisible: true, staffPlacement: StaffPlacement.Primary, systemDisplay: SystemDisplay.AllSystems }, + barNumber: BarNumberDisplay.AllBars, + rhythm: TabRhythmMode.Automatic, + rests: { isVisible: true, staffPlacement: StaffPlacement.Primary } + }; + + /** + * Score-wide display configuration for the slash staff. + */ + public slashConfig: SlashStaffConfig = { + keySignature: { isVisible: false }, + timeSignature: { isVisible: true, staffPlacement: StaffPlacement.Primary, systemDisplay: SystemDisplay.AllSystems }, + barNumber: BarNumberDisplay.AllBars + }; + + /** + * Score-wide display configuration for the numbered (jianpu) staff. */ - public barNumberDisplay: BarNumberDisplay = BarNumberDisplay.AllBars; + public numberedConfig: NumberedStaffConfig = { + timeSignature: { isVisible: true, staffPlacement: StaffPlacement.Primary, systemDisplay: SystemDisplay.AllSystems }, + barNumber: BarNumberDisplay.AllBars + }; } diff --git a/packages/alphatab/src/model/Staff.ts b/packages/alphatab/src/model/Staff.ts index 82cb2e2f9..9174b4d50 100644 --- a/packages/alphatab/src/model/Staff.ts +++ b/packages/alphatab/src/model/Staff.ts @@ -1,5 +1,11 @@ import type { Bar } from '@coderline/alphatab/model/Bar'; import type { Chord } from '@coderline/alphatab/model/Chord'; +import type { + NumberedStaffConfig, + ScoreStaffConfig, + SlashStaffConfig, + TabStaffConfig +} from '@coderline/alphatab/model/StaffConfigs'; import type { Track } from '@coderline/alphatab/model/Track'; import { Tuning } from '@coderline/alphatab/model/Tuning'; import type { Settings } from '@coderline/alphatab/Settings'; @@ -100,6 +106,26 @@ export class Staff { */ public showStandardNotation: boolean = true; + /** + * Per-{@link Staff} override for the standard-notation staff's display. + */ + public scoreConfig?: ScoreStaffConfig; + + /** + * Per-{@link Staff} override for the tablature staff's display. + */ + public tabConfig?: TabStaffConfig; + + /** + * Per-{@link Staff} override for the slash staff's display. + */ + public slashConfig?: SlashStaffConfig; + + /** + * Per-{@link Staff} override for the numbered (jianpu) staff's display. + */ + public numberedConfig?: NumberedStaffConfig; + /** * Gets or sets whether the staff contains percussion notation */ diff --git a/packages/alphatab/src/model/StaffConfigs.ts b/packages/alphatab/src/model/StaffConfigs.ts new file mode 100644 index 000000000..16f6c7e0c --- /dev/null +++ b/packages/alphatab/src/model/StaffConfigs.ts @@ -0,0 +1,55 @@ +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import type { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; +import type { TabRhythmMode } from '@coderline/alphatab/NotationSettings'; + +/** + * Per-staff-type display configuration for the standard-notation staff. + * @record + * @json + * @public + */ +export interface ScoreStaffConfig { + clef?: ElementDisplay; + keySignature?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} + +/** + * Per-staff-type display configuration for the tablature staff. + * @record + * @json + * @public + */ +export interface TabStaffConfig { + clef?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; + rhythm?: TabRhythmMode; + rests?: ElementDisplay; +} + +/** + * Per-staff-type display configuration for the slash staff. + * @record + * @json + * @public + */ +export interface SlashStaffConfig { + keySignature?: ElementDisplay; + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} + +/** + * Per-staff-type display configuration for the numbered (jianpu) staff. + * The "1=X" key designation is rendered as an above-staff effect-band + * label, not a header glyph, so this config has no `keySignature` field. + * @record + * @json + * @public + */ +export interface NumberedStaffConfig { + timeSignature?: ElementDisplay; + barNumber?: BarNumberDisplay; +} diff --git a/packages/alphatab/src/model/_barrel.ts b/packages/alphatab/src/model/_barrel.ts index c5c0e1a6a..4a450a87d 100644 --- a/packages/alphatab/src/model/_barrel.ts +++ b/packages/alphatab/src/model/_barrel.ts @@ -70,3 +70,20 @@ export { WahPedal } from '@coderline/alphatab/model/WahPedal'; export { WhammyType } from '@coderline/alphatab/model/WhammyType'; export { ElementStyle } from '@coderline/alphatab/model/ElementStyle'; export { BackingTrack } from '@coderline/alphatab/model/BackingTrack'; +export { + StaffPlacement, + SystemDisplay, + type ElementDisplay +} from '@coderline/alphatab/model/ElementDisplay'; +export type { + ScoreStaffConfig, + TabStaffConfig, + SlashStaffConfig, + NumberedStaffConfig +} from '@coderline/alphatab/model/StaffConfigs'; +export type { + ScoreBarOverride, + TabBarOverride, + SlashBarOverride, + NumberedBarOverride +} from '@coderline/alphatab/model/BarOverrides'; diff --git a/packages/alphatab/src/rendering/BarRendererBase.ts b/packages/alphatab/src/rendering/BarRendererBase.ts index dd015bec6..f10aa08e6 100644 --- a/packages/alphatab/src/rendering/BarRendererBase.ts +++ b/packages/alphatab/src/rendering/BarRendererBase.ts @@ -102,14 +102,14 @@ export class BarRendererBase { if (!this.bar || !this.bar.nextBar) { return null; } - return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId, this.bar.nextBar); + return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId,this.bar.nextBar); } public get previousRenderer(): BarRendererBase | null { if (!this.bar || !this.bar.previousBar) { return null; } - return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId, this.bar.previousBar); + return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId,this.bar.previousBar); } public scoreRenderer: ScoreRenderer; diff --git a/packages/alphatab/src/rendering/BarRendererFactory.ts b/packages/alphatab/src/rendering/BarRendererFactory.ts index c5d9bf268..e19c97a94 100644 --- a/packages/alphatab/src/rendering/BarRendererFactory.ts +++ b/packages/alphatab/src/rendering/BarRendererFactory.ts @@ -64,6 +64,13 @@ export abstract class BarRendererFactory { public abstract get staffId(): string; + /** + * Priority in the staff-display cascade. Lower wins. The lowest-priority + * render-staff among siblings sharing the same model {@link Staff} + * is the {@link StaffPlacement.Primary} painter. + */ + public abstract get cascadePriority(): number; + public constructor(effectBands: EffectBandInfo[]) { this.effectBands = effectBands; } diff --git a/packages/alphatab/src/rendering/LineBarRenderer.ts b/packages/alphatab/src/rendering/LineBarRenderer.ts index 2cf28ab75..82ff99e65 100644 --- a/packages/alphatab/src/rendering/LineBarRenderer.ts +++ b/packages/alphatab/src/rendering/LineBarRenderer.ts @@ -11,6 +11,8 @@ import type { TupletGroup } from '@coderline/alphatab/model/TupletGroup'; import { NotationElement, NotationMode } from '@coderline/alphatab/NotationSettings'; import { CanvasHelper, type ICanvas, TextAlign, TextBaseline } from '@coderline/alphatab/platform/ICanvas'; import { BarRendererBase, NoteYPosition } from '@coderline/alphatab/rendering/BarRendererBase'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { TabRhythmMode } from '@coderline/alphatab/NotationSettings'; import { BeatXPosition } from '@coderline/alphatab/rendering/BeatXPosition'; import { BarLineGlyph } from '@coderline/alphatab/rendering/glyphs/BarLineGlyph'; import { BarNumberGlyph } from '@coderline/alphatab/rendering/glyphs/BarNumberGlyph'; @@ -651,17 +653,31 @@ export abstract class LineBarRenderer extends BarRendererBase { } } + public resolveClefDisplay(): ElementDisplay { + return { isVisible: false }; + } + + public resolveKeySignatureDisplay(): ElementDisplay { + return { isVisible: false }; + } + + public abstract resolveTimeSignatureDisplay(): ElementDisplay; + + protected abstract resolveBarNumberDisplay(): BarNumberDisplay; + + public resolveRestsDisplay(): ElementDisplay { + return { isVisible: false }; + } + + public resolveRhythm(): TabRhythmMode { + return TabRhythmMode.Hidden; + } + public shouldCreateBarNumber(): boolean { - let display = BarNumberDisplay.AllBars; if (!this.settings.notation.isNotationElementVisible(NotationElement.BarNumber)) { - display = BarNumberDisplay.Hide; - } else if (this.bar.barNumberDisplay !== undefined) { - display = this.bar.barNumberDisplay!; - } else { - display = this.bar.staff.track.score.stylesheet.barNumberDisplay; + return false; } - - switch (display) { + switch (this.resolveBarNumberDisplay()) { case BarNumberDisplay.AllBars: return true; case BarNumberDisplay.FirstOfSystem: diff --git a/packages/alphatab/src/rendering/NumberedBarRenderer.ts b/packages/alphatab/src/rendering/NumberedBarRenderer.ts index 1e6a29a6c..c617a01e8 100644 --- a/packages/alphatab/src/rendering/NumberedBarRenderer.ts +++ b/packages/alphatab/src/rendering/NumberedBarRenderer.ts @@ -1,6 +1,6 @@ import { EngravingSettings } from '@coderline/alphatab/EngravingSettings'; import { MidiUtils } from '@coderline/alphatab/midi/MidiUtils'; -import { type Bar, BarSubElement } from '@coderline/alphatab/model/Bar'; +import { BarSubElement } from '@coderline/alphatab/model/Bar'; import { type Beat, BeatSubElement } from '@coderline/alphatab/model/Beat'; import { Duration } from '@coderline/alphatab/model/Duration'; import { GraceType } from '@coderline/alphatab/model/GraceType'; @@ -9,6 +9,7 @@ import { MusicFontSymbol } from '@coderline/alphatab/model/MusicFontSymbol'; import type { Note } from '@coderline/alphatab/model/Note'; import type { Voice } from '@coderline/alphatab/model/Voice'; import type { ICanvas } from '@coderline/alphatab/platform/ICanvas'; +import { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; import { BeatXPosition } from '@coderline/alphatab/rendering/BeatXPosition'; import { BarLineGlyph } from '@coderline/alphatab/rendering/glyphs/BarLineGlyph'; import { BarNumberGlyph } from '@coderline/alphatab/rendering/glyphs/BarNumberGlyph'; @@ -20,7 +21,8 @@ import { ScoreTimeSignatureGlyph } from '@coderline/alphatab/rendering/glyphs/Sc import { SpacingGlyph } from '@coderline/alphatab/rendering/glyphs/SpacingGlyph'; import { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; import { NumberedBeatContainerGlyph } from '@coderline/alphatab/rendering/NumberedBeatContainerGlyph'; -import type { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; import type { BeamingHelper, BeamingHelperDrawInfo } from '@coderline/alphatab/rendering/utils/BeamingHelper'; import { ElementStyleHelper } from '@coderline/alphatab/rendering/utils/ElementStyleHelper'; @@ -34,9 +36,24 @@ export class NumberedBarRenderer extends LineBarRenderer { public simpleWhammyOverflow: number = 0; - private _isOnlyNumbered: boolean; public shortestDuration = Duration.QuadrupleWhole; + public override resolveTimeSignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.numberedDisplay?.timeSignature, + this.bar.staff.numberedConfig?.timeSignature, + this.bar.staff.track.score.stylesheet.numberedConfig.timeSignature + ); + } + + protected override resolveBarNumberDisplay(): BarNumberDisplay { + return ( + this.bar.numberedDisplay?.barNumber ?? + this.bar.staff.numberedConfig?.barNumber ?? + this.bar.staff.track.score.stylesheet.numberedConfig.barNumber! + ); + } + get dotSpacing(): number { return this.smuflMetrics.glyphHeights.get(MusicFontSymbol.AugmentationDot)! * 2; } @@ -57,11 +74,6 @@ export class NumberedBarRenderer extends LineBarRenderer { return BarSubElement.NumberedStaffLine; } - public constructor(renderer: ScoreRenderer, bar: Bar) { - super(renderer, bar); - this._isOnlyNumbered = !bar.staff.showSlash && !bar.staff.showTablature && !bar.staff.showStandardNotation; - } - public override get lineSpacing(): number { return this.smuflMetrics.oneStaffSpace; } @@ -254,7 +266,7 @@ export class NumberedBarRenderer extends LineBarRenderer { protected override createPreBeatGlyphs(): void { this.wasFirstOfStaff = this.isFirstOfStaff; - if (this.index === 0 || (this.bar.masterBar.isRepeatStart && this._isOnlyNumbered)) { + if (this.index === 0 || (this.bar.masterBar.isRepeatStart && this.staff!.isCascadePrimary)) { this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines)); } this.createLinePreBeatGlyphs(); @@ -267,8 +279,11 @@ export class NumberedBarRenderer extends LineBarRenderer { } protected override createLinePreBeatGlyphs(): void { + // No header KS glyph: the "1=X" key designation is rendered as an + // above-staff label by {@link NumberedBarKeySignatureEffectInfo}. + const timeSignatureDisplay = this.resolveTimeSignatureDisplay(); if ( - this._isOnlyNumbered && + StaffDisplayResolver.isPrimaryForElement(this.staff!, timeSignatureDisplay) && (!this.bar.previousBar || (this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== @@ -302,7 +317,7 @@ export class NumberedBarRenderer extends LineBarRenderer { } protected override createPostBeatGlyphs(): void { - if (this._isOnlyNumbered) { + if (this.staff!.isCascadePrimary) { super.createPostBeatGlyphs(); } } diff --git a/packages/alphatab/src/rendering/NumberedBarRendererFactory.ts b/packages/alphatab/src/rendering/NumberedBarRendererFactory.ts index 50705e033..51dfeff1c 100644 --- a/packages/alphatab/src/rendering/NumberedBarRendererFactory.ts +++ b/packages/alphatab/src/rendering/NumberedBarRendererFactory.ts @@ -11,10 +11,14 @@ import type { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer' * @internal */ export class NumberedBarRendererFactory extends BarRendererFactory { - public get staffId(): string { + public override get staffId(): string { return NumberedBarRenderer.StaffId; } + public override get cascadePriority(): number { + return 3; + } + public create(renderer: ScoreRenderer, bar: Bar): BarRendererBase { return new NumberedBarRenderer(renderer, bar); } diff --git a/packages/alphatab/src/rendering/ScoreBarRenderer.ts b/packages/alphatab/src/rendering/ScoreBarRenderer.ts index c5f09c158..2d33a6c49 100644 --- a/packages/alphatab/src/rendering/ScoreBarRenderer.ts +++ b/packages/alphatab/src/rendering/ScoreBarRenderer.ts @@ -16,9 +16,12 @@ import type { Glyph } from '@coderline/alphatab/rendering/glyphs/Glyph'; import { KeySignatureGlyph } from '@coderline/alphatab/rendering/glyphs/KeySignatureGlyph'; import { ScoreTimeSignatureGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreTimeSignatureGlyph'; import { SpacingGlyph } from '@coderline/alphatab/rendering/glyphs/SpacingGlyph'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; import { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; import { ScoreBeatContainerGlyph } from '@coderline/alphatab/rendering/ScoreBeatContainerGlyph'; import type { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import { AccidentalHelper } from '@coderline/alphatab/rendering/utils/AccidentalHelper'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; import type { BeamingHelper } from '@coderline/alphatab/rendering/utils/BeamingHelper'; @@ -30,6 +33,7 @@ import { ElementStyleHelper } from '@coderline/alphatab/rendering/utils/ElementS */ export class ScoreBarRenderer extends LineBarRenderer { public static readonly StaffId: string = 'score'; + private static _sharpKsSteps: number[] = [-1, 2, -2, 1, 4, 0, 3]; private static _flatKsSteps: number[] = [3, 0, 4, 1, 5, 2, 6]; @@ -40,6 +44,38 @@ export class ScoreBarRenderer extends LineBarRenderer { this.accidentalHelper = new AccidentalHelper(this); } + public override resolveClefDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.scoreDisplay?.clef, + this.bar.staff.scoreConfig?.clef, + this.bar.staff.track.score.stylesheet.scoreConfig.clef + ); + } + + public override resolveKeySignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.scoreDisplay?.keySignature, + this.bar.staff.scoreConfig?.keySignature, + this.bar.staff.track.score.stylesheet.scoreConfig.keySignature + ); + } + + public override resolveTimeSignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.scoreDisplay?.timeSignature, + this.bar.staff.scoreConfig?.timeSignature, + this.bar.staff.track.score.stylesheet.scoreConfig.timeSignature + ); + } + + protected override resolveBarNumberDisplay(): BarNumberDisplay { + return ( + this.bar.scoreDisplay?.barNumber ?? + this.bar.staff.scoreConfig?.barNumber ?? + this.bar.staff.track.score.stylesheet.scoreConfig.barNumber! + ); + } + public override get repeatsBarSubElement(): BarSubElement { return BarSubElement.StandardNotationRepeats; } @@ -176,10 +212,12 @@ export class ScoreBarRenderer extends LineBarRenderer { protected override createLinePreBeatGlyphs(): void { // Clef let hasClef = false; + const clefDisplay = this.resolveClefDisplay(); if ( - this.isFirstOfStaff || - this.bar.clef !== this.bar.previousBar!.clef || - this.bar.clefOttava !== this.bar.previousBar!.clefOttava + StaffDisplayResolver.isPrimaryForElement(this.staff!, clefDisplay) && + (this.isFirstOfStaff || + this.bar.clef !== this.bar.previousBar!.clef || + this.bar.clefOttava !== this.bar.previousBar!.clefOttava) ) { // SMUFL: Clefs should be positioned such that the pitch the clef refers to is on the baseline // (e.g. the F clef is placed such that the upper dot is above and the lower dot below the baseline). @@ -210,25 +248,30 @@ export class ScoreBarRenderer extends LineBarRenderer { hasClef = true; } // Key signature + const keySignatureDisplay = this.resolveKeySignatureDisplay(); if ( - hasClef || - (this.index === 0 && this.bar.keySignature !== KeySignature.C) || - (this.bar.previousBar && this.bar.keySignature !== this.bar.previousBar.keySignature) + StaffDisplayResolver.isPrimaryForElement(this.staff!, keySignatureDisplay) && + (hasClef || + (this.index === 0 && this.bar.keySignature !== KeySignature.C) || + (this.bar.previousBar && this.bar.keySignature !== this.bar.previousBar.keySignature)) ) { this.createStartSpacing(); this._createKeySignatureGlyphs(); } // Time Signature + const timeSignatureDisplay = this.resolveTimeSignatureDisplay(); if ( - !this.bar.previousBar || - (this.bar.previousBar && - this.bar.masterBar.timeSignatureNumerator !== this.bar.previousBar.masterBar.timeSignatureNumerator) || - (this.bar.previousBar && - this.bar.masterBar.timeSignatureDenominator !== - this.bar.previousBar.masterBar.timeSignatureDenominator) || - (this.bar.previousBar && - this.bar.masterBar.isFreeTime && - this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime) + StaffDisplayResolver.isPrimaryForElement(this.staff!, timeSignatureDisplay) && + (!this.bar.previousBar || + (this.bar.previousBar && + this.bar.masterBar.timeSignatureNumerator !== + this.bar.previousBar.masterBar.timeSignatureNumerator) || + (this.bar.previousBar && + this.bar.masterBar.timeSignatureDenominator !== + this.bar.previousBar.masterBar.timeSignatureDenominator) || + (this.bar.previousBar && + this.bar.masterBar.isFreeTime && + this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime)) ) { this.createStartSpacing(); this._createTimeSignatureGlyphs(); diff --git a/packages/alphatab/src/rendering/ScoreBarRendererFactory.ts b/packages/alphatab/src/rendering/ScoreBarRendererFactory.ts index c1634bbcc..fee8f83af 100644 --- a/packages/alphatab/src/rendering/ScoreBarRendererFactory.ts +++ b/packages/alphatab/src/rendering/ScoreBarRendererFactory.ts @@ -11,10 +11,14 @@ import type { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer' * @internal */ export class ScoreBarRendererFactory extends BarRendererFactory { - public get staffId(): string { + public override get staffId(): string { return ScoreBarRenderer.StaffId; } + public override get cascadePriority(): number { + return 0; + } + public create(renderer: ScoreRenderer, bar: Bar): BarRendererBase { return new ScoreBarRenderer(renderer, bar); } diff --git a/packages/alphatab/src/rendering/SlashBarRenderer.ts b/packages/alphatab/src/rendering/SlashBarRenderer.ts index b6165c1ab..16f8317a4 100644 --- a/packages/alphatab/src/rendering/SlashBarRenderer.ts +++ b/packages/alphatab/src/rendering/SlashBarRenderer.ts @@ -1,10 +1,13 @@ import { type Bar, BarSubElement } from '@coderline/alphatab/model/Bar'; import { type Beat, BeatSubElement } from '@coderline/alphatab/model/Beat'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; import type { Note } from '@coderline/alphatab/model/Note'; +import { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; import type { Voice } from '@coderline/alphatab/model/Voice'; import type { ICanvas } from '@coderline/alphatab/platform/ICanvas'; import { LineBarRenderer } from '@coderline/alphatab/rendering//LineBarRenderer'; import { NoteYPosition } from '@coderline/alphatab/rendering/BarRendererBase'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import { ScoreTimeSignatureGlyph } from '@coderline/alphatab/rendering/glyphs/ScoreTimeSignatureGlyph'; import { SpacingGlyph } from '@coderline/alphatab/rendering/glyphs/SpacingGlyph'; import type { ScoreRenderer } from '@coderline/alphatab/rendering/ScoreRenderer'; @@ -21,15 +24,36 @@ export class SlashBarRenderer extends LineBarRenderer { public static readonly StaffId: string = 'slash'; public simpleWhammyOverflow: number = 0; - private _isOnlySlash: boolean; public constructor(renderer: ScoreRenderer, bar: Bar) { super(renderer, bar); - // ignore numbered notation here - this._isOnlySlash = !bar.staff.showTablature && !bar.staff.showStandardNotation; this.helpers.preferredBeamDirection = BeamDirection.Up; } + public override resolveKeySignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.slashDisplay?.keySignature, + this.bar.staff.slashConfig?.keySignature, + this.bar.staff.track.score.stylesheet.slashConfig.keySignature + ); + } + + public override resolveTimeSignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.slashDisplay?.timeSignature, + this.bar.staff.slashConfig?.timeSignature, + this.bar.staff.track.score.stylesheet.slashConfig.timeSignature + ); + } + + protected override resolveBarNumberDisplay(): BarNumberDisplay { + return ( + this.bar.slashDisplay?.barNumber ?? + this.bar.staff.slashConfig?.barNumber ?? + this.bar.staff.track.score.stylesheet.slashConfig.barNumber! + ); + } + public override get repeatsBarSubElement(): BarSubElement { return BarSubElement.SlashRepeats; } @@ -109,9 +133,9 @@ export class SlashBarRenderer extends LineBarRenderer { } protected override createLinePreBeatGlyphs(): void { - // Key signature + const timeSignatureDisplay = this.resolveTimeSignatureDisplay(); if ( - this._isOnlySlash && + StaffDisplayResolver.isPrimaryForElement(this.staff!, timeSignatureDisplay) && (!this.bar.previousBar || (this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== diff --git a/packages/alphatab/src/rendering/SlashBarRendererFactory.ts b/packages/alphatab/src/rendering/SlashBarRendererFactory.ts index 24b6ef53d..01e2fb7bc 100644 --- a/packages/alphatab/src/rendering/SlashBarRendererFactory.ts +++ b/packages/alphatab/src/rendering/SlashBarRendererFactory.ts @@ -11,10 +11,14 @@ import { SlashBarRenderer } from '@coderline/alphatab/rendering/SlashBarRenderer * @internal */ export class SlashBarRendererFactory extends BarRendererFactory { - public get staffId(): string { + public override get staffId(): string { return SlashBarRenderer.StaffId; } + public override get cascadePriority(): number { + return 2; + } + public create(renderer: ScoreRenderer, bar: Bar): BarRendererBase { return new SlashBarRenderer(renderer, bar); } diff --git a/packages/alphatab/src/rendering/TabBarRenderer.ts b/packages/alphatab/src/rendering/TabBarRenderer.ts index 122975265..d16fa59e8 100644 --- a/packages/alphatab/src/rendering/TabBarRenderer.ts +++ b/packages/alphatab/src/rendering/TabBarRenderer.ts @@ -13,7 +13,9 @@ import { TabClefGlyph } from '@coderline/alphatab/rendering/glyphs/TabClefGlyph' import type { TabNoteChordGlyph } from '@coderline/alphatab/rendering/glyphs/TabNoteChordGlyph'; import { TabTimeSignatureGlyph } from '@coderline/alphatab/rendering/glyphs/TabTimeSignatureGlyph'; import { LineBarRenderer } from '@coderline/alphatab/rendering/LineBarRenderer'; -import { ScoreBarRenderer } from '@coderline/alphatab/rendering/ScoreBarRenderer'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { BarNumberDisplay } from '@coderline/alphatab/model/RenderStylesheet'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import type { ReservedLayoutAreaSlot } from '@coderline/alphatab/rendering/utils/BarCollisionHelper'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; import type { BeamingHelper } from '@coderline/alphatab/rendering/utils/BeamingHelper'; @@ -28,14 +30,56 @@ export class TabBarRenderer extends LineBarRenderer { private _hasTuplets = false; - public showTimeSignature: boolean = false; - public showRests: boolean = false; - public showTiedNotes: boolean = false; + public override resolveClefDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.tabDisplay?.clef, + this.bar.staff.tabConfig?.clef, + this.bar.staff.track.score.stylesheet.tabConfig.clef + ); + } + + public override resolveTimeSignatureDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + this.bar.tabDisplay?.timeSignature, + this.bar.staff.tabConfig?.timeSignature, + this.bar.staff.track.score.stylesheet.tabConfig.timeSignature + ); + } + + public override resolveRestsDisplay(): ElementDisplay { + return StaffDisplayResolver.merge( + undefined, + this.bar.staff.tabConfig?.rests, + this.bar.staff.track.score.stylesheet.tabConfig.rests + ); + } + + public override resolveRhythm(): TabRhythmMode { + return this.bar.staff.tabConfig?.rhythm ?? this.bar.staff.track.score.stylesheet.tabConfig.rhythm!; + } - private _showMultiBarRest: boolean = false; + protected override resolveBarNumberDisplay(): BarNumberDisplay { + return ( + this.bar.tabDisplay?.barNumber ?? + this.bar.staff.tabConfig?.barNumber ?? + this.bar.staff.track.score.stylesheet.tabConfig.barNumber! + ); + } + + public get showTimeSignature(): boolean { + return StaffDisplayResolver.isPrimaryForElement(this.staff!, this.resolveTimeSignatureDisplay()); + } + + public get showRests(): boolean { + return StaffDisplayResolver.isPrimaryForElement(this.staff!, this.resolveRestsDisplay()); + } + + public get showTiedNotes(): boolean { + return this.staff!.isCascadePrimary; + } public override get showMultiBarRest(): boolean { - return this._showMultiBarRest; + return this.staff!.isCascadePrimary; } public override get repeatsBarSubElement(): BarSubElement { @@ -109,16 +153,6 @@ export class TabBarRenderer extends LineBarRenderer { } public override doLayout(): void { - const hasStandardNotation = - this.bar.staff.showStandardNotation && this.scoreRenderer.layout!.profile.has(ScoreBarRenderer.StaffId); - - if (!hasStandardNotation) { - this.showTimeSignature = true; - this.showRests = true; - this.showTiedNotes = true; - this._showMultiBarRest = true; - } - super.doLayout(); const hasNoteOnTopString = this.minString === 0; @@ -140,14 +174,16 @@ export class TabBarRenderer extends LineBarRenderer { protected override createLinePreBeatGlyphs(): void { // Clef - if (this.isFirstOfStaff) { + const clefDisplay = this.resolveClefDisplay(); + if (StaffDisplayResolver.isPrimaryForElement(this.staff!, clefDisplay) && this.isFirstOfStaff) { const center: number = (this.bar.staff.tuning.length - 1) / 2; this.createStartSpacing(); this.addPreBeatGlyph(new TabClefGlyph(0, this.getLineY(center))); } // Time Signature + const timeSignatureDisplay = this.resolveTimeSignatureDisplay(); if ( - this.showTimeSignature && + StaffDisplayResolver.isPrimaryForElement(this.staff!, timeSignatureDisplay) && (!this.bar.previousBar || (this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== diff --git a/packages/alphatab/src/rendering/TabBarRendererFactory.ts b/packages/alphatab/src/rendering/TabBarRendererFactory.ts index df2521c38..54ca6d3c7 100644 --- a/packages/alphatab/src/rendering/TabBarRendererFactory.ts +++ b/packages/alphatab/src/rendering/TabBarRendererFactory.ts @@ -11,10 +11,14 @@ import { TabBarRenderer } from '@coderline/alphatab/rendering/TabBarRenderer'; * @internal */ export class TabBarRendererFactory extends BarRendererFactory { - public get staffId(): string { + public override get staffId(): string { return TabBarRenderer.StaffId; } + public override get cascadePriority(): number { + return 1; + } + public constructor(effectBands: EffectBandInfo[]) { super(effectBands); this.hideOnPercussionTrack = true; diff --git a/packages/alphatab/src/rendering/staves/RenderStaff.ts b/packages/alphatab/src/rendering/staves/RenderStaff.ts index 5a0aa6be1..1f4b63001 100644 --- a/packages/alphatab/src/rendering/staves/RenderStaff.ts +++ b/packages/alphatab/src/rendering/staves/RenderStaff.ts @@ -8,6 +8,7 @@ import { EffectBandMode } from '@coderline/alphatab/rendering/BarRendererFactory'; import type { BarLayoutingInfo } from '@coderline/alphatab/rendering/staves/BarLayoutingInfo'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import type { StaffSystem } from '@coderline/alphatab/rendering/staves/StaffSystem'; import type { StaffTrackGroup } from '@coderline/alphatab/rendering/staves/StaffTrackGroup'; @@ -52,6 +53,18 @@ export class RenderStaff { return this._factory.staffId; } + public get cascadePriority(): number { + return this._factory.cascadePriority; + } + + private _isCascadePrimary: boolean | null = null; + public get isCascadePrimary(): boolean { + if (this._isCascadePrimary === null) { + this._isCascadePrimary = StaffDisplayResolver.computeCascadePrimary(this); + } + return this._isCascadePrimary; + } + /** * This is the visual offset from top where the * Staff contents actually start. Used for grouping diff --git a/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts new file mode 100644 index 000000000..a0866e578 --- /dev/null +++ b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts @@ -0,0 +1,73 @@ +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import type { RenderStaff } from '@coderline/alphatab/rendering/staves/RenderStaff'; + +/** + * Helpers for the staff-placement cascade and the per-axis + * {@link ElementDisplay} merge. Per-element resolution lives on the + * renderer subclasses themselves. + * @internal + */ +export class StaffDisplayResolver { + private static readonly _fallback: ElementDisplay = { + isVisible: true, + staffPlacement: StaffPlacement.AllStaves, + systemDisplay: SystemDisplay.AllSystems + }; + + /** + * Per-axis fall-through: first defined value walking + * per-bar → per-staff → score-wide → {@link _fallback}. + */ + public static merge( + perBar: ElementDisplay | undefined, + perStaff: ElementDisplay | undefined, + stylesheet: ElementDisplay | undefined + ): ElementDisplay { + const fallback = StaffDisplayResolver._fallback; + return { + isVisible: + perBar?.isVisible ?? perStaff?.isVisible ?? stylesheet?.isVisible ?? fallback.isVisible, + staffPlacement: + perBar?.staffPlacement ?? + perStaff?.staffPlacement ?? + stylesheet?.staffPlacement ?? + fallback.staffPlacement, + systemDisplay: + perBar?.systemDisplay ?? + perStaff?.systemDisplay ?? + stylesheet?.systemDisplay ?? + fallback.systemDisplay + }; + } + + public static isPrimaryForElement(staff: RenderStaff, display: ElementDisplay): boolean { + if (display.isVisible === false) { + return false; + } + if (display.systemDisplay === SystemDisplay.FirstSystemOnly && staff.system.index !== 0) { + return false; + } + switch (display.staffPlacement) { + case StaffPlacement.AllStaves: + return true; + case StaffPlacement.Primary: + return staff.isCascadePrimary; + } + return true; + } + + public static computeCascadePrimary(staff: RenderStaff): boolean { + const modelStaff = staff.modelStaff; + let primary = staff; + for (const sibling of staff.staffTrackGroup.staves) { + if (sibling === staff || sibling.modelStaff !== modelStaff) { + continue; + } + if (sibling.cascadePriority < primary.cascadePriority) { + primary = sibling; + } + } + return primary === staff; + } +} diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png new file mode 100644 index 0000000000000000000000000000000000000000..8d161c2758bc659493f5d2d0e5aba89273f0fdc8 GIT binary patch literal 18028 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 D&)AR2 literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-numbered-only.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-numbered-only.png new file mode 100644 index 0000000000000000000000000000000000000000..1f500f594164d73b2a64e6bb6776f881f0d7b697 GIT binary patch literal 5705 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 a(gmVwi{^y$>+p|+$U#%flcgsv-})brfj0sG literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-score-tab.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-score-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..49aded466a15fc3595965a38a48fb163534e8c43 GIT binary patch literal 15596 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 literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png new file mode 100644 index 0000000000000000000000000000000000000000..de154cdb255174d967d685220f47f0fbcc26a158 GIT binary patch literal 8193 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 MEPp9Kd-=|P0J53*DgXcg literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-only.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-only.png new file mode 100644 index 0000000000000000000000000000000000000000..cb3b4e0fb3319986474e158f8aaac58b264e3ccc GIT binary patch literal 10053 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 Vg7iP{T@#N8JZo_#{}0!@{|&b}G|vD4 literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png b/packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png new file mode 100644 index 0000000000000000000000000000000000000000..4530c90e9bba22f226f723d0f3577d1b9abba02e GIT binary patch literal 10035 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

hpI4AbuJI^SKZxlV+5nL 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 Jk~ewrzW^!*=i&eW literal 0 HcmV?d00001 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png b/packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png new file mode 100644 index 0000000000000000000000000000000000000000..7c16a1ef6893f042bd2e98ccfdccaef7109919de GIT binary patch literal 7665 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 literal 0 HcmV?d00001 diff --git a/packages/alphatab/test/importer/__snapshots__/MusicXmlImporter.test.ts.snap b/packages/alphatab/test/importer/__snapshots__/MusicXmlImporter.test.ts.snap index 11e20342c..88982a96c 100644 --- a/packages/alphatab/test/importer/__snapshots__/MusicXmlImporter.test.ts.snap +++ b/packages/alphatab/test/importer/__snapshots__/MusicXmlImporter.test.ts.snap @@ -794,6 +794,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -852,6 +864,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -918,6 +942,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -976,6 +1012,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -3036,6 +3084,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -3094,6 +3154,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -3160,6 +3232,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", @@ -3218,6 +3302,18 @@ Map { }, ], "barnumberdisplay" => 2, + "scoredisplay" => Map { + "barnumber" => 2, + }, + "tabdisplay" => Map { + "barnumber" => 2, + }, + "slashdisplay" => Map { + "barnumber" => 2, + }, + "numbereddisplay" => Map { + "barnumber" => 2, + }, }, Map { "__kind" => "Bar", diff --git a/packages/alphatab/test/model/StaffConfiguration.test.ts b/packages/alphatab/test/model/StaffConfiguration.test.ts new file mode 100644 index 000000000..308819829 --- /dev/null +++ b/packages/alphatab/test/model/StaffConfiguration.test.ts @@ -0,0 +1,246 @@ +import { describe, expect, it } from 'vitest'; +import { BarSerializer } from '@coderline/alphatab/generated/model/BarSerializer'; +import { RenderStylesheetSerializer } from '@coderline/alphatab/generated/model/RenderStylesheetSerializer'; +import { StaffSerializer } from '@coderline/alphatab/generated/model/StaffSerializer'; +import { Bar } from '@coderline/alphatab/model/Bar'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { BarNumberDisplay, RenderStylesheet } from '@coderline/alphatab/model/RenderStylesheet'; +import { Staff } from '@coderline/alphatab/model/Staff'; +import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; + +import { TabRhythmMode } from '@coderline/alphatab/NotationSettings'; + +/** + * @internal + */ +function expectElementDisplay( + actual: ElementDisplay | undefined, + isVisible: boolean | undefined, + staffPlacement: StaffPlacement | undefined, + systemDisplay: SystemDisplay | undefined +): void { + expect(actual).not.toBeUndefined(); + expect(actual!.isVisible).toBe(isVisible); + expect(actual!.staffPlacement).toBe(staffPlacement); + expect(actual!.systemDisplay).toBe(systemDisplay); +} + +describe('RenderStylesheet L3 historical defaults', () => { + it('scoreConfig defaults', () => { + const rs = new RenderStylesheet(); + expectElementDisplay(rs.scoreConfig.clef, true, StaffPlacement.AllStaves, SystemDisplay.AllSystems); + expectElementDisplay(rs.scoreConfig.keySignature, true, StaffPlacement.AllStaves, SystemDisplay.AllSystems); + expectElementDisplay(rs.scoreConfig.timeSignature, true, StaffPlacement.AllStaves, SystemDisplay.AllSystems); + expect(rs.scoreConfig.barNumber).toBe(BarNumberDisplay.AllBars); + }); + + it('tabConfig defaults', () => { + const rs = new RenderStylesheet(); + expectElementDisplay(rs.tabConfig.clef, true, StaffPlacement.AllStaves, SystemDisplay.AllSystems); + expectElementDisplay(rs.tabConfig.timeSignature, true, StaffPlacement.Primary, SystemDisplay.AllSystems); + expect(rs.tabConfig.barNumber).toBe(BarNumberDisplay.AllBars); + expect(rs.tabConfig.rhythm).toBe(TabRhythmMode.Automatic); + expectElementDisplay(rs.tabConfig.rests, true, StaffPlacement.Primary, undefined); + }); + + it('slashConfig defaults', () => { + const rs = new RenderStylesheet(); + expectElementDisplay(rs.slashConfig.keySignature, false, undefined, undefined); + expectElementDisplay(rs.slashConfig.timeSignature, true, StaffPlacement.Primary, SystemDisplay.AllSystems); + expect(rs.slashConfig.barNumber).toBe(BarNumberDisplay.AllBars); + }); + + it('numberedConfig defaults', () => { + const rs = new RenderStylesheet(); + expectElementDisplay(rs.numberedConfig.timeSignature, true, StaffPlacement.Primary, SystemDisplay.AllSystems); + expect(rs.numberedConfig.barNumber).toBe(BarNumberDisplay.AllBars); + }); +}); + +describe('Staff L2 fields default to undefined', () => { + it('all four *Config fields are undefined on a fresh Staff', () => { + const staff = new Staff(); + expect(staff.scoreConfig).toBeUndefined(); + expect(staff.tabConfig).toBeUndefined(); + expect(staff.slashConfig).toBeUndefined(); + expect(staff.numberedConfig).toBeUndefined(); + }); +}); + +describe('Bar L1 fields default to undefined', () => { + it('all four *Display fields are undefined on a fresh Bar', () => { + const bar = new Bar(); + expect(bar.scoreDisplay).toBeUndefined(); + expect(bar.tabDisplay).toBeUndefined(); + expect(bar.slashDisplay).toBeUndefined(); + expect(bar.numberedDisplay).toBeUndefined(); + }); +}); + +describe('RenderStylesheet.barNumberDisplay shim (ADR-006 §1)', () => { + it('getter reads from scoreConfig.barNumber', () => { + const rs = new RenderStylesheet(); + expect(rs.barNumberDisplay).toBe(BarNumberDisplay.AllBars); + rs.scoreConfig.barNumber = BarNumberDisplay.Hide; + expect(rs.barNumberDisplay).toBe(BarNumberDisplay.Hide); + }); + + it('setter broadcasts to all four staff-type L3 entries', () => { + const rs = new RenderStylesheet(); + rs.barNumberDisplay = BarNumberDisplay.FirstOfSystem; + expect(rs.scoreConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(rs.tabConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(rs.slashConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(rs.numberedConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + }); +}); + +describe('Bar.barNumberDisplay shim (ADR-006 §2)', () => { + it('getter returns undefined when no scoreDisplay override exists', () => { + const bar = new Bar(); + expect(bar.barNumberDisplay).toBeUndefined(); + }); + + it('getter returns scoreDisplay.barNumber when present', () => { + const bar = new Bar(); + bar.scoreDisplay = { barNumber: BarNumberDisplay.Hide }; + expect(bar.barNumberDisplay).toBe(BarNumberDisplay.Hide); + }); + + it('setter with concrete value lazy-creates each *Display bag and broadcasts', () => { + const bar = new Bar(); + bar.barNumberDisplay = BarNumberDisplay.FirstOfSystem; + expect(bar.scoreDisplay).not.toBeUndefined(); + expect(bar.scoreDisplay!.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(bar.tabDisplay).not.toBeUndefined(); + expect(bar.tabDisplay!.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(bar.slashDisplay).not.toBeUndefined(); + expect(bar.slashDisplay!.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(bar.numberedDisplay).not.toBeUndefined(); + expect(bar.numberedDisplay!.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + }); + + it('setter with undefined clears barNumber on each existing bag without deleting the bag', () => { + const bar = new Bar(); + bar.barNumberDisplay = BarNumberDisplay.Hide; + bar.barNumberDisplay = undefined; + expect(bar.scoreDisplay).not.toBeUndefined(); + expect(bar.scoreDisplay!.barNumber).toBeUndefined(); + expect(bar.tabDisplay).not.toBeUndefined(); + expect(bar.tabDisplay!.barNumber).toBeUndefined(); + expect(bar.slashDisplay).not.toBeUndefined(); + expect(bar.slashDisplay!.barNumber).toBeUndefined(); + expect(bar.numberedDisplay).not.toBeUndefined(); + expect(bar.numberedDisplay!.barNumber).toBeUndefined(); + }); + + it('setter with undefined preserves other L1 element overrides on the same bag', () => { + const bar = new Bar(); + bar.scoreDisplay = { timeSignature: { isVisible: false } }; + bar.barNumberDisplay = BarNumberDisplay.AllBars; + bar.barNumberDisplay = undefined; + expect(bar.scoreDisplay).not.toBeUndefined(); + expect(bar.scoreDisplay!.barNumber).toBeUndefined(); + expectElementDisplay(bar.scoreDisplay!.timeSignature, false, undefined, undefined); + }); +}); + +describe('JSON round-trip for the new staff-config surface', () => { + function roundtripStylesheet(rs: RenderStylesheet): RenderStylesheet { + const out = RenderStylesheetSerializer.toJson(rs)!; + const result = new RenderStylesheet(); + RenderStylesheetSerializer.fromJson(result, out); + return result; + } + + function roundtripStaff(staff: Staff): Staff { + const out = StaffSerializer.toJson(staff)!; + const result = new Staff(); + StaffSerializer.fromJson(result, out); + return result; + } + + function roundtripBar(bar: Bar): Bar { + const out = BarSerializer.toJson(bar)!; + const result = new Bar(); + BarSerializer.fromJson(result, out); + return result; + } + + it('preserves RenderStylesheet L3 historical defaults', () => { + const rs = roundtripStylesheet(new RenderStylesheet()); + expectElementDisplay(rs.scoreConfig.clef, true, StaffPlacement.AllStaves, SystemDisplay.AllSystems); + expect(rs.tabConfig.rhythm).toBe(TabRhythmMode.Automatic); + expectElementDisplay(rs.tabConfig.rests, true, StaffPlacement.Primary, undefined); + expectElementDisplay(rs.numberedConfig.timeSignature, true, StaffPlacement.Primary, SystemDisplay.AllSystems); + expect(rs.scoreConfig.barNumber).toBe(BarNumberDisplay.AllBars); + }); + + it('preserves RenderStylesheet L3 author overrides', () => { + const rs = new RenderStylesheet(); + rs.tabConfig = { + clef: { isVisible: false }, + timeSignature: { systemDisplay: SystemDisplay.FirstSystemOnly }, + barNumber: BarNumberDisplay.FirstOfSystem, + rhythm: TabRhythmMode.ShowWithBeams, + rests: { isVisible: false } + }; + const out = roundtripStylesheet(rs); + expectElementDisplay(out.tabConfig.clef, false, undefined, undefined); + expectElementDisplay(out.tabConfig.timeSignature, undefined, undefined, SystemDisplay.FirstSystemOnly); + expect(out.tabConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(out.tabConfig.rhythm).toBe(TabRhythmMode.ShowWithBeams); + expectElementDisplay(out.tabConfig.rests, false, undefined, undefined); + }); + + it('preserves Staff L2 overrides; undefined L2 stays undefined', () => { + const staff = new Staff(); + staff.tabConfig = { clef: { isVisible: false } }; + const out = roundtripStaff(staff); + expect(out.tabConfig).not.toBeUndefined(); + expectElementDisplay(out.tabConfig!.clef, false, undefined, undefined); + expect(out.scoreConfig).toBeUndefined(); + expect(out.slashConfig).toBeUndefined(); + expect(out.numberedConfig).toBeUndefined(); + }); + + it('preserves Bar L1 overrides; undefined L1 stays undefined', () => { + const bar = new Bar(); + bar.scoreDisplay = { timeSignature: { isVisible: false } }; + const out = roundtripBar(bar); + expect(out.scoreDisplay).not.toBeUndefined(); + expectElementDisplay(out.scoreDisplay!.timeSignature, false, undefined, undefined); + expect(out.tabDisplay).toBeUndefined(); + expect(out.slashDisplay).toBeUndefined(); + expect(out.numberedDisplay).toBeUndefined(); + }); + + it('preserves per-axis sparseness in ElementDisplay', () => { + const rs = new RenderStylesheet(); + rs.scoreConfig.clef = { isVisible: true }; + const out = roundtripStylesheet(rs); + expectElementDisplay(out.scoreConfig.clef, true, undefined, undefined); + }); + + it('preserves RenderStylesheet.barNumberDisplay shim through round-trip', () => { + const rs = new RenderStylesheet(); + rs.barNumberDisplay = BarNumberDisplay.FirstOfSystem; + const out = roundtripStylesheet(rs); + expect(out.barNumberDisplay).toBe(BarNumberDisplay.FirstOfSystem); + expect(out.scoreConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(out.tabConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(out.slashConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + expect(out.numberedConfig.barNumber).toBe(BarNumberDisplay.FirstOfSystem); + }); + + it('preserves Bar.barNumberDisplay shim through round-trip', () => { + const bar = new Bar(); + bar.barNumberDisplay = BarNumberDisplay.Hide; + const out = roundtripBar(bar); + expect(out.barNumberDisplay).toBe(BarNumberDisplay.Hide); + expect(out.scoreDisplay!.barNumber).toBe(BarNumberDisplay.Hide); + expect(out.tabDisplay!.barNumber).toBe(BarNumberDisplay.Hide); + expect(out.slashDisplay!.barNumber).toBe(BarNumberDisplay.Hide); + expect(out.numberedDisplay!.barNumber).toBe(BarNumberDisplay.Hide); + }); +}); diff --git a/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts new file mode 100644 index 000000000..6d45cac75 --- /dev/null +++ b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts @@ -0,0 +1,132 @@ +import { describe, expect, it } from 'vitest'; +import type { Staff } from '@coderline/alphatab/model/Staff'; +import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; +import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; +import type { RenderStaff } from '@coderline/alphatab/rendering/staves/RenderStaff'; +import type { StaffSystem } from '@coderline/alphatab/rendering/staves/StaffSystem'; +import type { StaffTrackGroup } from '@coderline/alphatab/rendering/staves/StaffTrackGroup'; + +/** + * Build a {@link RenderStaff}-shaped stub. Each siblings entry becomes + * a peer in the same {@link StaffTrackGroup}; the focused stub is at + * `siblings[focusIndex]`. + * @internal + */ +function makeGroup( + focusIndex: number, + siblings: Array<{ cascadePriority: number; modelStaff: Staff; systemIndex?: number }> +): RenderStaff { + const group = { staves: [] as RenderStaff[] } as unknown as StaffTrackGroup; + const staves: RenderStaff[] = siblings.map(s => { + let cachedPrimary: boolean | null = null; + const stub = { + modelStaff: s.modelStaff, + cascadePriority: s.cascadePriority, + staffTrackGroup: group, + system: { index: s.systemIndex ?? 0 } as unknown as StaffSystem, + get isCascadePrimary(): boolean { + if (cachedPrimary === null) { + cachedPrimary = StaffDisplayResolver.computeCascadePrimary(stub); + } + return cachedPrimary; + } + } as unknown as RenderStaff; + return stub; + }); + (group as { staves: RenderStaff[] }).staves = staves; + return staves[focusIndex]; +} + +describe('StaffDisplayResolver.merge', () => { + it('returns fallback when every layer leaves all axes undefined', () => { + const display = StaffDisplayResolver.merge(undefined, undefined, undefined); + expect(display.isVisible).toBe(true); + expect(display.staffPlacement).toBe(StaffPlacement.AllStaves); + expect(display.systemDisplay).toBe(SystemDisplay.AllSystems); + }); + + it('walks per-bar → per-staff → stylesheet → fallback per-axis', () => { + const display = StaffDisplayResolver.merge( + { isVisible: false }, + { staffPlacement: StaffPlacement.Primary }, + { systemDisplay: SystemDisplay.FirstSystemOnly } + ); + expect(display.isVisible).toBe(false); + expect(display.staffPlacement).toBe(StaffPlacement.Primary); + expect(display.systemDisplay).toBe(SystemDisplay.FirstSystemOnly); + }); + + it('earlier defined value wins over later layers', () => { + const display = StaffDisplayResolver.merge( + { isVisible: false }, + { isVisible: true, staffPlacement: StaffPlacement.Primary }, + { isVisible: true, staffPlacement: StaffPlacement.AllStaves } + ); + expect(display.isVisible).toBe(false); + expect(display.staffPlacement).toBe(StaffPlacement.Primary); + }); +}); + +describe('StaffDisplayResolver.isPrimaryForElement', () => { + const modelStaffA = {} as Staff; + const modelStaffB = {} as Staff; + const scoreStub = (focusIndex: number) => + makeGroup(focusIndex, [ + { cascadePriority: 0, modelStaff: modelStaffA }, + { cascadePriority: 1, modelStaff: modelStaffA } + ]); + + it('returns false when isVisible is false', () => { + const staff = scoreStub(0); + expect(StaffDisplayResolver.isPrimaryForElement(staff, { isVisible: false })).toBe(false); + }); + + it('suppresses paint on systems with index != 0 when systemDisplay is FirstSystemOnly', () => { + const focus = makeGroup(0, [{ cascadePriority: 0, modelStaff: modelStaffA, systemIndex: 1 }]); + expect( + StaffDisplayResolver.isPrimaryForElement(focus, { + isVisible: true, + staffPlacement: StaffPlacement.AllStaves, + systemDisplay: SystemDisplay.FirstSystemOnly + }) + ).toBe(false); + }); + + it('AllStaves paints on every staff regardless of cascade winner', () => { + const display = { + isVisible: true, + staffPlacement: StaffPlacement.AllStaves, + systemDisplay: SystemDisplay.AllSystems + }; + expect(StaffDisplayResolver.isPrimaryForElement(scoreStub(0), display)).toBe(true); + expect(StaffDisplayResolver.isPrimaryForElement(scoreStub(1), display)).toBe(true); + }); + + it('Primary paints only on the cascade winner among siblings sharing the model Staff', () => { + const display = { + isVisible: true, + staffPlacement: StaffPlacement.Primary, + systemDisplay: SystemDisplay.AllSystems + }; + expect(StaffDisplayResolver.isPrimaryForElement(scoreStub(0), display)).toBe(true); + expect(StaffDisplayResolver.isPrimaryForElement(scoreStub(1), display)).toBe(false); + }); + + it('cascade evaluates per model Staff — different model staves elect independent primaries', () => { + const display = { + isVisible: true, + staffPlacement: StaffPlacement.Primary, + systemDisplay: SystemDisplay.AllSystems + }; + const group = [ + { cascadePriority: 0, modelStaff: modelStaffA }, + { cascadePriority: 1, modelStaff: modelStaffA }, + { cascadePriority: 0, modelStaff: modelStaffB }, + { cascadePriority: 1, modelStaff: modelStaffB } + ]; + expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(0, group), display)).toBe(true); + expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(1, group), display)).toBe(false); + expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(2, group), display)).toBe(true); + expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(3, group), display)).toBe(false); + }); +}); diff --git a/packages/alphatab/test/visualTests/features/StaffDisplayConfig.test.ts b/packages/alphatab/test/visualTests/features/StaffDisplayConfig.test.ts new file mode 100644 index 000000000..191261850 --- /dev/null +++ b/packages/alphatab/test/visualTests/features/StaffDisplayConfig.test.ts @@ -0,0 +1,159 @@ +import { describe, it } from 'vitest'; + +import { VisualTestHelper } from 'test/visualTests/VisualTestHelper'; + +describe('StaffDisplayConfig', () => { + describe('Primary cascade — multi-notation single-track stacks', () => { + it('cascade-score-tab', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {score tabs} + \\ks D + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/cascade-score-tab.png' + ); + }); + + it('cascade-tab-only', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {tabs} + 3.3.4 3.3 r.4 3.3 | + 3.3 -.3 3.3 r.4 | + `, + 'test-data/visual-tests/staff-display-config/cascade-tab-only.png' + ); + }); + + it('cascade-tab-slash', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {tabs slash} + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/cascade-tab-slash.png' + ); + }); + + it('cascade-slash-numbered', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {slash numbered} + \\ks G + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/cascade-slash-numbered.png' + ); + }); + + it('cascade-numbered-only', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {numbered} + \\ks G + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/cascade-numbered-only.png' + ); + }); + + it('cascade-all-four', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {score tabs slash numbered} + \\ks F + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/cascade-all-four.png' + ); + }); + }); + + describe('Per-staff (L2) overrides', () => { + it('override-l2-tab-ts-hide', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {tabs} + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/override-l2-tab-ts-hide.png', + undefined, + o => { + const staff = o.score.tracks[0].staves[0]; + staff.tabConfig = { timeSignature: { isVisible: false } }; + } + ); + }); + + it('override-l2-score-clef-hide', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {score} + \\ks D + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png', + undefined, + o => { + const staff = o.score.tracks[0].staves[0]; + staff.scoreConfig = { clef: { isVisible: false } }; + } + ); + }); + }); + + describe('Per-bar (L1) overrides', () => { + it('override-l1-ks-change-hide', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {score} + \\ks D + 3.3.4 3.3 3.3 3.3 | + \\ks A + 3.3.4 3.3 3.3 3.3 | + 3.3.4 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png', + undefined, + o => { + const bars = o.score.tracks[0].staves[0].bars; + bars[1].scoreDisplay = { keySignature: { isVisible: false } }; + } + ); + }); + + it('override-l1-ts-hide-firstbar', async () => { + await VisualTestHelper.runVisualTestTex( + ` + \\track + \\staff {score tabs} + 3.3.4 3.3 3.3 3.3 | + 3.3 3.3 3.3 3.3 | + `, + 'test-data/visual-tests/staff-display-config/override-l1-ts-hide-firstbar.png', + undefined, + o => { + const bars = o.score.tracks[0].staves[0].bars; + bars[0].scoreDisplay = { timeSignature: { isVisible: false } }; + } + ); + }); + }); +}); diff --git a/packages/csharp/src/AlphaTab.Test/Test/Globals.cs b/packages/csharp/src/AlphaTab.Test/Test/Globals.cs index 1634e4879..64d85feaf 100644 --- a/packages/csharp/src/AlphaTab.Test/Test/Globals.cs +++ b/packages/csharp/src/AlphaTab.Test/Test/Globals.cs @@ -340,6 +340,53 @@ public void ToBeUndefined() Assert.IsNull(_actual, _message); } + public void ToBeDefined() + { + Assert.IsNotNull(_actual, _message); + } + + public void ToEqual(object? expected, string? message = null) + { + if (expected is null && _actual is null) + { + return; + } + if (expected is null || _actual is null) + { + Assert.Fail(message ?? _message ?? $"Expected {(expected is null ? "null" : expected.ToString())}, got {((object?)_actual is null ? "null" : _actual!.ToString())}"); + return; + } + + var expectedType = expected.GetType(); + var actualType = _actual.GetType(); + + if (expectedType == actualType) + { + Assert.AreEqual(expected, _actual, message ?? _message); + return; + } + + // Structural comparison: walk expected's properties (e.g. an anonymous object from a + // TS object-literal `expect(x).toEqual({...})`) and match against the actual instance's + // properties case-insensitively (TS source uses camelCase, C# properties are PascalCase). + var expectedProps = expectedType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + foreach (var prop in expectedProps) + { + var actualProp = actualType.GetProperty( + prop.Name, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase + ); + if (actualProp is null) + { + Assert.Fail(message ?? _message ?? $"Property '{prop.Name}' not found on {actualType.Name}"); + return; + } + var expectedValue = prop.GetValue(expected); + var actualValue = actualProp.GetValue(_actual); + Assert.AreEqual(expectedValue, actualValue, $"Property '{prop.Name}'"); + } + } + public void ToThrow(Type expected) { Throw(expected); From 232996303b0b2bae94ae50b772764ad1c560ebd0 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 28 Jun 2026 21:44:44 +0200 Subject: [PATCH 2/3] build: fix transpilation --- .../src/rendering/staves/RenderStaff.ts | 18 +- .../rendering/staves/StaffDisplayResolver.ts | 25 ++- .../rendering/StaffDisplayResolver.test.ts | 189 +++++++++++------- 3 files changed, 152 insertions(+), 80 deletions(-) diff --git a/packages/alphatab/src/rendering/staves/RenderStaff.ts b/packages/alphatab/src/rendering/staves/RenderStaff.ts index 3dad97d70..679fcede7 100644 --- a/packages/alphatab/src/rendering/staves/RenderStaff.ts +++ b/packages/alphatab/src/rendering/staves/RenderStaff.ts @@ -11,7 +11,7 @@ import { import { EffectSystemPlacement } from '@coderline/alphatab/rendering/EffectSystemPlacement'; import { StaffSystemSkyline } from '@coderline/alphatab/rendering/skyline/StaffSystemSkyline'; import type { BarLayoutingInfo } from '@coderline/alphatab/rendering/staves/BarLayoutingInfo'; -import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; +import { type IStaffDisplayContext, StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; import type { StaffSystem } from '@coderline/alphatab/rendering/staves/StaffSystem'; import type { StaffTrackGroup } from '@coderline/alphatab/rendering/staves/StaffTrackGroup'; @@ -20,7 +20,7 @@ import type { StaffTrackGroup } from '@coderline/alphatab/rendering/staves/Staff * It stores BarRenderer instances created from a given factory. * @internal */ -export class RenderStaff { +export class RenderStaff implements IStaffDisplayContext { private _factory: BarRendererFactory; private _sharedLayoutData: Map = new Map(); @@ -60,14 +60,24 @@ export class RenderStaff { return this._factory.cascadePriority; } - private _isCascadePrimary: boolean | null = null; + private _isCascadePrimary: boolean = false; + private _isCascadePrimaryComputed: boolean = false; public get isCascadePrimary(): boolean { - if (this._isCascadePrimary === null) { + if (!this._isCascadePrimaryComputed) { this._isCascadePrimary = StaffDisplayResolver.computeCascadePrimary(this); + this._isCascadePrimaryComputed = true; } return this._isCascadePrimary; } + public get systemIndex(): number { + return this.system.index; + } + + public get cascadeSiblings(): IStaffDisplayContext[] { + return this.staffTrackGroup.staves; + } + /** * This is the visual offset from top where the * Staff contents actually start. Used for grouping diff --git a/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts index a0866e578..854003de6 100644 --- a/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts +++ b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts @@ -1,6 +1,21 @@ import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; -import type { RenderStaff } from '@coderline/alphatab/rendering/staves/RenderStaff'; +import type { Staff } from '@coderline/alphatab/model/Staff'; + +/** + * Per-staff view required by {@link StaffDisplayResolver} to evaluate + * placement decisions. Exposed as an interface so unit tests can supply + * lightweight stand-ins without instantiating a full render pipeline. + * {@link RenderStaff} implements this directly. + * @internal + */ +export interface IStaffDisplayContext { + readonly modelStaff: Staff; + readonly cascadePriority: number; + readonly systemIndex: number; + readonly isCascadePrimary: boolean; + readonly cascadeSiblings: IStaffDisplayContext[]; +} /** * Helpers for the staff-placement cascade and the per-axis @@ -41,11 +56,11 @@ export class StaffDisplayResolver { }; } - public static isPrimaryForElement(staff: RenderStaff, display: ElementDisplay): boolean { + public static isPrimaryForElement(staff: IStaffDisplayContext, display: ElementDisplay): boolean { if (display.isVisible === false) { return false; } - if (display.systemDisplay === SystemDisplay.FirstSystemOnly && staff.system.index !== 0) { + if (display.systemDisplay === SystemDisplay.FirstSystemOnly && staff.systemIndex !== 0) { return false; } switch (display.staffPlacement) { @@ -57,10 +72,10 @@ export class StaffDisplayResolver { return true; } - public static computeCascadePrimary(staff: RenderStaff): boolean { + public static computeCascadePrimary(staff: IStaffDisplayContext): boolean { const modelStaff = staff.modelStaff; let primary = staff; - for (const sibling of staff.staffTrackGroup.staves) { + for (const sibling of staff.cascadeSiblings) { if (sibling === staff || sibling.modelStaff !== modelStaff) { continue; } diff --git a/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts index 6d45cac75..f95e9e128 100644 --- a/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts +++ b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts @@ -1,99 +1,138 @@ -import { describe, expect, it } from 'vitest'; -import type { Staff } from '@coderline/alphatab/model/Staff'; +import type { ElementDisplay } from '@coderline/alphatab/model/ElementDisplay'; import { StaffPlacement, SystemDisplay } from '@coderline/alphatab/model/ElementDisplay'; -import { StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; -import type { RenderStaff } from '@coderline/alphatab/rendering/staves/RenderStaff'; -import type { StaffSystem } from '@coderline/alphatab/rendering/staves/StaffSystem'; -import type { StaffTrackGroup } from '@coderline/alphatab/rendering/staves/StaffTrackGroup'; +import { Staff } from '@coderline/alphatab/model/Staff'; +import { type IStaffDisplayContext, StaffDisplayResolver } from '@coderline/alphatab/rendering/staves/StaffDisplayResolver'; +import { describe, expect, it } from 'vitest'; /** - * Build a {@link RenderStaff}-shaped stub. Each siblings entry becomes - * a peer in the same {@link StaffTrackGroup}; the focused stub is at - * `siblings[focusIndex]`. + * Lightweight {@link IStaffDisplayContext} implementation used to drive + * {@link StaffDisplayResolver} without a full render pipeline. Sibling + * arrays are shared by reference across peers in the same group. * @internal */ -function makeGroup( - focusIndex: number, - siblings: Array<{ cascadePriority: number; modelStaff: Staff; systemIndex?: number }> -): RenderStaff { - const group = { staves: [] as RenderStaff[] } as unknown as StaffTrackGroup; - const staves: RenderStaff[] = siblings.map(s => { - let cachedPrimary: boolean | null = null; - const stub = { - modelStaff: s.modelStaff, - cascadePriority: s.cascadePriority, - staffTrackGroup: group, - system: { index: s.systemIndex ?? 0 } as unknown as StaffSystem, - get isCascadePrimary(): boolean { - if (cachedPrimary === null) { - cachedPrimary = StaffDisplayResolver.computeCascadePrimary(stub); - } - return cachedPrimary; - } - } as unknown as RenderStaff; - return stub; - }); - (group as { staves: RenderStaff[] }).staves = staves; - return staves[focusIndex]; +class StaffDisplayContextStub implements IStaffDisplayContext { + public modelStaff: Staff; + public cascadePriority: number; + public systemIndex: number; + public cascadeSiblings: IStaffDisplayContext[] = []; + + private _cachedPrimary: boolean = false; + private _cachedPrimaryComputed: boolean = false; + + public constructor(modelStaff: Staff, cascadePriority: number, systemIndex: number = 0) { + this.modelStaff = modelStaff; + this.cascadePriority = cascadePriority; + this.systemIndex = systemIndex; + } + + public get isCascadePrimary(): boolean { + if (!this._cachedPrimaryComputed) { + this._cachedPrimary = StaffDisplayResolver.computeCascadePrimary(this); + this._cachedPrimaryComputed = true; + } + return this._cachedPrimary; + } +} + +/** + * @internal + */ +class StaffDisplayContextSpec { + public cascadePriority: number; + public modelStaff: Staff; + public systemIndex: number; + + public constructor(cascadePriority: number, modelStaff: Staff, systemIndex: number = 0) { + this.cascadePriority = cascadePriority; + this.modelStaff = modelStaff; + this.systemIndex = systemIndex; + } +} + +/** + * @internal + */ +class StaffDisplayContextFixtures { + /** + * Build a {@link IStaffDisplayContext}-shaped stub group. Each entry in + * `siblings` becomes a peer sharing the same sibling array; the + * focused stub is returned at `siblings[focusIndex]`. + */ + public static makeGroup(focusIndex: number, siblings: StaffDisplayContextSpec[]): IStaffDisplayContext { + const staves: StaffDisplayContextStub[] = []; + for (const s of siblings) { + staves.push(new StaffDisplayContextStub(s.modelStaff, s.cascadePriority, s.systemIndex)); + } + const sharedSiblings: IStaffDisplayContext[] = []; + for (const staff of staves) { + sharedSiblings.push(staff); + } + for (const staff of staves) { + staff.cascadeSiblings = sharedSiblings; + } + return staves[focusIndex]; + } } describe('StaffDisplayResolver.merge', () => { it('returns fallback when every layer leaves all axes undefined', () => { - const display = StaffDisplayResolver.merge(undefined, undefined, undefined); + const display: ElementDisplay = StaffDisplayResolver.merge(undefined, undefined, undefined); expect(display.isVisible).toBe(true); expect(display.staffPlacement).toBe(StaffPlacement.AllStaves); expect(display.systemDisplay).toBe(SystemDisplay.AllSystems); }); it('walks per-bar → per-staff → stylesheet → fallback per-axis', () => { - const display = StaffDisplayResolver.merge( - { isVisible: false }, - { staffPlacement: StaffPlacement.Primary }, - { systemDisplay: SystemDisplay.FirstSystemOnly } - ); + const perBar: ElementDisplay = { isVisible: false }; + const perStaff: ElementDisplay = { staffPlacement: StaffPlacement.Primary }; + const stylesheet: ElementDisplay = { systemDisplay: SystemDisplay.FirstSystemOnly }; + const display: ElementDisplay = StaffDisplayResolver.merge(perBar, perStaff, stylesheet); expect(display.isVisible).toBe(false); expect(display.staffPlacement).toBe(StaffPlacement.Primary); expect(display.systemDisplay).toBe(SystemDisplay.FirstSystemOnly); }); it('earlier defined value wins over later layers', () => { - const display = StaffDisplayResolver.merge( - { isVisible: false }, - { isVisible: true, staffPlacement: StaffPlacement.Primary }, - { isVisible: true, staffPlacement: StaffPlacement.AllStaves } - ); + const perBar: ElementDisplay = { isVisible: false }; + const perStaff: ElementDisplay = { isVisible: true, staffPlacement: StaffPlacement.Primary }; + const stylesheet: ElementDisplay = { isVisible: true, staffPlacement: StaffPlacement.AllStaves }; + const display: ElementDisplay = StaffDisplayResolver.merge(perBar, perStaff, stylesheet); expect(display.isVisible).toBe(false); expect(display.staffPlacement).toBe(StaffPlacement.Primary); }); }); describe('StaffDisplayResolver.isPrimaryForElement', () => { - const modelStaffA = {} as Staff; - const modelStaffB = {} as Staff; - const scoreStub = (focusIndex: number) => - makeGroup(focusIndex, [ - { cascadePriority: 0, modelStaff: modelStaffA }, - { cascadePriority: 1, modelStaff: modelStaffA } + const modelStaffA: Staff = new Staff(); + const modelStaffB: Staff = new Staff(); + + function scoreStub(focusIndex: number): IStaffDisplayContext { + return StaffDisplayContextFixtures.makeGroup(focusIndex, [ + new StaffDisplayContextSpec(0, modelStaffA), + new StaffDisplayContextSpec(1, modelStaffA) ]); + } it('returns false when isVisible is false', () => { - const staff = scoreStub(0); - expect(StaffDisplayResolver.isPrimaryForElement(staff, { isVisible: false })).toBe(false); + const staff: IStaffDisplayContext = scoreStub(0); + const display: ElementDisplay = { isVisible: false }; + expect(StaffDisplayResolver.isPrimaryForElement(staff, display)).toBe(false); }); it('suppresses paint on systems with index != 0 when systemDisplay is FirstSystemOnly', () => { - const focus = makeGroup(0, [{ cascadePriority: 0, modelStaff: modelStaffA, systemIndex: 1 }]); - expect( - StaffDisplayResolver.isPrimaryForElement(focus, { - isVisible: true, - staffPlacement: StaffPlacement.AllStaves, - systemDisplay: SystemDisplay.FirstSystemOnly - }) - ).toBe(false); + const focus: IStaffDisplayContext = StaffDisplayContextFixtures.makeGroup(0, [ + new StaffDisplayContextSpec(0, modelStaffA, 1) + ]); + const display: ElementDisplay = { + isVisible: true, + staffPlacement: StaffPlacement.AllStaves, + systemDisplay: SystemDisplay.FirstSystemOnly + }; + expect(StaffDisplayResolver.isPrimaryForElement(focus, display)).toBe(false); }); it('AllStaves paints on every staff regardless of cascade winner', () => { - const display = { + const display: ElementDisplay = { isVisible: true, staffPlacement: StaffPlacement.AllStaves, systemDisplay: SystemDisplay.AllSystems @@ -103,7 +142,7 @@ describe('StaffDisplayResolver.isPrimaryForElement', () => { }); it('Primary paints only on the cascade winner among siblings sharing the model Staff', () => { - const display = { + const display: ElementDisplay = { isVisible: true, staffPlacement: StaffPlacement.Primary, systemDisplay: SystemDisplay.AllSystems @@ -113,20 +152,28 @@ describe('StaffDisplayResolver.isPrimaryForElement', () => { }); it('cascade evaluates per model Staff — different model staves elect independent primaries', () => { - const display = { + const display: ElementDisplay = { isVisible: true, staffPlacement: StaffPlacement.Primary, systemDisplay: SystemDisplay.AllSystems }; - const group = [ - { cascadePriority: 0, modelStaff: modelStaffA }, - { cascadePriority: 1, modelStaff: modelStaffA }, - { cascadePriority: 0, modelStaff: modelStaffB }, - { cascadePriority: 1, modelStaff: modelStaffB } + const group: StaffDisplayContextSpec[] = [ + new StaffDisplayContextSpec(0, modelStaffA), + new StaffDisplayContextSpec(1, modelStaffA), + new StaffDisplayContextSpec(0, modelStaffB), + new StaffDisplayContextSpec(1, modelStaffB) ]; - expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(0, group), display)).toBe(true); - expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(1, group), display)).toBe(false); - expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(2, group), display)).toBe(true); - expect(StaffDisplayResolver.isPrimaryForElement(makeGroup(3, group), display)).toBe(false); + expect(StaffDisplayResolver.isPrimaryForElement(StaffDisplayContextFixtures.makeGroup(0, group), display)).toBe( + true + ); + expect(StaffDisplayResolver.isPrimaryForElement(StaffDisplayContextFixtures.makeGroup(1, group), display)).toBe( + false + ); + expect(StaffDisplayResolver.isPrimaryForElement(StaffDisplayContextFixtures.makeGroup(2, group), display)).toBe( + true + ); + expect(StaffDisplayResolver.isPrimaryForElement(StaffDisplayContextFixtures.makeGroup(3, group), display)).toBe( + false + ); }); }); From e9d7248893928d14564bf4712ccc9444cd575afe Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 28 Jun 2026 22:04:09 +0200 Subject: [PATCH 3/3] build: fix transpilation and update tests --- .../src/rendering/staves/RenderStaff.ts | 2 +- .../rendering/staves/StaffDisplayResolver.ts | 2 +- .../staff-display-config/cascade-all-four.png | Bin 18028 -> 18013 bytes .../cascade-numbered-only.png | Bin 5705 -> 5274 bytes .../cascade-score-tab.png | Bin 15596 -> 15699 bytes .../cascade-slash-numbered.png | Bin 8193 -> 7634 bytes .../staff-display-config/cascade-tab-only.png | Bin 10053 -> 10170 bytes .../cascade-tab-slash.png | Bin 12647 -> 12633 bytes .../override-l1-ks-change-hide.png | Bin 10035 -> 10036 bytes .../override-l1-ts-hide-firstbar.png | Bin 14161 -> 13947 bytes .../override-l2-score-clef-hide.png | Bin 7665 -> 7784 bytes .../override-l2-tab-ts-hide.png | Bin 8794 -> 8908 bytes .../rendering/StaffDisplayResolver.test.ts | 12 ++++++++++-- 13 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/alphatab/src/rendering/staves/RenderStaff.ts b/packages/alphatab/src/rendering/staves/RenderStaff.ts index 679fcede7..a63194e9f 100644 --- a/packages/alphatab/src/rendering/staves/RenderStaff.ts +++ b/packages/alphatab/src/rendering/staves/RenderStaff.ts @@ -74,7 +74,7 @@ export class RenderStaff implements IStaffDisplayContext { return this.system.index; } - public get cascadeSiblings(): IStaffDisplayContext[] { + public get cascadeSiblings(): Iterable { return this.staffTrackGroup.staves; } diff --git a/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts index 854003de6..67fdebac0 100644 --- a/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts +++ b/packages/alphatab/src/rendering/staves/StaffDisplayResolver.ts @@ -14,7 +14,7 @@ export interface IStaffDisplayContext { readonly cascadePriority: number; readonly systemIndex: number; readonly isCascadePrimary: boolean; - readonly cascadeSiblings: IStaffDisplayContext[]; + readonly cascadeSiblings: Iterable; } /** diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-all-four.png index 8d161c2758bc659493f5d2d0e5aba89273f0fdc8..44e99706f4a5914e839c68c9155ab46c37cb410c 100644 GIT binary patch literal 18013 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 D&)AR2 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-numbered-only.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-numbered-only.png index 1f500f594164d73b2a64e6bb6776f881f0d7b697..2e57b35496d7ffc92c098fef15fd92e31758fee8 100644 GIT binary patch literal 5274 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 literal 5705 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 a(gmVwi{^y$>+p|+$U#%flcgsv-})brfj0sG diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-score-tab.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-score-tab.png index 49aded466a15fc3595965a38a48fb163534e8c43..832f2df5f99d2dd1e078fd337b70c14257c5e5ee 100644 GIT binary patch literal 15699 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 C6E`^k literal 15596 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 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-slash-numbered.png index de154cdb255174d967d685220f47f0fbcc26a158..c03abfd62309d63d42a43ef0f75ac0ed8a2adeca 100644 GIT binary patch literal 7634 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 literal 8193 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 MEPp9Kd-=|P0J53*DgXcg diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-only.png b/packages/alphatab/test-data/visual-tests/staff-display-config/cascade-tab-only.png index cb3b4e0fb3319986474e158f8aaac58b264e3ccc..8915ddbe07811878cbf3edfba60a13c1a5f15ae6 100644 GIT binary patch literal 10170 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 B7Uci{ literal 12647 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 Vg7iP{T@#N8JZo_#{}0!@{|&b}G|vD4 diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png b/packages/alphatab/test-data/visual-tests/staff-display-config/override-l1-ks-change-hide.png index 4530c90e9bba22f226f723d0f3577d1b9abba02e..1aa8cddf2dea072d6218518b47ba3283c53ea18c 100644 GIT binary patch literal 10036 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

hpI4AbuJI^SKZxlV+5nL z=q6_!&u086{iJ_kgxV+e!ij)}Zp>zruy)ntR;+Z|_NTTMnlr-W4PL3{3 zQ@YidtO6;HKSviU6z`gKyN#F16jxnB3Q+kM%|>vNx+F1HS(OQ)AQLVbz4?L}*58UE z6%=5yOq2flbM*J=CTnFmsJMbw*XPGtuAkdC{!5UV`P|!nnjsH!CAR0{WWSl1X0$lE zB6eGq99t($pSoX`A8gx!=EE)(lo73b$@%ehx{ zH*v854wbNUh%TP?G&&{omYc|(ub z*J0&bH-@&He056Kekif6$42?qijhf1@@t$sXpqwI^&aV_sIiSE>?phZi-no?`wft$ zCJuJ_)z%KB$g0AuHnWFx9R?R^iSo#rL&WjWWYZp@91~frV0YEIgevjQ z5eM9B?gtV=M<4Bem(@mxsEbS)DHnv?5Aiv$)=RZen2V6)tW780Aggd6@0KYZveRei zso`JT8;7Pc)aScBZmxuaWNB#A^GIP#;mz3jjbYDt`?vdg3^N}NbR_tx7pydtZcvbi zFLr^tiClzaM;ez^&QJrU_fRSIgLCXw7??*R09S*Sc4)GeNbos-pK3CAd)99BrXy`g z*7ElpP?`A~#j|ULgNCbOdAy7iwE|sZi6ky^{lOFH^T+@54R_0(5WI>G*N!|3E)F*? z^RHxll7FH~Jysg?r~|D7$l#`2L7Zpk&ZGPlQOKQN#IOHITYI}7_n^@4hsrmsAY)ue61{{3L;$b64OQmUcGhBaAppC>?{ji;jJ36gav2yzA}xgb zvNiKAUoAs2CG1|nHZtPWFXa4j3B*lA5g=tD_zyIGB79WBeqMlx2>MXf=7Sv68e5&( z&P)(ptj|GXYimn-55c&O&^0#nlC~%c?E(cny1rGOn=y`*?CIPj?6!G-@I^+TH0z=j zsB^uxI9ACqxIxX^d{+)1dk2wTb7s|J&L70BZ`nJqfBJM^Zhs@A2dA&4wO^zf;vt&w zK{L41Q<#;0jjAM9xG4OFgbcMZ3JhMveLX-lUls78R@U0Gm!WO5?$J z+A7bUS%!kspZ3OFYvCln@xhL4Vfy>5H>rfFQ<8<-AQr+&OTUg}O>TYb`k<0A_yeI| z$F;r(K`l>gSYf15xq;6xYjr;F_(kX?81*iCT&0`^K|#>3OiH~hiG;qCPv1xh+BODqxxv^s2%>{YVhsvh%2^xHap)Okc{1{W}JR7 z;nz?{rnMl(9AN$vn?#cMn0RCoaTXeGQ00ZH->>^#<~>@dA!L>~imzFz&M&E`a98IS zW~)7>@)T3t>lMuI)lT_sYk~2&bw~=w9hw>&OW3l>P`f-mTbM?wL=Dxt^!p#4Q#|lr z9;w6z=B7WXB*7$EuMDSzuP}@s58vPWF#%gOdJ=>AR7b4zdL&!id*%M=+vO^F)UOS; zyF>&A@KXJ@bK6wYYq#oFy$5hQE8p=2s{Ta(P>H{h1^77{|FVG~|C0)@jhXt{G>>uJ zO1q&ZN=3#J^g#V~xl^GrkEB&kI;^(7{yD~Nz%U`vGgm#sNb@1^(brFTl^8EzY~;Jv zdf8>jG9jYyz6j+?efAzf%L2SS%>pP7*YgpRSrs2O4##p3k8qz07|DIT6A@MG1B6*S9g)>K`0T z1pMBSS@K!mpc}g)b48WcG0X98io(0LOPAtg+`iwG^I}8LorH2;?tL?Pr-c3e*`g;U zW<#;m>Iac^)!l1tEIrZJR3r{Je-+=))i07>EA~GO=hLqMVJD#eo<{Conh%nMgB4l) zVqK-`L|62ZwY9aKmP*>x)N+5J!=z~g*4LduA!PLHaLom`g}ywQ&0d9)-}-)jupRWV zxSG^_ork4x5|2|$l>PdjZ+4@|x2{r$Sx9pmF}p!QHHnEJ+nApYoDY&)-rWtS+VYXx z9yIrw|B#@R`-|nx)KNr)bQNwznoh=(J1)*~=HhBS4nf-%!Q$U%`1WqqDWt$|Yirx& zOy?JDe=jW^URWsI=0`<$;>Ht&5gi4G%>mc4mMl$72uJhtRS6vs(ywk*f>|PgCF!H~TbT$60n| zu}AGf4dJZ(XJDSEKhHbVy$?AylXpPZ}EmxYYk6+xfgNE5}^WpZNn)w@mPc!-~mBjp--}IP7;Ahs>G6t|Jgvg}E zdZ$adU5COpHSD&;o*&#U6X7$qEO(5L`>ms!U_bn_GagbIoYhrjWV|w%`?S&n&w6$GW)4K$LqmpX zS`0JgL`W$l*tY}ZvQ%p}n0TZ^{pE(de%Cwt>Es4ux7S=_+XASkDA>$su=huATkJ_; zr;rXtT3WK1pFW9d85&BlS2q;OX`Q+X6Fa2>v-DslHeuAGQuDcu-tQ`2COooNb_qci z34LRO@u#d{VcPqNdv^laeT1m!$@o%}<{Q(+S3bz^U4VXtGjXceAdrJPi}? zx9QOusUU;5=Ennpq=5s?+s`ryxR)n)OPNSgS!ie5Z_4N|@c->l7{;2VM`RFfejJSQ z2ynGPyG$Hr^1m*8Ofm@lNKlVw0E!L1@TRW1FYTXs?0;ptrGNka>u`oES4b8X7QU9d zcYR1O@;+dXlyP=;HTLq_d$H;}EA794Za5yCJGyDxzbSWout5*=-u&h=)1`bo(kj)s zKHVAKaD2GR(qP#cUp#$XZsFtm5M$4Y;6hnr+kf3G23B08J2&Tlsayv>&und}DSw^3 zD^R~{#$U5kT5{>qrI9HFA?95;|CM_8<>A4F<@L_lr3R-d6@2k=RUe{w&3DQ{gq zz0oc0I0(d2$4pN~#w&LSy#KNFvWRI@P=`woOq^0^%=Om;c3OS|J$N&@I0qZ^ctPb) z$l&fnv3qDcR<&t#qsLmeYP7aT~*7FJ*;8B_XY@{ zRNyH=_a!|7GP>TZHMyNp7X!bo-@rrD=#JN~U+=an$~HN*G3~s6nmSbBi0*EN%5_nz z%QTV-)ZXHZnTS%Lm}qB@wD|o=`^)y2Yfc1%_&T;3y74DQz0`gA2?6<)mP8?QiMh;| ziNcm0e}FwDtq5VWweb63iscwHpPOL?M15>Rg3IniC`8brJt}l$A0e$^yCr7Ybm9K} z`(}CK0c%rS&S<}I8#}w&>oMO{zwOj^+jUO0Mdp^2oNiJu|5DhmC;H4%uH0Oy@TPLZ zF$du!GL-~=%lV%lWN=Gmz-)pk+3yK@Z$1U4WM(5?_}fEiEL1fPs?T zdhk74a^BTj&9+Tj2a$}l__kq4pL`Msd1cz#aaK?2JD#C$@a7j5@sIR9EDh`CP;jmXWj!Q*+4J4_lZEjLO=diFZ z{Rrd5NzeB8?6I!?vLmL@n{AaMx zCCEVV>L)&7*biO)t56n&rC50}3B z)z=R$PMm0^?t1&icm8hnq(M3(L)NgZ{)bXEd~&^Dp&4FuMQt^y8JLc!3;jTt5>wCr zI@G;yRyqE>AHT%)OSeO( zn-8VF&zD?2^a%bMsFp#3CvxifPy7;5l_zIpn<~3zM?*$*eJ`t^H1E~}3m>Psq({U{ zpn6iq3##2~36l_MQ`y$J1&X_-M{O~IC6Wj~YvzFzh8e#llIF7d&VFBV&pOgc*3Hb} zv^W&B=4!l^a(-pEnf{8N;vc83)j+g6V3ued#}k~+zA(Q++&Yt0z@V_sy%5ztyQuI2 zD~>8Ned=ndL^n#B8uxzSCl3>&ZALq84VBxRYV+Qiu|}w^{-bTPJcpsB4|7}B=yzXR zCVLMTwt50zJkL+zldOST{g3TBnet7=r*}dUtDPUlXa7EhexBRaKJsfx*dvR6xV5}G zM?g91?k!i#kq;uFI^%p)wa z`LOg5vnkdg-Kk*Th2GZ3Fd0f%ls`W4r@?sX@r)+_m(Ep;yBc~C)x6gV$4@sL;^;X^ z8kK*+`RVJ&KNIS|I34b9k|@9yD!-ml6fpY z3a8~ub{Vm+d@%CG=GTaDlB%hb)0#OUi!T;!-JQC(qfsn5^1vEM<}7Ot)+KR{qq~}o z5#r+#IeB?JtNt3F`8+-`4H&q5&t(Bv5Yzzx>2?6%?S?(jek}ANR$Xb<8GhT*Sagwr zOPzZ%N56i>{{GFo8#CW6cd;GoRW6s8o_Um6eYbNmP*!$YTah+6O}d87JxH&+R)6~R zQ?(P8=U8A+RYHr|{H1PCYt~xIV|={-L9)jWz~`#T*Sy?3JQEA~#hh{88&1rg7%;&1 z+HmOO=d!zv@!?`}fGvC%_0f|Zyu}uCy;(KetD{vhz`~TeE$RShuJ_pljF0a#9=36W zTb)&u+keXU|$ymP88ZHRt{lt?bK^fc&!Jg6CChI(v>9v$+ z5%!P6H2(|o^}ePjYu8NAh6WQ!CY7*FlDFzi5;v6&+=$*=nf&|p8d@YBl0t&Bw1E=I+xF=TdjPR%V34u< zEjv;L`3-BsTKW9GALqP@*jq{7iChpOL9;8SLBnHP5FTggqiR zaU*Q05ZN5>FbaIK;PCgw==u&9=>z;-B5b~(@#K=AXxR{C;?fow_JIkg_aYUdEYLQ9 zw_4))DVO8O)1M=T(WLwiuA)LShlu!-aobPrYESrGhtp%VOqj8kOl-N@_AkN}xzGv= zB!3xTQuq zP5kexRd=}lL(G?N^!ex%8y!xJIMmqpebUaSK-YS0)Oain3R$!vmKrDnB00yWs}iTIu(jutjS1-PQ?{YG$%nxWPI9#MH?uvq)f z`>+4E5Q+RJM1<_#u-`ec%0dZMnnpnZ<4vd5*Ou1+j$q@{184>&`6A9 z%%b}`Kff$*n%b&8vJm)_AX8+Ob=v%3H*C}cZFYr$p}50BSZmm)-u|(&(9>QM(6eWp z-vQp{@@^og+$s`yjK2*X2}Vt$2%Q;m-gMgr!>vN+ zPmF1*t8j0V^NP

+s?R@UErNou|cp=9{NglR2FZwf41Io=lR#KKzn1?@}H!0$$4* z=B^=q+A*w48*)A{=w&+goQSTb{*Uttf zp^8hlFXI_sSO~aeNcaBSB=%chg4j^yrqfpP&Q3SrH=_`YB1Fgw5_pN!TB)bO2ju#{ z#8*I4joz3;){NNMhsyrkx0HoQ=ipGE69o2+J*aN#ar>o-ZC9 zSca17)hu2mnB0l*tat(Fz_6QHN_wf&0~2Q|EJq$>^G}eO`Y#q>TT9w6L}{UZ3d;Ri zbRy(BZ8dv5i;KVGCp8nt4ZVVpdb5R4?d(YVm5X@c6UkAkQaHI;0>p6aq%Su|w03uM(<(w+Ww9 zYn@9R3&E<~oFg{3Of7J0*mMGiaGrCmddrNHCdOJWQ(f=3m$$_+%=C7=u!*hb`EnR` zNYcbuN_?jBr1zvuq~S>+vm>(9{rcD7-a^!`zpdj5(kX$hE#my7mej%4Z8RBY1M-#x zZo0YlZ)cdlKChz=w+5LBZ$V_~hKfiPGS4iQt(T;sn&X6GeY-5zLU+pPl%v0d6SrC< z$Cmqfs5+hMHyp}*fToz^p(uMy=PCA8@2rb#Lts|wl5lSeoUYJUwzEN(o5%}!aRL++ zI!bMR<9yXgPiA@l&&CH-H=X(0v$vlJX3-TZ1gZyl1W;kjCpK6D_08U#(pV1VeR01j zipxp76194JtW^tDo=F5S`^ zZ9KPq)u4iq5pT0W*k8vrf!;m8epxQ zN3UDSKRj=0T=j2|ccc*i&l>FqqG?#zwIFdVB6A!%;$$R~}*Fv)G^YuG7Zl8dQ zCNvHkG#Q{(>EP#gODfIiipLF2b*JM)fAirl3)X=6^9pJHcKea}l-f!?j)DNneBW|9 zMY09J{`aj;Q*A76mj!QzTs$>Q+J}D!Qcw0+?|49deDDLE)W`JuzsRHD6#ueq2`?>UR~N(wmA)C9&-7MIF;WNTzu+y_nlALRaGqD=4OyF|Nf zz0jwn2K;aQN}AS2o&1U@T|jcOvdho;&D4HG{>fhXEqb;_SoFkIHLdf3Wc7=0-0%9w zIy(A>h81}bhhNb4pn+ZrWO|>yHXxwAKI+b1`S@Q5xFIh8N1v?;l|@~>dI_k+Kmv~d zt?ez|{br9i8s&mYw1zZj!H8X0IvDu=nq=A!Q^#MXh16SEipNwv)Nd4j-)8c)) z>s<=~Fbk+p-xMUFBTt1MP<(vDlb+LS)qQ~izeAztgFq_{^cE{tRFGbROoCun6#ndu z5Rmmu#uLL<_({->N*H%co6wOscbL7T%`#`$)+vJA50LP2ve`LGFZUzFUKEtsG+TH! zq9B|#)QMURjBLB8QZ^f4e5XPePaI6xMhE2Te8kT$?Tua>{tj&x9DX3w5(5mf#XaWB z`5jULd`h43I~{&2z)O{TpR>5vUqE?&Trhh1b;MFxEY!_#Y54o zKp2Xw2i*vh%mI>+(Q&5w&=OWBao9=#)nI(gphL9YSx!s070>+IIwaeSVAp%J@yoAH z6gogZFb%b%FnL2Q63+wg_%iLSFrUV^Or}l|Bh8pm540~OY?bJxelZ$3;_*6Jq`FX5Eg$Z%US|R1FCS;19ur~e;^j$6%izV)MeT_u7atWY$jr?A zrK<g0T(l#}n7#8W4cwcqdEPvT*ZL$?tpkL`=VciB1 zbpF$x%c+)%6tVki8pZ<@OShJ&g`2>byWx~|Bbxt%d zAmfV$3P`T%#U-ZA1Y(ZkUAGCDT7X=-b1G8KsOtIQzT$lq6=|_SibuxA{=mT{#5+~J zpzI4KKvB#ZP}^BtZ!6^oQWnM*l9GzjfKvjE0g>NaN;(rzL|KANyQ>QDJ3QYXg)Tq9 z*+i;xitzB>F3;zF;s}iWPy%kL+Y+l{YU-b(2Al2!w8G%-`hl+z4A2Yxf4IG2O9C?y z`v=cBW2!RCrobyu-oV+P@Az_m&C8YlSds1mMAmu|gY@?w@7ClM7qblX^=)bZ=J@P9 z-SM)yuB`l{IHuNB%Fh(&!@f6DT*{%pPc=D4EqC^dyTOTysuC}Qj>|gTSf%v;tyWc+ zc5qxaAuw|pB+@kNxa{}Ga8l0%-M&46qBiwsq#$vry$SWWL0|=OGi?l!USulsF7}Sv=o#G>^5$B)752zOH6OxnH!P?p% zk`@+z(*HQLKTJB^I~M3*e#`|lf_%P5E*AI$Wo$6JXgiY6Y@0g1!Z)t0p-t;i5=#tb zdZeS&X1w5T@~~lvH=rZB5DQtd8x$pn5;>kqCUvcaphV(Y+JzY}%p1X24?k6*YbAVK zh5uk7anu}Z50i-~wkS%;;0hJKKS_SP+UqXu_(y1h`peNQ`hg*dQ(iK@9@lR9V=iU# z%p^KcY;aPLjrfebFK6cfPz*TyGMT|dwU^Rdo8WZcOkeFu&EJwVRc0=rlJV3I1Y6uD z(4*TCBdE)gj>xZ>f=`b^~&&&mbWvYaR-Re9l($5e}a4kJw-(b?ILehxcRjR2N8 zrDQbk(^EB;Aiko$i0wPIytV!Wg90Jv)HmB9A4qbzK)`uEmYHj|6>MZa{1DDIx^p7h zw+vA7$(knIgU2`#lw;GZR*l3tJIm8w%nL8wB$TC>^{0`zmhTJqJZ2Q+>Vlr%w-NV# zCckEn%9?P|4=<*{YlAc_zx$`x!dwb32Q{{I^6V#GY19ZwzONEzTrAt+1Hb_Y@iIs< zE>}8@rcE4*p!BP+{;epEsBA|4hfRDh-36$mGUEUpol!$mbA4d3sHR9RYGd^4*ROp5 za;-Q%eVQohy*a1e1xP6mLkR?~^(_q<-}v}Z!gKCgLRSyY}({R*jLI^a=4}UZ*eY)cIoKo0PXI!$sHjox>Y`CojmilGIkL7QnqOPa^IPYrQ0>E2+@=zY)w4o#fyO2t6iK1|cWP zn6kR2S*Z)~0G@s6nCkccmGcAjP$Xdm-uvd+*>#EMk{V314L`%2&Ur9Q9>^r?DGKb` z){@+r1J3H_bqOTJSAB~C@1u|S|MoT_1G6gxftFPG9~Ld|TqNnNq)*@*6MWaT5IcPA;c+T&TG5>Zxvd=J%M^`$Kw4v5@#T z9jp!>Pt;%p^?^2;wr`lIbP1h1*_ix0U9WMK)i5#}hwsG!`PJOa=j%SQ2q+|?a7Tve zVsIoF3K9>UI*Wgf=`0}r6YyfDDCEycewgGN`P2JW@Tk%78N-d z07(<9^1= zGfmB(bww{5cJsfLpz_*OTA5CdQcS1!iR%=N>M`iboXsZs$?QLqS&wgFeqF3EV~vlW zSCgD93@tF&>u_;u{fn?4E^yN5-~XVwlcR}`F8oMWIagG(@@%QP{ml6}ELD8vg(e;S z_Ot8jeD^v%fD>!JJ?Bf;7g((&FQjysZQSreKyIr~rPxj9T)v8S4u@rVwzFEYDCLSA zf=NjBvw^y2$gP=+N=)QQl`~RYab|0%KwR2dkH0MLS;AjcXUnXFi)O@mF01)E0|P^3 zkA<*t`&)zBtS?^{v?68J+q)B+&e6a-4XD%i#wQp*Km4t0G_*gc%$2qsv$dFUC=Dlq zn{YEX*pKk4*ROX}d=LudImezW0A3~9cO?o1k5m>PKH`koXSLV{>+CEJSl4dwoa<)K zwB6k1k$~FXc5;M(U6I1eadhom=BT@S`{Z1pb-LH|+KU%QT(=jtb8- z3X1rpC08WQEqLyy=S%bVqGs+QwFd~eSf?i>2#|COv)X~HnM8yA$~!C2B|=f~{1~G? zC^qC+ee8$wT8o$5Su-|~X)Mt`+Cu0>9Zb4f?GEw8`0BT*!K{hF@DVTIaQjeU?N`^P zL!cM$!g?pd69{w*z{50Qy`IiRR7q{VGJwcXy7&V9!a`2GJiDKXlni`?cR=`=cvoR= zTKpy%`wcq>gj;~rvJy``UxD3X@4Xlu z%D#@&VOZeY_U&6}MY03z$j~0$OS|V^aYsAT#pYv@p z-yp{khF(~mnn+5aE(*3E<;`$eftJ+LMJG`YBhvwyqWDxLv)QS*D_ab8If?*ZXD=RL zZxij&P5f5f&1;(805`J2?`Ui}kQgQG<-B#3fu@P>)G z23w3Av4#ya#M#y{&%h7hbCP9O9*Zq8yYE92MyvQosftw5N>ru(dUUf>Os?HFC|8UNYgV;HA$cZ{S9I?xfsI-+>DLq%b=-7Ra!l>b+gM+yB$e13|Zo~^pkE3^iCw_hDL zM#WwOzF*P$cMdr0@5q6a@2cG? Jk~ewrzW^!*=i&eW diff --git a/packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png b/packages/alphatab/test-data/visual-tests/staff-display-config/override-l2-score-clef-hide.png index 7c16a1ef6893f042bd2e98ccfdccaef7109919de..2567af499542465c0096065e5113ec0f3201ffc9 100644 GIT binary patch literal 7784 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 J7T>T6{SP8O-T?pr literal 7665 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 diff --git a/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts index f95e9e128..23352deb4 100644 --- a/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts +++ b/packages/alphatab/test/rendering/StaffDisplayResolver.test.ts @@ -14,8 +14,8 @@ class StaffDisplayContextStub implements IStaffDisplayContext { public modelStaff: Staff; public cascadePriority: number; public systemIndex: number; - public cascadeSiblings: IStaffDisplayContext[] = []; + private _siblings: IStaffDisplayContext[] = []; private _cachedPrimary: boolean = false; private _cachedPrimaryComputed: boolean = false; @@ -25,6 +25,14 @@ class StaffDisplayContextStub implements IStaffDisplayContext { this.systemIndex = systemIndex; } + public get cascadeSiblings(): Iterable { + return this._siblings; + } + + public setSiblings(siblings: IStaffDisplayContext[]): void { + this._siblings = siblings; + } + public get isCascadePrimary(): boolean { if (!this._cachedPrimaryComputed) { this._cachedPrimary = StaffDisplayResolver.computeCascadePrimary(this); @@ -68,7 +76,7 @@ class StaffDisplayContextFixtures { sharedSiblings.push(staff); } for (const staff of staves) { - staff.cascadeSiblings = sharedSiblings; + staff.setSiblings(sharedSiblings); } return staves[focusIndex]; }