@coderline/alphatab 1.6.0-alpha.1430 → 1.6.0-alpha.1435

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.6.0-alpha.1430 (develop, build 1430)
2
+ * alphaTab v1.6.0-alpha.1435 (develop, build 1435)
3
3
  *
4
4
  * Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
@@ -1012,6 +1012,26 @@
1012
1012
  get isEmpty() {
1013
1013
  return this._isEmpty;
1014
1014
  }
1015
+ /**
1016
+ * Whether this bar has any changes applied which are not related to the voices in it.
1017
+ * (e.g. new key signatures)
1018
+ */
1019
+ get hasChanges() {
1020
+ if (this.index === 0) {
1021
+ return true;
1022
+ }
1023
+ const hasChangesToPrevious = this.keySignature !== this.previousBar.keySignature ||
1024
+ this.keySignatureType !== this.previousBar.keySignatureType ||
1025
+ this.clef !== this.previousBar.clef ||
1026
+ this.clefOttava !== this.previousBar.clefOttava;
1027
+ if (hasChangesToPrevious) {
1028
+ return true;
1029
+ }
1030
+ return (this.simileMark !== SimileMark.None ||
1031
+ this.sustainPedals.length > 0 ||
1032
+ this.barLineLeft !== BarLineStyle.Automatic ||
1033
+ this.barLineRight !== BarLineStyle.Automatic);
1034
+ }
1015
1035
  /**
1016
1036
  * Whether this bar is empty or has only rests.
1017
1037
  */
@@ -2625,6 +2645,33 @@
2625
2645
  */
2626
2646
  this.directions = null;
2627
2647
  }
2648
+ /**
2649
+ * Whether the masterbar is has any changes applied to it (e.g. tempo changes, time signature changes etc)
2650
+ * The first bar is always considered changed due to initial setup of values. It does not consider
2651
+ * elements like whether the tempo really changes to the previous bar.
2652
+ */
2653
+ get hasChanges() {
2654
+ if (this.index === 0) {
2655
+ return false;
2656
+ }
2657
+ const hasChangesToPrevious = this.timeSignatureCommon !== this.previousMasterBar.timeSignatureCommon ||
2658
+ this.timeSignatureNumerator !== this.previousMasterBar.timeSignatureNumerator ||
2659
+ this.timeSignatureDenominator !== this.previousMasterBar.timeSignatureDenominator ||
2660
+ this.tripletFeel !== this.previousMasterBar.tripletFeel;
2661
+ if (hasChangesToPrevious) {
2662
+ return true;
2663
+ }
2664
+ return (this.alternateEndings !== 0 ||
2665
+ this.isRepeatStart ||
2666
+ this.isRepeatEnd ||
2667
+ this.isFreeTime ||
2668
+ this.isSectionStart ||
2669
+ this.tempoAutomations.length > 0 ||
2670
+ this.syncPoints && this.syncPoints.length > 0 ||
2671
+ (this.fermata !== null && this.fermata.size > 0) ||
2672
+ (this.directions !== null && this.directions.size > 0) ||
2673
+ this.isAnacrusis);
2674
+ }
2628
2675
  /**
2629
2676
  * The key signature used on all bars.
2630
2677
  * @deprecated Use key signatures on bar level
@@ -3566,6 +3613,43 @@
3566
3613
  }
3567
3614
  }
3568
3615
  }
3616
+ /**
3617
+ * Trims any empty bars at the end of the song.
3618
+ * @param score
3619
+ */
3620
+ static trimEmptyBarsAtEnd(score) {
3621
+ while (score.masterBars.length > 1) {
3622
+ const barIndex = score.masterBars.length - 1;
3623
+ const masterBar = score.masterBars[barIndex];
3624
+ if (masterBar.hasChanges) {
3625
+ return;
3626
+ }
3627
+ for (const track of score.tracks) {
3628
+ for (const staff of track.staves) {
3629
+ if (barIndex < staff.bars.length) {
3630
+ const bar = staff.bars[barIndex];
3631
+ if (!bar.isEmpty || bar.hasChanges) {
3632
+ // found a non-empty bar, stop whole cleanup
3633
+ return;
3634
+ }
3635
+ }
3636
+ }
3637
+ }
3638
+ // if we reach here, all found bars are empty, remove the bar
3639
+ for (const track of score.tracks) {
3640
+ for (const staff of track.staves) {
3641
+ if (barIndex < staff.bars.length) {
3642
+ const bar = staff.bars[barIndex];
3643
+ staff.bars.pop();
3644
+ // unlink
3645
+ bar.previousBar.nextBar = null;
3646
+ }
3647
+ }
3648
+ }
3649
+ score.masterBars.pop();
3650
+ masterBar.previousMasterBar.nextMasterBar = null;
3651
+ }
3652
+ }
3569
3653
  }
