@coderline/alphatab 1.7.0-alpha.1515 → 1.7.0-alpha.1517

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/alphaTab.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * alphaTab v1.7.0-alpha.1515 (develop, build 1515)
2
+ * alphaTab v1.7.0-alpha.1517 (develop, build 1517)
3
3
  *
4
4
  * Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
@@ -203,9 +203,9 @@
203
203
  print(`build date: ${VersionInfo.date}`);
204
204
  }
205
205
  }
206
- VersionInfo.version = '1.7.0-alpha.1515';
207
- VersionInfo.date = '2025-08-17T02:26:19.392Z';
208
- VersionInfo.commit = '23aaf549a408c97811ff01054a773c3fa2344bf0';
206
+ VersionInfo.version = '1.7.0-alpha.1517';
207
+ VersionInfo.date = '2025-08-19T02:07:05.813Z';
208
+ VersionInfo.commit = 'a8c49344e3fef6f72a38d5493a2e58223e2c777b';
209
209
 
210
210
  /**
211
211
  * This public class provides names for all general midi instruments.
@@ -3393,6 +3393,49 @@
3393
3393
  MusicFontSymbol[MusicFontSymbol["FingeringCLower"] = 60700] = "FingeringCLower";
3394
3394
  })(MusicFontSymbol || (MusicFontSymbol = {}));
3395
3395
 
3396
+ /**
3397
+ * Defines all possible accidentals for notes.
3398
+ */
3399
+ var AccidentalType;
3400
+ (function (AccidentalType) {
3401
+ /**
3402
+ * No accidental
3403
+ */
3404
+ AccidentalType[AccidentalType["None"] = 0] = "None";
3405
+ /**
3406
+ * Naturalize
3407
+ */
3408
+ AccidentalType[AccidentalType["Natural"] = 1] = "Natural";
3409
+ /**
3410
+ * Sharp
3411
+ */
3412
+ AccidentalType[AccidentalType["Sharp"] = 2] = "Sharp";
3413
+ /**
3414
+ * Flat
3415
+ */
3416
+ AccidentalType[AccidentalType["Flat"] = 3] = "Flat";
3417
+ /**
3418
+ * Natural for smear bends
3419
+ */
3420
+ AccidentalType[AccidentalType["NaturalQuarterNoteUp"] = 4] = "NaturalQuarterNoteUp";
3421
+ /**
3422
+ * Sharp for smear bends
3423
+ */
3424
+ AccidentalType[AccidentalType["SharpQuarterNoteUp"] = 5] = "SharpQuarterNoteUp";
3425
+ /**
3426
+ * Flat for smear bends
3427
+ */
3428
+ AccidentalType[AccidentalType["FlatQuarterNoteUp"] = 6] = "FlatQuarterNoteUp";
3429
+ /**
3430
+ * Double Sharp, indicated by an 'x'
3431
+ */
3432
+ AccidentalType[AccidentalType["DoubleSharp"] = 7] = "DoubleSharp";
3433
+ /**
3434
+ * Double Flat, indicated by 'bb'
3435
+ */
3436
+ AccidentalType[AccidentalType["DoubleFlat"] = 8] = "DoubleFlat";
3437
+ })(AccidentalType || (AccidentalType = {}));
3438
+
3396
3439
  class TuningParseResult {
3397
3440
  constructor() {
3398
3441
  this.note = null;
@@ -3898,6 +3941,150 @@
3898
3941
  }
3899
3942
  return ModelUtils.allMusicFontSymbols;
3900
3943
  }
