diff --git a/packages/alphatab/src/importer/Gp3To5Importer.ts b/packages/alphatab/src/importer/Gp3To5Importer.ts index a42714081..dbe90ebf8 100644 --- a/packages/alphatab/src/importer/Gp3To5Importer.ts +++ b/packages/alphatab/src/importer/Gp3To5Importer.ts @@ -37,17 +37,17 @@ import { TripletFeel } from '@coderline/alphatab/model/TripletFeel'; import { VibratoType } from '@coderline/alphatab/model/VibratoType'; import { Voice } from '@coderline/alphatab/model/Voice'; -import { Logger } from '@coderline/alphatab/Logger'; -import { ModelUtils } from '@coderline/alphatab/model/ModelUtils'; import type { IWriteable } from '@coderline/alphatab/io/IWriteable'; -import { FadeType } from '@coderline/alphatab/model/FadeType'; -import { Rasgueado } from '@coderline/alphatab/model/Rasgueado'; +import { Logger } from '@coderline/alphatab/Logger'; +import { AccidentalType } from '@coderline/alphatab/model/AccidentalType'; import { Direction } from '@coderline/alphatab/model/Direction'; -import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; +import { FadeType } from '@coderline/alphatab/model/FadeType'; +import { ModelUtils } from '@coderline/alphatab/model/ModelUtils'; import { Ottavia } from '@coderline/alphatab/model/Ottavia'; -import { WahPedal } from '@coderline/alphatab/model/WahPedal'; -import { AccidentalType } from '@coderline/alphatab/model/AccidentalType'; +import { Rasgueado } from '@coderline/alphatab/model/Rasgueado'; import { TremoloPickingEffect } from '@coderline/alphatab/model/TremoloPickingEffect'; +import { WahPedal } from '@coderline/alphatab/model/WahPedal'; +import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; /** * @internal @@ -434,6 +434,11 @@ export class Gp3To5Importer extends ScoreImporter { } } + /** + * Guitar Pro 3-6 changes to a bass clef if any string tuning is below B2; + */ + private static readonly _bassClefTuningThreshold = ModelUtils.parseTuning('B2')!.realValue; + public readTrack(): void { const newTrack: Track = new Track(); newTrack.ensureStaveCount(1); @@ -527,10 +532,10 @@ export class Gp3To5Importer extends ScoreImporter { // `12` for all tunings which have bass clefs const clefMode = IOHelper.readInt32LE(this.data); - if (clefMode === 12) { - this._clefsPerTrack.set(index, Clef.F4); + if (clefMode === 12 || tuning[tuning.length - 1] < Gp3To5Importer._bassClefTuningThreshold) { + this._clefsPerTrack.set(newTrack.index, Clef.F4); } else { - this._clefsPerTrack.set(index, Clef.G2); + this._clefsPerTrack.set(newTrack.index, Clef.G2); } // Unknown, no UI setting seem to affect this @@ -570,10 +575,10 @@ export class Gp3To5Importer extends ScoreImporter { GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding); } } else { - if (GeneralMidi.isBass(newTrack.playbackInfo.program)) { - this._clefsPerTrack.set(index, Clef.F4); + if (tuning[tuning.length - 1] < Gp3To5Importer._bassClefTuningThreshold) { + this._clefsPerTrack.set(newTrack.index, Clef.F4); } else { - this._clefsPerTrack.set(index, Clef.G2); + this._clefsPerTrack.set(newTrack.index, Clef.G2); } } } diff --git a/packages/alphatab/test-data/guitarpro5/bass-tuning.gp5 b/packages/alphatab/test-data/guitarpro5/bass-tuning.gp5 new file mode 100644 index 000000000..700c1c137 Binary files /dev/null and b/packages/alphatab/test-data/guitarpro5/bass-tuning.gp5 differ diff --git a/packages/alphatab/test/importer/Gp5Importer.test.ts b/packages/alphatab/test/importer/Gp5Importer.test.ts index af12fee60..e56f85ebb 100644 --- a/packages/alphatab/test/importer/Gp5Importer.test.ts +++ b/packages/alphatab/test/importer/Gp5Importer.test.ts @@ -8,6 +8,7 @@ import { TextAlign } from '@coderline/alphatab/platform/ICanvas'; import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection'; import { GpImporterTestHelper } from 'test/importer/GpImporterTestHelper'; import { expect } from 'chai'; +import { Clef } from '@coderline/alphatab/model/Clef'; describe('Gp5ImporterTest', () => { it('score-info', async () => { @@ -544,4 +545,12 @@ describe('Gp5ImporterTest', () => { expect(score.tracks[1].playbackInfo.program).to.equal(25); expect(score.tracks[1].playbackInfo.bank).to.equal(77); }); + + it('tuning-bass-clef', async () => { + const score = (await GpImporterTestHelper.prepareImporterWithFile('guitarpro5/bass-tuning.gp5')).readScore(); + expect(score.tracks[0].staves[0].bars[0].clef).to.equal(Clef.F4); + expect(score.tracks[1].staves[0].bars[0].clef).to.equal(Clef.F4); + expect(score.tracks[2].staves[0].bars[0].clef).to.equal(Clef.F4); + expect(score.tracks[3].staves[0].bars[0].clef).to.equal(Clef.F4); + }); }); diff --git a/packages/transpiler/src/AstPrinterBase.ts b/packages/transpiler/src/AstPrinterBase.ts index b095b2128..34764cd0e 100644 --- a/packages/transpiler/src/AstPrinterBase.ts +++ b/packages/transpiler/src/AstPrinterBase.ts @@ -152,10 +152,41 @@ export default abstract class AstPrinterBase { d.isStatic && !d.setAccessor && cs.isPrimitiveTypeNode(d.type) && - !!d.initializer && + this._isConstantExpression(d.initializer) && (!d.getAccessor || !d.getAccessor.body) ); } + private _isConstantExpression(expression: cs.Expression | undefined): boolean { + if (expression === undefined) { + return false; + } + + switch (expression.nodeType) { + case cs.SyntaxKind.PrefixUnaryExpression: + return this._isConstantExpression((expression as cs.PrefixUnaryExpression).operand); + case cs.SyntaxKind.PostfixUnaryExpression: + return this._isConstantExpression((expression as cs.PostfixUnaryExpression).operand); + case cs.SyntaxKind.NullLiteral: + case cs.SyntaxKind.TrueLiteral: + case cs.SyntaxKind.FalseLiteral: + case cs.SyntaxKind.StringLiteral: + case cs.SyntaxKind.NumericLiteral: + case cs.SyntaxKind.DefaultExpression: + return true; + case cs.SyntaxKind.BinaryExpression: + return ( + this._isConstantExpression((expression as cs.BinaryExpression).left) && + this._isConstantExpression((expression as cs.BinaryExpression).right) + ); + case cs.SyntaxKind.ParenthesizedExpression: + return this._isConstantExpression((expression as cs.ParenthesizedExpression).expression); + // case cs.SyntaxKind.MemberAccessExpression: + // case cs.SyntaxKind.Identifier: + // maybe detect enums and other constant declarations? + } + + return false; + } protected writePropertyAsField(d: cs.PropertyDeclaration) { if (