3570
3654
  ModelUtils.TuningLetters = new Set([
3571
3655
  0x43 /* C */, 0x44 /* D */, 0x45 /* E */, 0x46 /* F */, 0x47 /* G */, 0x41 /* A */, 0x42 /* B */, 0x63 /* c */,
@@ -8683,6 +8767,7 @@
8683
8767
  this._slurs = new Map();
8684
8768
  this._articulationValueToIndex = new Map();
8685
8769
  this._accidentalMode = AlphaTexAccidentalMode.Explicit;
8770
+ this._syncPoints = [];
8686
8771
  this.logErrors = false;
8687
8772
  }
8688
8773
  get name() {
@@ -8723,10 +8808,16 @@
8723
8808
  if (!anyMetaRead && !anyBarsRead) {
8724
8809
  throw new UnsupportedFormatError('No alphaTex data found');
8725
8810
  }
8811
+ if (this._sy === AlphaTexSymbols.Dot) {
8812
+ this._sy = this.newSy();
8813
+ this.syncPoints();
8814
+ }
8726
8815
  }
8727
8816
  ModelUtils.consolidate(this._score);
8728
8817
  this._score.finish(this.settings);
8818
+ ModelUtils.trimEmptyBarsAtEnd(this._score);
8729
8819
  this._score.rebuildRepeatGroups();
8820
+ this._score.applyFlatSyncPoints(this._syncPoints);
8730
8821
  for (const [track, lyrics] of this._lyrics) {
8731
8822
  this._score.tracks[track].applyLyrics(lyrics);
8732
8823
  }
@@ -8743,6 +8834,47 @@
8743
8834
  throw e;
8744
8835
  }
8745
8836
  }