3944
+ /**
3945
+ * @internal
3946
+ */
3947
+ static flooredDivision(a, b) {
3948
+ return a - b * Math.floor(a / b);
3949
+ }
3950
+ // NOTE: haven't figured out yet what exact formula is applied when transposing key signatures
3951
+ // this table is simply created by checking the Guitar Pro behavior,
3952
+ // The table is organized as [<transpose>][<key signature>] to match the table above
3953
+ // it's also easier to read as we list every key signature per row, transposed by the same value
3954
+ // this gives typically just a shifted list according to the transpose (with some special treatments)
3955
+ /**
3956
+ * Converts the key transpose table to actual key signatures.
3957
+ * @param texts An array where every item indicates the number of accidentals and which accidental
3958
+ * placed for the key signature.
3959
+ *
3960
+ * e.g. 3# is 3-sharps -> KeySignature.A
3961
+ */
3962
+ static translateKeyTransposeTable(texts) {
3963
+ const keySignatures = [];
3964
+ for (const transpose of texts) {
3965
+ const transposeValues = [];
3966
+ keySignatures.push(transposeValues);
3967
+ for (const keySignatureText of transpose) {
3968
+ const keySignature =
3969
+ // digit
3970
+ (Number.parseInt(keySignatureText.charAt(0)) *
3971
+ // b -> negative, # positive
3972
+ (keySignatureText.charAt(1) === 'b' ? -1 : 1));
3973
+ transposeValues.push(keySignature);
3974
+ }
3975
+ }
3976
+ return keySignatures;
3977
+ }
3978
+ /**
3979
+ * Transposes the given key signature.
3980
+ * @internal
3981
+ * @param keySignature The key signature to transpose
3982
+ * @param transpose The number of semitones to transpose (+/- 0-11)
3983
+ * @returns
3984
+ */
3985
+ static transposeKey(keySignature, transpose) {
3986
+ if (transpose === 0) {
3987
+ return keySignature;
3988
+ }
3989
+ if (transpose < 0) {
3990
+ const lookup = ModelUtils.keyTransposeTable[-transpose];
3991
+ const keySignatureIndex = lookup.indexOf(keySignature);
3992
+ if (keySignatureIndex === -1) {
3993
+ return keySignature;
3994
+ }
3995
+ return (keySignatureIndex - 7);
3996
+ }
3997
+ else {
3998
+ return ModelUtils.keyTransposeTable[transpose][keySignature + 7];
3999
+ }
4000
+ }
4001
+ /**
4002
+ * @internal
4003
+ */
4004
+ static computeAccidental(keySignature, accidentalMode, noteValue, quarterBend, currentAccidental = null) {
4005
+ const ks = keySignature;
4006
+ const ksi = ks + 7;
4007
+ const index = noteValue % 12;
4008
+ const accidentalForKeySignature = ksi < 7 ? AccidentalType.Flat : AccidentalType.Sharp;
4009
+ const hasKeySignatureAccidentalSetForNote = ModelUtils.KeySignatureLookup[ksi][index];
4010
+ const hasNoteAccidentalWithinOctave = ModelUtils.AccidentalNotes[index];
4011
+ // the general logic is like this:
4012
+ // - we check if the key signature has an accidental defined
4013
+ // - we calculate which accidental a note needs according to its index in the octave
4014
+ // - if the accidental is already placed at this line, nothing needs to be done, otherwise we place it
4015
+ // - if there should not be an accidental, but there is one in the key signature, we clear it.
4016
+ // the exceptions are:
4017
+ // - for quarter bends we just place the corresponding accidental
4018
+ // - the accidental mode can enforce the accidentals for the note
4019
+ let accidentalToSet = AccidentalType.None;
4020
+ if (quarterBend) {
4021
+ accidentalToSet = hasNoteAccidentalWithinOctave ? accidentalForKeySignature : AccidentalType.Natural;
4022
+ switch (accidentalToSet) {
4023
+ case AccidentalType.Natural:
4024
+ accidentalToSet = AccidentalType.NaturalQuarterNoteUp;
4025
+ break;
4026
+ case AccidentalType.Sharp:
4027
+ accidentalToSet = AccidentalType.SharpQuarterNoteUp;
4028
+ break;
4029
+ case AccidentalType.Flat:
4030
+ accidentalToSet = AccidentalType.FlatQuarterNoteUp;
4031
+ break;
4032
+ }
4033
+ }
4034
+ else {
4035
+ // define which accidental should be shown ignoring what might be set on the KS already
4036
+ switch (accidentalMode) {
4037
+ case NoteAccidentalMode.ForceSharp:
4038
+ accidentalToSet = AccidentalType.Sharp;
4039
+ break;
4040
+ case NoteAccidentalMode.ForceDoubleSharp:
4041
+ accidentalToSet = AccidentalType.DoubleSharp;
4042
+ break;
4043
+ case NoteAccidentalMode.ForceFlat:
4044
+ accidentalToSet = AccidentalType.Flat;
4045
+ break;
4046
+ case NoteAccidentalMode.ForceDoubleFlat:
4047
+ accidentalToSet = AccidentalType.DoubleFlat;
4048
+ break;
4049
+ default:
4050
+ // if note has an accidental in the octave, we place a symbol
4051
+ // according to the Key Signature
4052
+ if (hasNoteAccidentalWithinOctave) {
4053
+ accidentalToSet = accidentalForKeySignature;
4054
+ }
4055
+ else if (hasKeySignatureAccidentalSetForNote) {
4056
+ // note does not get an accidental, but KS defines one -> Naturalize
4057
+ accidentalToSet = AccidentalType.Natural;
4058
+ }
4059
+ break;
4060
+ }
4061
+ // do we need an accidental on the note?
4062
+ if (accidentalToSet !== AccidentalType.None) {
4063
+ // if there is no accidental on the line, and the key signature has it set already, we clear it on the note
4064
+ if (currentAccidental != null) {
4065
+ if (currentAccidental === accidentalToSet) {
4066
+ accidentalToSet = AccidentalType.None;
4067
+ }
4068
+ }
4069
+ else if (hasKeySignatureAccidentalSetForNote && accidentalToSet === accidentalForKeySignature) {
4070
+ accidentalToSet = AccidentalType.None;
4071
+ }
4072
+ }
4073
+ else {
4074
+ // if we don't want an accidental, but there is already one applied, we place a naturalize accidental
4075
+ // and clear the registration
4076
+ if (currentAccidental !== null) {
4077
+ if (currentAccidental === AccidentalType.Natural) {
4078
+ accidentalToSet = AccidentalType.None;
4079
+ }
4080
+ else {
4081
+ accidentalToSet = AccidentalType.Natural;
4082
+ }
4083
+ }
4084
+ }
4085
+ }
4086
+ return accidentalToSet;
4087
+ }
3901
4088
  }
3902
4089
  ModelUtils.TuningLetters = new Set([
3903
4090
  0x43 /* C */, 0x44 /* D */, 0x45 /* E */, 0x46 /* F */, 0x47 /* G */, 0x41 /* A */, 0x42 /* B */, 0x63 /* c */,
@@ -3950,6 +4137,66 @@
3950
4137
  // Contrabass
3951
4138
  [43, -12]
3952
4139
  ]);