8837
+ syncPoints() {
8838
+ while (this._sy !== AlphaTexSymbols.Eof) {
8839
+ this.syncPoint();
8840
+ }
8841
+ }
8842
+ syncPoint() {
8843
+ // \sync BarIndex Occurence MillisecondOffset
8844
+ // \sync BarIndex Occurence MillisecondOffset RatioPosition
8845
+ if (this._sy !== AlphaTexSymbols.MetaCommand || this._syData !== 'sync') {
8846
+ this.error('syncPoint', AlphaTexSymbols.MetaCommand, true);
8847
+ }
8848
+ this._sy = this.newSy();
8849
+ if (this._sy !== AlphaTexSymbols.Number) {
8850
+ this.error('syncPointBarIndex', AlphaTexSymbols.Number, true);
8851
+ }
8852
+ const barIndex = this._syData;
8853
+ this._sy = this.newSy();
8854
+ if (this._sy !== AlphaTexSymbols.Number) {
8855
+ this.error('syncPointBarOccurence', AlphaTexSymbols.Number, true);
8856
+ }
8857
+ const barOccurence = this._syData;
8858
+ this._sy = this.newSy();
8859
+ if (this._sy !== AlphaTexSymbols.Number) {
8860
+ this.error('syncPointBarMillis', AlphaTexSymbols.Number, true);
8861
+ }
8862
+ const millisecondOffset = this._syData;
8863
+ this._allowFloat = true;
8864
+ this._sy = this.newSy();
8865
+ this._allowFloat = false;
8866
+ let barPosition = 0;
8867
+ if (this._sy === AlphaTexSymbols.Number) {
8868
+ barPosition = this._syData;
8869
+ this._sy = this.newSy();
8870
+ }
8871
+ this._syncPoints.push({
8872
+ barIndex,
8873
+ barOccurence,
8874
+ barPosition,
8875
+ millisecondOffset
8876
+ });
8877
+ }
8746
8878
  error(nonterm, expected, wrongSymbol = true) {
8747
8879
  let receivedSymbol;
8748
8880
  let showSyData = false;
@@ -33108,7 +33240,7 @@
33108
33240
  addSamples(samples) {
33109
33241
  this._worker.postMessage({
33110
33242
  cmd: 'alphaSynth.output.addSamples',
33111
- samples: samples
33243
+ samples: Environment.prepareForPostMessage(samples)
33112
33244
  });
33113
33245
  }
33114
33246
  play() {
@@ -33304,7 +33436,7 @@
33304
33436
  onSoundFontLoadFailed(e) {
33305
33437
  this._main.postMessage({
33306
33438
  cmd: 'alphaSynth.soundFontLoadFailed',
33307
- error: this.serializeException(e)
33439
+ error: this.serializeException(Environment.prepareForPostMessage(e))
33308
33440
  });
33309
33441
  }
33310
33442
  serializeException(e) {
@@ -33335,7 +33467,7 @@
33335
33467
  onMidiLoadFailed(e) {
33336
33468
  this._main.postMessage({
33337
33469
  cmd: 'alphaSynth.midiLoaded',
33338
- error: this.serializeException(e)
33470
+ error: this.serializeException(Environment.prepareForPostMessage(e))
33339
33471
  });
33340
33472
  }
33341
33473
  onReadyForPlayback() {
@@ -42460,6 +42592,18 @@
42460
42592
  * available importers
42461
42593
  */
42462
42594
  class ScoreLoader {
42595
+ /**
42596
+ * Loads the given alphaTex string.
42597
+ * @param tex The alphaTex string.
42598
+ * @param settings The settings to use for parsing.
42599
+ * @returns The parsed {@see Score}.
42600
+ */
42601
+ static loadAlphaTex(tex, settings) {
42602
+ const parser = new AlphaTexImporter();
42603
+ parser.logErrors = true;
42604
+ parser.initFromString(tex, settings ?? new Settings());
42605
+ return parser.readScore();
42606
+ }
42463
42607
  /**
42464
42608
  * Loads a score asynchronously from the given datasource
42465
42609
  * @param path the source path to load the binary file from
@@ -43310,7 +43454,7 @@
43310
43454
  this._midiEventsPlayedFilter = value;
43311
43455
  this._synth.postMessage({
43312
43456
  cmd: 'alphaSynth.setMidiEventsPlayedFilter',
43313
- value: value
43457
+ value: Environment.prepareForPostMessage(value)
43314
43458
  });
43315
43459
  }
43316
43460
  get playbackSpeed() {
@@ -43375,7 +43519,7 @@
43375
43519
  this._playbackRange = value;
43376
43520
  this._synth.postMessage({
43377
43521
  cmd: 'alphaSynth.setPlaybackRange',
43378
- value: value
43522
+ value: Environment.prepareForPostMessage(value)
43379
43523
  });
43380
43524
  }
43381
43525
  constructor(player, settings) {
@@ -43469,13 +43613,13 @@
43469
43613
  playOneTimeMidiFile(midi) {
43470
43614
  this._synth.postMessage({
43471
43615
  cmd: 'alphaSynth.playOneTimeMidiFile',
43472
- midi: JsonConverter.midiFileToJsObject(midi)
43616
+ midi: JsonConverter.midiFileToJsObject(Environment.prepareForPostMessage(midi))
43473
43617
  });
43474
43618
  }
43475
43619
  loadSoundFont(data, append) {
43476
43620
  this._synth.postMessage({
43477
43621
  cmd: 'alphaSynth.loadSoundFontBytes',
43478
- data: data,
43622
+ data: Environment.prepareForPostMessage(data),
43479
43623
  append: append
43480
43624
  });
43481
43625
  }
@@ -43487,13 +43631,13 @@
43487
43631
  loadMidiFile(midi) {
43488
43632
  this._synth.postMessage({
43489
43633
  cmd: 'alphaSynth.loadMidi',
43490
- midi: JsonConverter.midiFileToJsObject(midi)
43634
+ midi: JsonConverter.midiFileToJsObject(Environment.prepareForPostMessage(midi))
43491
43635
  });
43492
43636
  }
43493
43637
  applyTranspositionPitches(transpositionPitches) {
43494
43638
  this._synth.postMessage({
43495
43639
  cmd: 'alphaSynth.applyTranspositionPitches',
43496
- transpositionPitches: JSON.stringify(Array.from(transpositionPitches.entries()))
43640
+ transpositionPitches: JSON.stringify(Array.from(Environment.prepareForPostMessage(transpositionPitches).entries()))
43497
43641
  });
43498
43642
  }
43499
43643
  setChannelTranspositionPitch(channel, semitones) {
@@ -43665,7 +43809,7 @@
43665
43809
  });
43666
43810
  }
43667
43811
  serializeSettingsForWorker(settings) {
43668
- const jsObject = JsonConverter.settingsToJsObject(settings);
43812
+ const jsObject = JsonConverter.settingsToJsObject(Environment.prepareForPostMessage(settings));
43669
43813
  // cut out player settings, they are only needed on UI thread side
43670
43814
  jsObject.delete('player');
43671
43815
  return jsObject;
@@ -43723,11 +43867,11 @@
43723
43867
  }
43724
43868
  }
43725
43869
  renderScore(score, trackIndexes) {
43726
- const jsObject = score == null ? null : JsonConverter.scoreToJsObject(score);
43870
+ const jsObject = score == null ? null : JsonConverter.scoreToJsObject(Environment.prepareForPostMessage(score));
43727
43871
  this._worker.postMessage({
43728
43872
  cmd: 'alphaTab.renderScore',
43729
43873
  score: jsObject,
43730
- trackIndexes: trackIndexes,
43874
+ trackIndexes: Environment.prepareForPostMessage(trackIndexes),
43731
43875
  fontSizes: FontSizes.FontSizeLookupTables
43732
43876
  });
43733
43877
  }
@@ -43918,7 +44062,7 @@
43918
44062
  addSamples(f) {
43919
44063
  this._worklet?.port.postMessage({
43920
44064
  cmd: AlphaSynthWorkerSynthOutput.CmdOutputAddSamples,
43921
- samples: f
44065
+ samples: Environment.prepareForPostMessage(f)
43922
44066
  });
43923
44067
  }
43924
44068
  resetSamples() {
@@ -61138,9 +61282,9 @@
61138
61282
  print(`build date: ${VersionInfo.date}`);
61139
61283
  }
61140
61284
  }
61141
- VersionInfo.version = '1.6.0-alpha.1430';
61142
- VersionInfo.date = '2025-05-29T22:21:21.689Z';
61143
- VersionInfo.commit = '98a4c2bec8d71f2645008118d3b77fb40973e7fe';
61285
+ VersionInfo.version = '1.6.0-alpha.1435';
61286
+ VersionInfo.date = '2025-06-03T02:15:37.318Z';
61287
+ VersionInfo.commit = 'abb74c7352231d1fc3619761642d7c5a07309917';
61144
61288
 
61145
61289
  /**
61146
61290
  * A factory for custom layout engines.
@@ -61685,6 +61829,29 @@
61685
61829
  print(`Screen Size: ${window.screen.width}x${window.screen.height}`);
61686
61830
  }
61687
61831
  }
61832
+ /**
61833
+ * Prepares the given object to be sent to workers. Web Frameworks like Vue might
61834
+ * create proxy objects for all objects used. This code handles the necessary unwrapping.
61835
+ * @internal
61836
+ * @target web
61837
+ */
61838
+ static prepareForPostMessage(object) {
61839
+ if (!object) {
61840
+ return object;
61841
+ }
61842
+ // Vue toRaw:
61843
+ // https://github.com/vuejs/core/blob/e7381761cc7971c0d40ae0a0a72687a500fd8db3/packages/reactivity/src/reactive.ts#L378-L381
61844
+ if (typeof object === 'object') {
61845
+ const unwrapped = object.__v_raw;
61846
+ if (unwrapped) {
61847
+ return Environment.prepareForPostMessage(unwrapped);
61848
+ }
61849
+ }
61850
+ // Solidjs unwrap: the symbol required to access the raw object is unfortunately hidden and we cannot unwrap it without importing
61851
+ // import { unwrap } from "solid-js/store"
61852
+ // alternative for users is to replace this method during runtime.
61853
+ return object;
61854
+ }
61688
61855
  }
61689
61856
  Environment.StaffIdBeforeSlashAlways = 'before-slash-always';
61690
61857
  Environment.StaffIdBeforeScoreAlways = 'before-score-always';
@@ -61956,6 +62123,7 @@
61956
62123
 
61957
62124
  const _barrel$7 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
61958
62125
  __proto__: null,
62126
+ AlphaTexImporter,
61959
62127
  ScoreImporter,
61960
62128
  ScoreLoader,
61961
62129
  UnsupportedFormatError