4140
+ /**
4141
+ * @internal
4142
+ */
4143
+ ModelUtils.keyTransposeTable = ModelUtils.translateKeyTransposeTable([
4144
+ /* Cb Gb Db Ab Eb Bb F C G D A E B F C# */
4145
+ /* C 0 */ ['7b', '6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#'],
4146
+ /* Db 1 */ ['2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#', '4b', '3b', '2b', '1b', '0#'],
4147
+ /* D 2 */ ['3#', '4#', '7b', '6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#'],
4148
+ /* Eb 3 */ ['4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#', '4b', '3b', '2b'],
4149
+ /* E 4 */ ['1#', '2#', '3#', '4#', '7b', '6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#'],
4150
+ /* F 5 */ ['6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#', '4b'],
4151
+ /* Gb 6 */ ['1b', '0#', '1#', '2#', '3#', '4#', '7b', '6#', '7#', '4b', '3b', '2b', '1b', '0#', '1#'],
4152
+ /* G 7 */ ['4#', '7b', '6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#'],
4153
+ /* Ab 8 */ ['3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#', '4b', '3b', '2b', '1b'],
4154
+ /* A 9 */ ['2#', '3#', '4#', '7b', '6b', '5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#'],
4155
+ /* Bb 10 */ ['5b', '4b', '3b', '2b', '1b', '0#', '1#', '2#', '3#', '4#', '5#', '6#', '7#', '4b', '3b'],
4156
+ /* B 11 */ ['0#', '1#', '2#', '3#', '4#', '7b', '6b', '6#', '4b', '3b', '2b', '1b', '0#', '1#', '2#']
4157
+ ]);
4158
+ /**
4159
+ * a lookup list containing an info whether the notes within an octave
4160
+ * need an accidental rendered. the accidental symbol is determined based on the type of key signature.
4161
+ */
4162
+ ModelUtils.KeySignatureLookup = [
4163
+ // Flats (where the value is true, a flat accidental is required for the notes)
4164
+ [true, true, true, true, true, true, true, true, true, true, true, true],
4165
+ [true, true, true, true, true, false, true, true, true, true, true, true],
4166
+ [false, true, true, true, true, false, true, true, true, true, true, true],
4167
+ [false, true, true, true, true, false, false, false, true, true, true, true],
4168
+ [false, false, false, true, true, false, false, false, true, true, true, true],
4169
+ [false, false, false, true, true, false, false, false, false, false, true, true],
4170
+ [false, false, false, false, false, false, false, false, false, false, true, true],
4171
+ // natural
4172
+ [false, false, false, false, false, false, false, false, false, false, false, false],
4173
+ // sharps (where the value is true, a flat accidental is required for the notes)
4174
+ [false, false, false, false, false, true, true, false, false, false, false, false],
4175
+ [true, true, false, false, false, true, true, false, false, false, false, false],
4176
+ [true, true, false, false, false, true, true, true, true, false, false, false],
4177
+ [true, true, true, true, false, true, true, true, true, false, false, false],
4178
+ [true, true, true, true, false, true, true, true, true, true, true, false],
4179
+ [true, true, true, true, true, true, true, true, true, true, true, false],
4180
+ [true, true, true, true, true, true, true, true, true, true, true, true]
4181
+ ];
4182
+ /**
4183
+ * Contains the list of notes within an octave have accidentals set.
4184
+ * @internal
4185
+ */
4186
+ ModelUtils.AccidentalNotes = [
4187
+ false,
4188
+ true,
4189
+ false,
4190
+ true,
4191
+ false,
4192
+ false,
4193
+ true,
4194
+ false,
4195
+ true,
4196
+ false,
4197
+ true,
4198
+ false
4199
+ ];
3953
4200
 
3954
4201
  /**
3955
4202
  * Lists all types of pick strokes.
@@ -7952,7 +8199,7 @@
7952
8199
  static getTextPartsForTuning(tuning, octaveShift = -1) {
7953
8200
  const octave = (tuning / 12) | 0;
7954
8201
  const note = tuning % 12;
7955
- const notes = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
8202
+ const notes = Tuning.noteNames;
7956
8203
  return [notes[note], (octave + octaveShift).toString()];
7957
8204
  }
7958
8205
  /**
@@ -8091,8 +8338,7 @@
8091
8338
  Tuning._fiveStrings = [];
8092
8339
  Tuning._fourStrings = [];
8093
8340
  Tuning._defaultTunings = new Map();
8094
- Tuning.defaultAccidentals = ['', '#', '', '#', '', '', '#', '', '#', '', '#', ''];
8095
- Tuning.defaultSteps = ['C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B'];
8341
+ Tuning.noteNames = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
8096
8342
  Tuning.initialize();
8097
8343
 
8098
8344
  /**
@@ -9018,8 +9264,7 @@
9018
9264
  }
9019
9265
  // unicode handling
9020
9266
  // https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-ecmascript-language-types-string-type
9021
- if (IOHelper.isLeadingSurrogate(previousCodepoint) &&
9022
- IOHelper.isTrailingSurrogate(codepoint)) {
9267
+ if (IOHelper.isLeadingSurrogate(previousCodepoint) && IOHelper.isTrailingSurrogate(codepoint)) {
9023
9268
  codepoint = (previousCodepoint - 0xd800) * 0x400 + (codepoint - 0xdc00) + 0x10000;
9024
9269
  s += String.fromCodePoint(codepoint);
9025
9270
  }
@@ -9454,10 +9699,10 @@
9454
9699
  case 'bass':
9455
9700
  return Clef.F4;
9456
9701
  case 'c3':
9457
- case 'tenor':
9702
+ case 'alto':
9458
9703
  return Clef.C3;
9459
9704
  case 'c4':
9460
- case 'alto':
9705
+ case 'tenor':
9461
9706
  return Clef.C4;
9462
9707
  case 'n':
9463
9708
  case 'neutral':
@@ -9474,6 +9719,8 @@
9474
9719
  */
9475
9720
  parseClefFromInt(i) {
9476
9721
  switch (i) {
9722
+ case 0:
9723
+ return Clef.Neutral;
9477
9724
  case 43:
9478
9725
  return Clef.G2;
9479
9726
  case 65:
@@ -10731,6 +10978,25 @@
10731
10978
  }
10732
10979
  beat.text = this.syData;
10733
10980
  }
10981
+ else if (syData === 'lyrics') {
10982
+ this.sy = this.newSy();
10983
+ let lyricsLine = 0;
10984
+ if (this.sy === AlphaTexSymbols.Number) {
10985
+ lyricsLine = this.syData;
10986
+ this.sy = this.newSy();
10987
+ }
10988
+ if (this.sy !== AlphaTexSymbols.String) {
10989
+ this.error('lyrics', AlphaTexSymbols.String, true);
10990
+ return false;
10991
+ }
10992
+ if (!beat.lyrics) {
10993
+ beat.lyrics = [];
10994
+ }
10995
+ while (beat.lyrics.length <= lyricsLine) {
10996
+ beat.lyrics.push('');
10997
+ }
10998
+ beat.lyrics[lyricsLine] = this.syData;
10999
+ }
10734
11000
  else if (syData === 'dd') {
10735
11001
  beat.dots = 2;
10736
11002
  }
@@ -15763,11 +16029,11 @@
15763
16029
  newNote.fret = -1;
15764
16030
  }
15765
16031
  if (swapAccidentals) {
15766
- const accidental = Tuning.defaultAccidentals[newNote.realValueWithoutHarmonic % 12];
15767
- if (accidental === '#') {
16032
+ const accidental = ModelUtils.computeAccidental(bar.keySignature, NoteAccidentalMode.Default, newNote.realValueWithoutHarmonic, false);
16033
+ if (accidental === AccidentalType.Sharp) {
15768
16034
  newNote.accidentalMode = NoteAccidentalMode.ForceFlat;
15769
16035
  }
15770
- else if (accidental === 'b') {
16036
+ else if (accidental === AccidentalType.Flat) {
15771
16037
  newNote.accidentalMode = NoteAccidentalMode.ForceSharp;
15772
16038
  }
15773
16039
  }
@@ -16667,6 +16933,7 @@
16667
16933
  this._backingTrackPadding = 0;
16668
16934
  this._doubleBars = new Set();
16669
16935
  this._keySignatures = new Map();
16936
+ this._transposeKeySignaturePerTrack = new Map();
16670
16937
  }
16671
16938
  parseXml(xml, settings) {
16672
16939
  this._masterTrackAutomations = new Map();
@@ -16897,7 +17164,8 @@
16897
17164
  assetId = c.innerText;
16898
17165
  break;
16899
17166
  case 'FramePadding':
16900
- this._backingTrackPadding = GpifParser.parseIntSafe(c.innerText, 0) / GpifParser.SampleRate * 1000;
17167
+ this._backingTrackPadding =
17168
+ (GpifParser.parseIntSafe(c.innerText, 0) / GpifParser.SampleRate) * 1000;
16901
17169
  break;
16902
17170
  }
16903
17171
  }
@@ -17133,13 +17401,13 @@
17133
17401
  track.playbackInfo.isMute = state === 'Mute';
17134
17402
  break;
17135
17403
  case 'PartSounding':
17136
- this.parsePartSounding(track, c);
17404
+ this.parsePartSounding(trackId, track, c);
17137
17405
  break;
17138
17406
  case 'Staves':
17139
17407
  this.parseStaves(track, c);
17140
17408
  break;
17141
17409
  case 'Transpose':
17142
- this.parseTranspose(track, c);
17410
+ this.parseTranspose(trackId, track, c);
17143
17411
  break;
17144
17412
  case 'RSE':
17145
17413
  this.parseRSE(track, c);
@@ -17663,7 +17931,7 @@
17663
17931
  }
17664
17932
  }
17665
17933
  }
17666
- parsePartSounding(track, node) {
17934
+ parsePartSounding(trackId, track, node) {
17667
17935
  for (const c of node.childElements()) {
17668
17936
  switch (c.localName) {
17669
17937
  case 'TranspositionPitch':
@@ -17671,10 +17939,14 @@
17671
17939
  staff.displayTranspositionPitch = GpifParser.parseIntSafe(c.innerText, 0);
17672
17940
  }
17673
17941
  break;
17942
+ case 'NominalKey':
17943
+ const transposeIndex = Math.max(0, Tuning.noteNames.indexOf(c.innerText));
17944
+ this._transposeKeySignaturePerTrack.set(trackId, transposeIndex);
17945
+ break;
17674
17946
  }
17675
17947
  }
17676
17948
  }
17677
- parseTranspose(track, node) {
17949
+ parseTranspose(trackId, track, node) {
17678
17950
  let octave = 0;
17679
17951
  let chromatic = 0;
17680
17952
  for (const c of node.childElements()) {
@@ -17687,9 +17959,14 @@
17687
17959
  break;
17688
17960
  }
17689
17961
  }
17962
+ const pitch = octave * 12 + chromatic;
17690
17963
  for (const staff of track.staves) {
17691
- staff.displayTranspositionPitch = octave * 12 + chromatic;
17964
+ staff.displayTranspositionPitch = pitch;
17692
17965
  }
17966
+ // the chromatic transpose also causes an alternative key signature to be adjusted
17967
+ // In Guitar Pro this feature is hidden in the track properties (more -> Transposition tonality -> 'C played as:' ).
17968
+ const transposeIndex = ModelUtils.flooredDivision(pitch, 12);
17969
+ this._transposeKeySignaturePerTrack.set(trackId, transposeIndex);
17693
17970
  }
17694
17971
  parseRSE(track, node) {
17695
17972
  for (const c of node.childElements()) {
@@ -18653,6 +18930,7 @@
18653
18930
  // GP6 had percussion as element+variation
18654
18931
  let element = -1;
18655
18932
  let variation = -1;
18933
+ let hasTransposedPitch = false;
18656
18934
  for (const c of node.childElements()) {
18657
18935
  switch (c.localName) {
18658
18936
  case 'Property':
@@ -18733,7 +19011,15 @@
18733
19011
  note.tone = GpifParser.parseIntSafe(c.findChildElement('Step')?.innerText, 0);
18734
19012
  break;
18735
19013
  case 'ConcertPitch':
19014
+ if (!hasTransposedPitch) {
19015
+ this.parseConcertPitch(c, note);
19016
+ }
19017
+ break;
19018
+ case 'TransposedPitch':
19019
+ // clear potential value from concert pitch
19020
+ note.accidentalMode = NoteAccidentalMode.Default;
18736
19021
  this.parseConcertPitch(c, note);
19022
+ hasTransposedPitch = true;
18737
19023
  break;
18738
19024
  case 'Bended':
18739
19025
  isBended = true;
@@ -18947,20 +19233,29 @@
18947
19233
  lastMasterBar.isDoubleBar = false;
18948
19234
  }
18949
19235
  // add tracks to score
19236
+ const trackIndexToTrackId = [];
18950
19237
  for (const trackId of this._tracksMapping) {
18951
19238
  if (!trackId) {
18952
19239
  continue;
18953
19240
  }
18954
19241
  const track = this._tracksById.get(trackId);
18955
19242
  this.score.addTrack(track);
19243
+ trackIndexToTrackId.push(trackId);
18956
19244
  }
18957
19245
  // process all masterbars
18958
19246
  let keySignature;
18959
19247
  for (const barIds of this._barsOfMasterBar) {
18960
19248
  // add all bars of masterbar vertically to all tracks
18961
19249
  let staffIndex = 0;
19250
+ let trackIndex = 0;
18962
19251
  keySignature = [KeySignature.C, KeySignatureType.Major];
18963
- for (let barIndex = 0, trackIndex = 0; barIndex < barIds.length && trackIndex < this.score.tracks.length; barIndex++) {
19252
+ if (this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[0])) {
19253
+ keySignature = [
19254
+ ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[0])),
19255
+ keySignature[1]
19256
+ ];
19257
+ }
19258
+ for (let barIndex = 0; barIndex < barIds.length && trackIndex < this.score.tracks.length; barIndex++) {
18964
19259
  const barId = barIds[barIndex];
18965
19260
  if (barId !== GpifParser.InvalidId) {
18966
19261
  const bar = this._barsById.get(barId);
@@ -18970,6 +19265,12 @@
18970
19265
  const masterBarIndex = staff.bars.length - 1;
18971
19266
  if (this._keySignatures.has(masterBarIndex)) {
18972
19267
  keySignature = this._keySignatures.get(masterBarIndex);
19268
+ if (this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[trackIndex])) {
19269
+ keySignature = [
19270
+ ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[trackIndex])),
19271
+ keySignature[1]
19272
+ ];
19273
+ }
18973
19274
  }
18974
19275
  bar.keySignature = keySignature[0];
18975
19276
  bar.keySignatureType = keySignature[1];
@@ -19036,11 +19337,17 @@
19036
19337
  if (staffIndex === track.staves.length - 1) {
19037
19338
  trackIndex++;
19038
19339
  staffIndex = 0;
19039
- keySignature = [KeySignature.C, KeySignatureType.Major];
19040
19340
  }
19041
19341
  else {
19042
19342
  staffIndex++;
19043
- keySignature = [KeySignature.C, KeySignatureType.Major];
19343
+ }
19344
+ keySignature = [KeySignature.C, KeySignatureType.Major];
19345
+ if (trackIndex < trackIndexToTrackId.length &&
19346
+ this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[trackIndex])) {
19347
+ keySignature = [
19348
+ ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[trackIndex])),
19349
+ keySignature[1]
19350
+ ];
19044
19351
  }
19045
19352
  }
19046
19353
  else {
@@ -19128,7 +19435,7 @@
19128
19435
  */
19129
19436
  GpifParser.BendPointValueFactor = 1 / 25.0;
19130
19437
  // tests have shown that Guitar Pro seem to always work with 44100hz for the frame offsets,
19131
- // they are NOT using the sample rate of the input file.
19438
+ // they are NOT using the sample rate of the input file.
19132
19439
  // Downsampling a 44100hz ogg to 8000hz and using it in as audio track resulted in the same frame offset when placing sync points.
19133
19440
  GpifParser.SampleRate = 44100;
19134
19441
 
@@ -19823,49 +20130,6 @@
19823
20130
  }
19824
20131
  }
19825
20132
 
19826
- /**
19827
- * Defines all possible accidentals for notes.
19828
- */
19829
- var AccidentalType;
19830
- (function (AccidentalType) {
19831
- /**
19832
- * No accidental
19833
- */
19834
- AccidentalType[AccidentalType["None"] = 0] = "None";
19835
- /**
19836
- * Naturalize
19837
- */
19838
- AccidentalType[AccidentalType["Natural"] = 1] = "Natural";
19839
- /**
19840
- * Sharp
19841
- */
19842
- AccidentalType[AccidentalType["Sharp"] = 2] = "Sharp";
19843
- /**
19844
- * Flat
19845
- */
19846
- AccidentalType[AccidentalType["Flat"] = 3] = "Flat";
19847
- /**
19848
- * Natural for smear bends
19849
- */
19850
- AccidentalType[AccidentalType["NaturalQuarterNoteUp"] = 4] = "NaturalQuarterNoteUp";
19851
- /**
19852
- * Sharp for smear bends
19853
- */
19854
- AccidentalType[AccidentalType["SharpQuarterNoteUp"] = 5] = "SharpQuarterNoteUp";
19855
- /**
19856
- * Flat for smear bends
19857
- */
19858
- AccidentalType[AccidentalType["FlatQuarterNoteUp"] = 6] = "FlatQuarterNoteUp";
19859
- /**
19860
- * Double Sharp, indicated by an 'x'
19861
- */
19862
- AccidentalType[AccidentalType["DoubleSharp"] = 7] = "DoubleSharp";
19863
- /**
19864
- * Double Flat, indicated by 'bb'
19865
- */
19866
- AccidentalType[AccidentalType["DoubleFlat"] = 8] = "DoubleFlat";
19867
- })(AccidentalType || (AccidentalType = {}));
19868
-
19869
20133
  class BeatLines {
19870
20134
  constructor() {
19871
20135
  this.maxLine = -1e3;
@@ -19968,90 +20232,6 @@
19968
20232
  }
19969
20233
  return line;
19970
20234
  }
19971
- static computeAccidental(keySignature, accidentalMode, noteValue, quarterBend, currentAccidental = null) {
19972
- const ks = keySignature;
19973
- const ksi = ks + 7;
19974
- const index = noteValue % 12;
19975
- const accidentalForKeySignature = ksi < 7 ? AccidentalType.Flat : AccidentalType.Sharp;
19976
- const hasKeySignatureAccidentalSetForNote = AccidentalHelper.KeySignatureLookup[ksi][index];
19977
- const hasNoteAccidentalWithinOctave = AccidentalHelper.AccidentalNotes[index];
19978
- // the general logic is like this:
19979
- // - we check if the key signature has an accidental defined
19980
- // - we calculate which accidental a note needs according to its index in the octave
19981
- // - if the accidental is already placed at this line, nothing needs to be done, otherwise we place it
19982
- // - if there should not be an accidental, but there is one in the key signature, we clear it.
19983
- // the exceptions are:
19984
- // - for quarter bends we just place the corresponding accidental
19985
- // - the accidental mode can enforce the accidentals for the note
19986
- let accidentalToSet = AccidentalType.None;
19987
- if (quarterBend) {
19988
- accidentalToSet = hasNoteAccidentalWithinOctave ? accidentalForKeySignature : AccidentalType.Natural;
19989
- switch (accidentalToSet) {
19990
- case AccidentalType.Natural:
19991
- accidentalToSet = AccidentalType.NaturalQuarterNoteUp;
19992
- break;
19993
- case AccidentalType.Sharp:
19994
- accidentalToSet = AccidentalType.SharpQuarterNoteUp;
19995
- break;
19996
- case AccidentalType.Flat:
19997
- accidentalToSet = AccidentalType.FlatQuarterNoteUp;
19998
- break;
19999
- }
20000
- }
20001
- else {
20002
- // define which accidental should be shown ignoring what might be set on the KS already
20003
- switch (accidentalMode) {
20004
- case NoteAccidentalMode.ForceSharp:
20005
- accidentalToSet = AccidentalType.Sharp;
20006
- break;
20007
- case NoteAccidentalMode.ForceDoubleSharp:
20008
- accidentalToSet = AccidentalType.DoubleSharp;
20009
- break;
20010
- case NoteAccidentalMode.ForceFlat:
20011
- accidentalToSet = AccidentalType.Flat;
20012
- break;
20013
- case NoteAccidentalMode.ForceDoubleFlat:
20014
- accidentalToSet = AccidentalType.DoubleFlat;
20015
- break;
20016
- default:
20017
- // if note has an accidental in the octave, we place a symbol
20018
- // according to the Key Signature
20019
- if (hasNoteAccidentalWithinOctave) {
20020
- accidentalToSet = accidentalForKeySignature;
20021
- }
20022
- else if (hasKeySignatureAccidentalSetForNote) {
20023
- // note does not get an accidental, but KS defines one -> Naturalize
20024
- accidentalToSet = AccidentalType.Natural;
20025
- }
20026
- break;
20027
- }
20028
- // do we need an accidental on the note?
20029
- if (accidentalToSet !== AccidentalType.None) {
20030
- // if there is no accidental on the line, and the key signature has it set already, we clear it on the note
20031
- if (currentAccidental != null) {
20032
- if (currentAccidental === accidentalToSet) {
20033
- accidentalToSet = AccidentalType.None;
20034
- }
20035
- }
20036
- else if (hasKeySignatureAccidentalSetForNote && accidentalToSet === accidentalForKeySignature) {
20037
- accidentalToSet = AccidentalType.None;
20038
- }
20039
- }
20040
- else {
20041
- // if we don't want an accidental, but there is already one applied, we place a naturalize accidental
20042
- // and clear the registration
20043
- if (currentAccidental !== null) {
20044
- if (currentAccidental === AccidentalType.Natural) {
20045
- accidentalToSet = AccidentalType.None;
20046
- }
20047
- else {
20048
- accidentalToSet = AccidentalType.Natural;
20049
- }
20050
- }
20051
- }
20052
- }
20053
- return accidentalToSet;
20054
- }
20055
20235
  getAccidental(noteValue, quarterBend, relatedBeat, isHelperNote, note = null) {
20056
20236
  let steps = 0;
20057
20237
  let accidentalToSet = AccidentalType.None;
@@ -20065,7 +20245,7 @@
20065
20245
  const currentAccidental = this._registeredAccidentals.has(steps)
20066
20246
  ? this._registeredAccidentals.get(steps)
20067
20247
  : null;
20068
- accidentalToSet = AccidentalHelper.computeAccidental(this._bar.keySignature, accidentalMode, noteValue, quarterBend, currentAccidental);
20248
+ accidentalToSet = ModelUtils.computeAccidental(this._bar.keySignature, accidentalMode, noteValue, quarterBend, currentAccidental);
20069
20249
  let skipAccidental = false;
20070
20250
  switch (accidentalToSet) {
20071
20251
  case AccidentalType.NaturalQuarterNoteUp:
@@ -20179,48 +20359,6 @@
20179
20359
  return 0;
20180
20360
  }
20181
20361
  }
20182
- /**
20183
- * a lookup list containing an info whether the notes within an octave
20184
- * need an accidental rendered. the accidental symbol is determined based on the type of key signature.
20185
- */
20186
- AccidentalHelper.KeySignatureLookup = [
20187
- // Flats (where the value is true, a flat accidental is required for the notes)
20188
- [true, true, true, true, true, true, true, true, true, true, true, true],
20189
- [true, true, true, true, true, false, true, true, true, true, true, true],
20190
- [false, true, true, true, true, false, true, true, true, true, true, true],
20191
- [false, true, true, true, true, false, false, false, true, true, true, true],
20192
- [false, false, false, true, true, false, false, false, true, true, true, true],
20193
- [false, false, false, true, true, false, false, false, false, false, true, true],
20194
- [false, false, false, false, false, false, false, false, false, false, true, true],
20195
- // natural
20196
- [false, false, false, false, false, false, false, false, false, false, false, false],
20197
- // sharps (where the value is true, a flat accidental is required for the notes)
20198
- [false, false, false, false, false, true, true, false, false, false, false, false],
20199
- [true, true, false, false, false, true, true, false, false, false, false, false],
20200
- [true, true, false, false, false, true, true, true, true, false, false, false],
20201
- [true, true, true, true, false, true, true, true, true, false, false, false],
20202
- [true, true, true, true, false, true, true, true, true, true, true, false],
20203
- [true, true, true, true, true, true, true, true, true, true, true, false],
20204
- [true, true, true, true, true, true, true, true, true, true, true, true]
20205
- ];
20206
- /**
20207
- * Contains the list of notes within an octave have accidentals set.
20208
- */
20209
- // prettier-ignore
20210
- AccidentalHelper.AccidentalNotes = [
20211
- false,
20212
- true,
20213
- false,
20214
- true,
20215
- false,
20216
- false,
20217
- true,
20218
- false,
20219
- true,
20220
- false,
20221
- true,
20222
- false
20223
- ];
20224
20362
  /**
20225
20363
  * We always have 7 steps per octave.
20226
20364
  * (by a step the offsets inbetween score lines is meant,
@@ -59059,7 +59197,7 @@
59059
59197
  // - when the standard notation naturalizes the accidental from the key signature, the numbered notation has the reversed accidental
59060
59198
  const accidentalMode = note ? note.accidentalMode : NoteAccidentalMode.Default;
59061
59199
  const noteValue = AccidentalHelper.getNoteValue(note);
59062
- let accidentalToSet = AccidentalHelper.computeAccidental(this.renderer.bar.keySignature, accidentalMode, noteValue, note.hasQuarterToneOffset);
59200
+ let accidentalToSet = ModelUtils.computeAccidental(this.renderer.bar.keySignature, accidentalMode, noteValue, note.hasQuarterToneOffset);
59063
59201
  if (accidentalToSet === AccidentalType.Natural) {
59064
59202
  const ks = this.renderer.bar.keySignature;
59065
59203
  const ksi = ks + 7;
@@ -59218,7 +59356,7 @@
59218
59356
  ? AccidentalHelper.FlatNoteSteps
59219
59357
  : AccidentalHelper.SharpNoteSteps;
59220
59358
  let steps = stepList[index] + 1;
59221
- const hasAccidental = AccidentalHelper.AccidentalNotes[index];
59359
+ const hasAccidental = ModelUtils.AccidentalNotes[index];
59222
59360
  if (hasAccidental &&
59223
59361
  !this.container.preNotes.isNaturalizeAccidental) {
59224
59362
  if (ksi < 7) {
@@ -66431,6 +66569,30 @@
66431
66569
  if (stylesheet.useSystemSignSeparator) {
66432
66570
  writer.writeMeta('useSystemSignSeparator');
66433
66571
  }
66572
+ if (stylesheet.multiTrackMultiBarRest) {
66573
+ writer.writeMeta('multiBarRest');
66574
+ }
66575
+ if (stylesheet.singleTrackTrackNamePolicy !==
66576
+ AlphaTexExporter.DefaultScore.stylesheet.singleTrackTrackNamePolicy) {
66577
+ writer.writeMeta('singleTrackTrackNamePolicy', TrackNamePolicy[stylesheet.singleTrackTrackNamePolicy]);
66578
+ }
66579
+ if (stylesheet.multiTrackTrackNamePolicy !== AlphaTexExporter.DefaultScore.stylesheet.multiTrackTrackNamePolicy) {
66580
+ writer.writeMeta('multiTrackTrackNamePolicy', TrackNamePolicy[stylesheet.multiTrackTrackNamePolicy]);
66581
+ }
66582
+ if (stylesheet.firstSystemTrackNameMode !== AlphaTexExporter.DefaultScore.stylesheet.firstSystemTrackNameMode) {
66583
+ writer.writeMeta('firstSystemTrackNameMode', TrackNameMode[stylesheet.firstSystemTrackNameMode]);
66584
+ }
66585
+ if (stylesheet.otherSystemsTrackNameMode !== AlphaTexExporter.DefaultScore.stylesheet.otherSystemsTrackNameMode) {
66586
+ writer.writeMeta('otherSystemsTrackNameMode', TrackNameMode[stylesheet.otherSystemsTrackNameMode]);
66587
+ }
66588
+ if (stylesheet.firstSystemTrackNameOrientation !==
66589
+ AlphaTexExporter.DefaultScore.stylesheet.firstSystemTrackNameOrientation) {
66590
+ writer.writeMeta('firstSystemTrackNameOrientation', TrackNameOrientation[stylesheet.firstSystemTrackNameOrientation]);
66591
+ }
66592
+ if (stylesheet.otherSystemsTrackNameOrientation !==
66593
+ AlphaTexExporter.DefaultScore.stylesheet.otherSystemsTrackNameOrientation) {
66594
+ writer.writeMeta('otherSystemsTrackNameOrientation', TrackNameOrientation[stylesheet.otherSystemsTrackNameOrientation]);
66595
+ }
66434
66596
  }
66435
66597
  writeTrackTo(writer, track) {
66436
66598
  writer.write('\\track ');
@@ -66600,6 +66762,7 @@
66600
66762
  if (staff.displayTranspositionPitch !== defaultTransposition) {
66601
66763
  writer.writeMeta('displaytranspose', `${-staff.displayTranspositionPitch}`);
66602
66764
  }
66765
+ writer.writeMeta('accidentals', 'auto');
66603
66766
  if (staff.chords != null) {
66604
66767
  for (const [_, chord] of staff.chords) {
66605
66768
  this.writeChordTo(writer, chord);
@@ -66967,6 +67130,18 @@
66967
67130
  writer.writeGroupItem('txt ');
66968
67131
  writer.writeString(beat.text);
66969
67132
  }
67133
+ if (beat.lyrics != null && beat.lyrics.length > 0) {
67134
+ if (beat.lyrics.length > 1) {
67135
+ for (let i = 0; i < beat.lyrics.length; i++) {
67136
+ writer.writeGroupItem(`lyrics ${i} `);
67137
+ writer.writeString(beat.lyrics[i]);
67138
+ }
67139
+ }
67140
+ else {
67141
+ writer.writeGroupItem('lyrics ');
67142
+ writer.writeString(beat.lyrics[0]);
67143
+ }
67144
+ }
66970
67145
  switch (beat.graceType) {
66971
67146
  case GraceType.OnBeat:
66972
67147
  writer.writeGroupItem('gr ob');
@@ -67601,7 +67776,7 @@
67601
67776
  this.writePitch(properties, 'ConcertPitch', 'C', '-1', '');
67602
67777
  }
67603
67778
  else {
67604
- this.writePitchForValue(properties, 'TransposedPitch', note.displayValueWithoutBend, note.accidentalMode);
67779
+ this.writePitchForValue(properties, 'TransposedPitch', note.displayValueWithoutBend, note.accidentalMode, note.beat.voice.bar.keySignature);
67605
67780
  }
67606
67781
  }
67607
67782
  writeConcertPitch(properties, note) {
@@ -67609,10 +67784,10 @@
67609
67784
  this.writePitch(properties, 'ConcertPitch', 'C', '-1', '');
67610
67785
  }
67611
67786
  else {
67612
- this.writePitchForValue(properties, 'ConcertPitch', note.realValueWithoutHarmonic, note.accidentalMode);
67787
+ this.writePitchForValue(properties, 'ConcertPitch', note.realValueWithoutHarmonic, note.accidentalMode, note.beat.voice.bar.keySignature);
67613
67788
  }
67614
67789
  }
67615
- writePitchForValue(properties, propertyName, value, accidentalMode) {
67790
+ writePitchForValue(properties, propertyName, value, accidentalMode, keySignature) {
67616
67791
  let index = 0;
67617
67792
  let octave = 0;
67618
67793
  let step = '';
@@ -67620,8 +67795,25 @@
67620
67795
  const updateParts = () => {
67621
67796
  index = value % 12;
67622
67797
  octave = (value / 12) | 0;
67623
- step = Tuning.defaultSteps[index];
67624
- accidental = Tuning.defaultAccidentals[index];
67798
+ step = GpifWriter.defaultSteps[index];
67799
+ switch (ModelUtils.computeAccidental(keySignature, NoteAccidentalMode.Default, value, false)) {
67800
+ case AccidentalType.None:
67801
+ case AccidentalType.Natural:
67802
+ accidental = '';
67803
+ break;
67804
+ case AccidentalType.Sharp:
67805
+ accidental = '#';
67806
+ break;
67807
+ case AccidentalType.Flat:
67808
+ accidental = 'b';
67809
+ break;
67810
+ case AccidentalType.DoubleSharp:
67811
+ accidental = 'x';
67812
+ break;
67813
+ case AccidentalType.DoubleFlat:
67814
+ accidental = 'bb';
67815
+ break;
67816
+ }
67625
67817
  };
67626
67818
  updateParts();
67627
67819
  switch (accidentalMode) {
@@ -68096,10 +68288,12 @@
68096
68288
  const value = syncPointAutomation.addElement('Value');
68097
68289
  value.addElement('BarIndex').innerText = mb.index.toString();
68098
68290
  value.addElement('BarOccurrence').innerText = syncPoint.syncPointValue.barOccurence.toString();
68099
- value.addElement('ModifiedTempo').innerText = modifiedTempoLookup.value.get(syncPoint).syncBpm.toString();
68291
+ value.addElement('ModifiedTempo').innerText = modifiedTempoLookup.value
68292
+ .get(syncPoint)
68293
+ .syncBpm.toString();
68100
68294
  value.addElement('OriginalTempo').innerText = score.tempo.toString();
68101
- let frameOffset = (((syncPoint.syncPointValue.millisecondOffset - millisecondPadding) / 1000) *
68102
- GpifWriter.SampleRate);
68295
+ let frameOffset = ((syncPoint.syncPointValue.millisecondOffset - millisecondPadding) / 1000) *
68296
+ GpifWriter.SampleRate;
68103
68297
  frameOffset = Math.floor(frameOffset + 0.5);
68104
68298
  value.addElement('FrameOffset').innerText = frameOffset.toString();
68105
68299
  }
@@ -68581,8 +68775,13 @@
68581
68775
  writeMasterBarNode(parent, masterBar) {
68582
68776
  const masterBarNode = parent.addElement('MasterBar');
68583
68777
  const key = masterBarNode.addElement('Key');
68584
- key.addElement('AccidentalCount').innerText = masterBar.keySignature.toString();
68585
- key.addElement('Mode').innerText = KeySignatureType[masterBar.keySignatureType];
68778
+ let keySignature = masterBar.score.tracks[0].staves[0].bars[masterBar.index].keySignature;
68779
+ const keySignatureType = masterBar.score.tracks[0].staves[0].bars[masterBar.index].keySignatureType;
68780
+ // reverse transpose
68781
+ const transposeIndex = ModelUtils.flooredDivision(masterBar.score.tracks[0].staves[0].displayTranspositionPitch, 12);
68782
+ keySignature = ModelUtils.transposeKey(keySignature, -transposeIndex);
68783
+ key.addElement('AccidentalCount').innerText = keySignature.toString();
68784
+ key.addElement('Mode').innerText = KeySignatureType[keySignatureType];
68586
68785
  key.addElement('Sharps').innerText = 'Sharps';
68587
68786
  masterBarNode.addElement('Time').innerText =
68588
68787
  `${masterBar.timeSignatureNumerator}/${masterBar.timeSignatureDenominator}`;
@@ -68892,6 +69091,7 @@
68892
69091
  [127, new GpifMidiProgramInfo(GpifIconIds.Fx, 'Timpani')]
68893
69092
  ]);
68894
69093
  GpifWriter.DrumKitProgramInfo = new GpifMidiProgramInfo(GpifIconIds.PercussionKit, 'Drums', 'drumKit');
69094
+ GpifWriter.defaultSteps = ['C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B'];
68895
69095
 
68896
69096
  /**
68897
69097
  * CRC-32 with reversed data and unreversed output
@@ -70770,6 +70970,7 @@
70770
70970
  SustainPedalMarker,
70771
70971
  get SustainPedalMarkerType () { return SustainPedalMarkerType; },
70772
70972
  SyncPointData,
70973
+ get TechniqueSymbolPlacement () { return TechniqueSymbolPlacement; },
70773
70974
  Track,
70774
70975
  get TrackNameMode () { return TrackNameMode; },
70775
70976
  get TrackNameOrientation () { return TrackNameOrientation; },