@coderline/alphatab 1.8.0-alpha.1670 → 1.8.0-alpha.1671
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.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +508 -30
- package/dist/alphaTab.d.ts +40 -0
- package/dist/alphaTab.js +508 -30
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +1 -1
package/dist/alphaTab.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.0-alpha.
|
|
2
|
+
* alphaTab v1.8.0-alpha.1671 (develop, build 1671)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2026, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
* @internal
|
|
210
210
|
*/
|
|
211
211
|
class VersionInfo {
|
|
212
|
-
static version = '1.8.0-alpha.
|
|
213
|
-
static date = '2026-01-
|
|
214
|
-
static commit = '
|
|
212
|
+
static version = '1.8.0-alpha.1671';
|
|
213
|
+
static date = '2026-01-10T02:20:48.787Z';
|
|
214
|
+
static commit = '1edf83d58fe31a924adb1980bc4a529aed07dad4';
|
|
215
215
|
static print(print) {
|
|
216
216
|
print(`alphaTab ${VersionInfo.version}`);
|
|
217
217
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -2202,6 +2202,12 @@
|
|
|
2202
2202
|
* If specified, overrides the value from the stylesheet on score level.
|
|
2203
2203
|
*/
|
|
2204
2204
|
barNumberDisplay;
|
|
2205
|
+
/**
|
|
2206
|
+
* The shortest duration contained across beats in this bar.
|
|
2207
|
+
* @internal
|
|
2208
|
+
* @json_ignore
|
|
2209
|
+
*/
|
|
2210
|
+
shortestDuration = Duration.DoubleWhole;
|
|
2205
2211
|
/**
|
|
2206
2212
|
* The bar line to draw on the left side of the bar with an "automatic" type resolved to the actual one.
|
|
2207
2213
|
* @param isFirstOfSystem Whether the bar is the first one in the system.
|
|
@@ -2273,12 +2279,16 @@
|
|
|
2273
2279
|
this._filledVoices.add(0);
|
|
2274
2280
|
this._isEmpty = true;
|
|
2275
2281
|
this._isRestOnly = true;
|
|
2282
|
+
this.shortestDuration = Duration.DoubleWhole;
|
|
2276
2283
|
for (let i = 0, j = this.voices.length; i < j; i++) {
|
|
2277
2284
|
const voice = this.voices[i];
|
|
2278
2285
|
voice.finish(settings, sharedDataBag);
|
|
2279
2286
|
if (!voice.isEmpty) {
|
|
2280
2287
|
this._isEmpty = false;
|
|
2281
2288
|
this._filledVoices.add(i);
|
|
2289
|
+
if (voice.shortestDuration > this.shortestDuration) {
|
|
2290
|
+
this.shortestDuration = voice.shortestDuration;
|
|
2291
|
+
}
|
|
2282
2292
|
}
|
|
2283
2293
|
if (!voice.isRestOnly) {
|
|
2284
2294
|
this._isRestOnly = false;
|
|
@@ -2375,6 +2385,116 @@
|
|
|
2375
2385
|
TripletFeel[TripletFeel["Scottish8th"] = 6] = "Scottish8th";
|
|
2376
2386
|
})(TripletFeel || (TripletFeel = {}));
|
|
2377
2387
|
|
|
2388
|
+
/**
|
|
2389
|
+
* Defines the custom beaming rules which define how beats are beamed together or split apart
|
|
2390
|
+
* during the automatic beaming when displayed.
|
|
2391
|
+
* @json
|
|
2392
|
+
* @json_strict
|
|
2393
|
+
* @public
|
|
2394
|
+
*
|
|
2395
|
+
* @remarks
|
|
2396
|
+
* The beaming logic works like this:
|
|
2397
|
+
*
|
|
2398
|
+
* The time axis of the bar is sliced into even chunks. The chunk-size is defined by the respective group definition.
|
|
2399
|
+
* Within these chunks groups can then be placed spanning 1 or more chunks.
|
|
2400
|
+
*
|
|
2401
|
+
* If beats start within the same "group" they are beamed together.
|
|
2402
|
+
*/
|
|
2403
|
+
class BeamingRules {
|
|
2404
|
+
_singleGroupKey;
|
|
2405
|
+
/**
|
|
2406
|
+
* The the group for a given "longest duration" within the bar.
|
|
2407
|
+
* @remarks
|
|
2408
|
+
* The map key is the duration to which the bar will be sliced into.
|
|
2409
|
+
* The map value defines the "groups" placed within the sliced.
|
|
2410
|
+
*/
|
|
2411
|
+
groups = new Map();
|
|
2412
|
+
/**
|
|
2413
|
+
* @internal
|
|
2414
|
+
* @json_ignore
|
|
2415
|
+
*/
|
|
2416
|
+
uniqueId = '';
|
|
2417
|
+
/**
|
|
2418
|
+
* @internal
|
|
2419
|
+
* @json_ignore
|
|
2420
|
+
*/
|
|
2421
|
+
timeSignatureNumerator = 0;
|
|
2422
|
+
/**
|
|
2423
|
+
* @internal
|
|
2424
|
+
* @json_ignore
|
|
2425
|
+
*/
|
|
2426
|
+
timeSignatureDenominator = 0;
|
|
2427
|
+
/**
|
|
2428
|
+
* @internal
|
|
2429
|
+
*/
|
|
2430
|
+
static createSimple(timeSignatureNumerator, timeSignatureDenominator, duration, groups) {
|
|
2431
|
+
const r = new BeamingRules();
|
|
2432
|
+
r.timeSignatureNumerator = timeSignatureNumerator;
|
|
2433
|
+
r.timeSignatureDenominator = timeSignatureDenominator;
|
|
2434
|
+
r.groups.set(duration, groups);
|
|
2435
|
+
r.finish();
|
|
2436
|
+
return r;
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* @internal
|
|
2440
|
+
*/
|
|
2441
|
+
findRule(shortestDuration) {
|
|
2442
|
+
// fast path: one rule -> take it
|
|
2443
|
+
const singleGroupKey = this._singleGroupKey;
|
|
2444
|
+
if (singleGroupKey) {
|
|
2445
|
+
return [singleGroupKey, this.groups.get(singleGroupKey)];
|
|
2446
|
+
}
|
|
2447
|
+
if (shortestDuration < Duration.Quarter) {
|
|
2448
|
+
return [shortestDuration, []];
|
|
2449
|
+
}
|
|
2450
|
+
// first search shorter
|
|
2451
|
+
let durationValue = shortestDuration;
|
|
2452
|
+
do {
|
|
2453
|
+
const duration = durationValue;
|
|
2454
|
+
if (this.groups.has(duration)) {
|
|
2455
|
+
return [duration, this.groups.get(duration)];
|
|
2456
|
+
}
|
|
2457
|
+
durationValue = durationValue * 2;
|
|
2458
|
+
} while (durationValue <= Duration.TwoHundredFiftySixth);
|
|
2459
|
+
// then longer
|
|
2460
|
+
durationValue = shortestDuration / 2;
|
|
2461
|
+
do {
|
|
2462
|
+
const duration = durationValue;
|
|
2463
|
+
if (this.groups.has(duration)) {
|
|
2464
|
+
return [duration, this.groups.get(duration)];
|
|
2465
|
+
}
|
|
2466
|
+
durationValue = durationValue / 2;
|
|
2467
|
+
} while (durationValue > Duration.Half);
|
|
2468
|
+
return [shortestDuration, []];
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* @internal
|
|
2472
|
+
*/
|
|
2473
|
+
finish() {
|
|
2474
|
+
let uniqueId = `${this.timeSignatureNumerator}_${this.timeSignatureDenominator}`;
|
|
2475
|
+
for (const [k, v] of this.groups) {
|
|
2476
|
+
uniqueId += `__${k}`;
|
|
2477
|
+
// trim of 0s at the end of the group
|
|
2478
|
+
let lastZero = v.length;
|
|
2479
|
+
for (let i = v.length - 1; i >= 0; i--) {
|
|
2480
|
+
if (v[i] === 0) {
|
|
2481
|
+
lastZero = i;
|
|
2482
|
+
}
|
|
2483
|
+
else {
|
|
2484
|
+
break;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
if (lastZero < v.length) {
|
|
2488
|
+
v.splice(lastZero, v.length - lastZero);
|
|
2489
|
+
}
|
|
2490
|
+
uniqueId += `_${v.join('_')}`;
|
|
2491
|
+
if (this.groups.size === 1) {
|
|
2492
|
+
this._singleGroupKey = k;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
this.uniqueId = uniqueId;
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2378
2498
|
/**
|
|
2379
2499
|
* The MasterBar stores information about a bar which affects
|
|
2380
2500
|
* all tracks.
|
|
@@ -2492,6 +2612,16 @@
|
|
|
2492
2612
|
* Gets or sets whether this is bar has a common time signature.
|
|
2493
2613
|
*/
|
|
2494
2614
|
timeSignatureCommon = false;
|
|
2615
|
+
/**
|
|
2616
|
+
* Defines the custom beaming rules which should be applied to this bar and all bars following.
|
|
2617
|
+
*/
|
|
2618
|
+
beamingRules;
|
|
2619
|
+
/**
|
|
2620
|
+
* The actual (custom) beaming rules to use for this bar if any were specified.
|
|
2621
|
+
* @json_ignore
|
|
2622
|
+
* @internal
|
|
2623
|
+
*/
|
|
2624
|
+
actualBeamingRules;
|
|
2495
2625
|
/**
|
|
2496
2626
|
* Gets or sets whether the bar indicates a free time playing.
|
|
2497
2627
|
*/
|
|
@@ -2624,6 +2754,32 @@
|
|
|
2624
2754
|
}
|
|
2625
2755
|
this.syncPoints.push(syncPoint);
|
|
2626
2756
|
}
|
|
2757
|
+
finish(sharedDataBag) {
|
|
2758
|
+
let beamingRules = this.beamingRules;
|
|
2759
|
+
if (beamingRules) {
|
|
2760
|
+
beamingRules.timeSignatureNumerator = this.timeSignatureNumerator;
|
|
2761
|
+
beamingRules.timeSignatureDenominator = this.timeSignatureDenominator;
|
|
2762
|
+
beamingRules.finish();
|
|
2763
|
+
}
|
|
2764
|
+
if (this.index > 0) {
|
|
2765
|
+
this.start = this.previousMasterBar.start + this.previousMasterBar.calculateDuration();
|
|
2766
|
+
// clear out equal rules to reduce memory consumption.
|
|
2767
|
+
const previousRules = sharedDataBag.has('beamingRules')
|
|
2768
|
+
? sharedDataBag.get('beamingRules')
|
|
2769
|
+
: undefined;
|
|
2770
|
+
if (previousRules && previousRules.uniqueId === beamingRules?.uniqueId) {
|
|
2771
|
+
this.beamingRules = undefined;
|
|
2772
|
+
beamingRules = previousRules;
|
|
2773
|
+
}
|
|
2774
|
+
else if (!beamingRules) {
|
|
2775
|
+
beamingRules = previousRules;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
this.actualBeamingRules = beamingRules;
|
|
2779
|
+
if (this.beamingRules) {
|
|
2780
|
+
sharedDataBag.set('beamingRules', beamingRules);
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2627
2783
|
}
|
|
2628
2784
|
|
|
2629
2785
|
/**
|
|
@@ -2974,6 +3130,12 @@
|
|
|
2974
3130
|
get isRestOnly() {
|
|
2975
3131
|
return this._isRestOnly;
|
|
2976
3132
|
}
|
|
3133
|
+
/**
|
|
3134
|
+
* The shortest duration contained across beats in this bar.
|
|
3135
|
+
* @internal
|
|
3136
|
+
* @json_ignore
|
|
3137
|
+
*/
|
|
3138
|
+
shortestDuration = Duration.DoubleWhole;
|
|
2977
3139
|
insertBeat(after, newBeat) {
|
|
2978
3140
|
newBeat.nextBeat = after.nextBeat;
|
|
2979
3141
|
if (newBeat.nextBeat) {
|
|
@@ -3067,6 +3229,7 @@
|
|
|
3067
3229
|
}
|
|
3068
3230
|
let currentDisplayTick = 0;
|
|
3069
3231
|
let currentPlaybackTick = 0;
|
|
3232
|
+
this.shortestDuration = Duration.DoubleWhole;
|
|
3070
3233
|
for (let i = 0; i < this.beats.length; i++) {
|
|
3071
3234
|
const beat = this.beats[i];
|
|
3072
3235
|
beat.index = i;
|
|
@@ -3075,6 +3238,9 @@
|
|
|
3075
3238
|
// we need to first steal the duration from the right beat
|
|
3076
3239
|
// and place the grace beats correctly
|
|
3077
3240
|
if (beat.graceType === GraceType.None) {
|
|
3241
|
+
if (beat.duration > this.shortestDuration) {
|
|
3242
|
+
this.shortestDuration = beat.duration;
|
|
3243
|
+
}
|
|
3078
3244
|
if (beat.graceGroup) {
|
|
3079
3245
|
const firstGraceBeat = beat.graceGroup.beats[0];
|
|
3080
3246
|
const lastGraceBeat = beat.graceGroup.beats[beat.graceGroup.beats.length - 1];
|
|
@@ -3535,7 +3701,7 @@
|
|
|
3535
3701
|
bar.previousMasterBar.nextMasterBar = bar;
|
|
3536
3702
|
// NOTE: this will not work on anacrusis. Correct anacrusis durations are only working
|
|
3537
3703
|
// when there are beats with playback positions already computed which requires full finish
|
|
3538
|
-
// chicken-egg problem here. temporarily forcing anacrusis length here to 0,
|
|
3704
|
+
// chicken-egg problem here. temporarily forcing anacrusis length here to 0,
|
|
3539
3705
|
// .finish() will correct these times
|
|
3540
3706
|
bar.start =
|
|
3541
3707
|
bar.previousMasterBar.start +
|
|
@@ -3599,9 +3765,7 @@
|
|
|
3599
3765
|
}
|
|
3600
3766
|
// fixup masterbar starts to handle anacrusis lengths
|
|
3601
3767
|
for (const mb of this.masterBars) {
|
|
3602
|
-
|
|
3603
|
-
mb.start = mb.previousMasterBar.start + mb.previousMasterBar.calculateDuration();
|
|
3604
|
-
}
|
|
3768
|
+
mb.finish(sharedDataBag);
|
|
3605
3769
|
}
|
|
3606
3770
|
}
|
|
3607
3771
|
/**
|
|
@@ -8970,7 +9134,16 @@
|
|
|
8970
9134
|
['spu', [[[[16], 2]]]],
|
|
8971
9135
|
['db', null],
|
|
8972
9136
|
['voicemode', [[[[10, 17], 0, ['staffwise', 'barwise']]]]],
|
|
8973
|
-
['barnumberdisplay', [[[[10, 17], 0, ['allbars', 'firstofsystem', 'hide']]]]]
|
|
9137
|
+
['barnumberdisplay', [[[[10, 17], 0, ['allbars', 'firstofsystem', 'hide']]]]],
|
|
9138
|
+
[
|
|
9139
|
+
'beaming',
|
|
9140
|
+
[
|
|
9141
|
+
[
|
|
9142
|
+
[[16], 0],
|
|
9143
|
+
[[16], 5]
|
|
9144
|
+
]
|
|
9145
|
+
]
|
|
9146
|
+
]
|
|
8974
9147
|
]);
|
|
8975
9148
|
static metaDataProperties = AlphaTex1LanguageDefinitions._metaProps([
|
|
8976
9149
|
[
|
|
@@ -9086,7 +9259,8 @@
|
|
|
9086
9259
|
['spu', null],
|
|
9087
9260
|
['db', null],
|
|
9088
9261
|
['voicemode', null],
|
|
9089
|
-
['barnumberdisplay', null]
|
|
9262
|
+
['barnumberdisplay', null],
|
|
9263
|
+
['beaming', null]
|
|
9090
9264
|
]);
|
|
9091
9265
|
static metaDataSignatures = [
|
|
9092
9266
|
AlphaTex1LanguageDefinitions.scoreMetaDataSignatures,
|
|
@@ -12801,6 +12975,7 @@
|
|
|
12801
12975
|
*/
|
|
12802
12976
|
class AlphaTex1LanguageHandler {
|
|
12803
12977
|
static instance = new AlphaTex1LanguageHandler();
|
|
12978
|
+
static _timeSignatureDenominators = new Set([1, 2, 4, 8, 16, 32, 64, 128]);
|
|
12804
12979
|
applyScoreMetaData(importer, score, metaData) {
|
|
12805
12980
|
const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.scoreMetaDataSignatures], metaData, metaData.tag.tag.text.toLowerCase(), metaData.arguments);
|
|
12806
12981
|
if (result !== undefined) {
|
|
@@ -13222,8 +13397,29 @@
|
|
|
13222
13397
|
case 'ts':
|
|
13223
13398
|
switch (metaData.arguments.arguments[0].nodeType) {
|
|
13224
13399
|
case AlphaTexNodeType.Number:
|
|
13225
|
-
bar.masterBar.timeSignatureNumerator =
|
|
13226
|
-
|
|
13400
|
+
bar.masterBar.timeSignatureNumerator =
|
|
13401
|
+
metaData.arguments.arguments[0].value | 0;
|
|
13402
|
+
if (bar.masterBar.timeSignatureNumerator < 1 || bar.masterBar.timeSignatureNumerator > 32) {
|
|
13403
|
+
importer.addSemanticDiagnostic({
|
|
13404
|
+
code: AlphaTexDiagnosticCode.AT211,
|
|
13405
|
+
message: `Value is out of valid range. Allowed range: 1-32, Actual Value: ${bar.masterBar.timeSignatureNumerator}`,
|
|
13406
|
+
start: metaData.arguments.arguments[0].start,
|
|
13407
|
+
end: metaData.arguments.arguments[0].end,
|
|
13408
|
+
severity: AlphaTexDiagnosticsSeverity.Error
|
|
13409
|
+
});
|
|
13410
|
+
}
|
|
13411
|
+
bar.masterBar.timeSignatureDenominator =
|
|
13412
|
+
metaData.arguments.arguments[1].value | 0;
|
|
13413
|
+
if (!AlphaTex1LanguageHandler._timeSignatureDenominators.has(bar.masterBar.timeSignatureDenominator)) {
|
|
13414
|
+
const valueList = Array.from(AlphaTex1LanguageHandler._timeSignatureDenominators).join(', ');
|
|
13415
|
+
importer.addSemanticDiagnostic({
|
|
13416
|
+
code: AlphaTexDiagnosticCode.AT211,
|
|
13417
|
+
message: `Value is out of valid range. Allowed range: ${valueList}, Actual Value: ${bar.masterBar.timeSignatureDenominator}`,
|
|
13418
|
+
start: metaData.arguments.arguments[0].start,
|
|
13419
|
+
end: metaData.arguments.arguments[0].end,
|
|
13420
|
+
severity: AlphaTexDiagnosticsSeverity.Error
|
|
13421
|
+
});
|
|
13422
|
+
}
|
|
13227
13423
|
break;
|
|
13228
13424
|
case AlphaTexNodeType.Ident:
|
|
13229
13425
|
case AlphaTexNodeType.String:
|
|
@@ -13246,6 +13442,8 @@
|
|
|
13246
13442
|
break;
|
|
13247
13443
|
}
|
|
13248
13444
|
return ApplyNodeResult.Applied;
|
|
13445
|
+
case 'beaming':
|
|
13446
|
+
return this._parseBeamingRule(importer, metaData, bar.masterBar);
|
|
13249
13447
|
case 'ks':
|
|
13250
13448
|
const keySignature = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, 'key signature', AlphaTex1EnumMappings.keySignature);
|
|
13251
13449
|
if (keySignature === undefined) {
|
|
@@ -13446,6 +13644,53 @@
|
|
|
13446
13644
|
return ApplyNodeResult.NotAppliedUnrecognizedMarker;
|
|
13447
13645
|
}
|
|
13448
13646
|
}
|
|
13647
|
+
_parseBeamingRule(importer, metaData, masterBar) {
|
|
13648
|
+
let duration = Duration.Eighth;
|
|
13649
|
+
const groupSizes = [];
|
|
13650
|
+
const durationValue = metaData.arguments.arguments[0].value;
|
|
13651
|
+
switch (durationValue) {
|
|
13652
|
+
case 4:
|
|
13653
|
+
duration = Duration.QuadrupleWhole;
|
|
13654
|
+
break;
|
|
13655
|
+
case 8:
|
|
13656
|
+
duration = Duration.Eighth;
|
|
13657
|
+
break;
|
|
13658
|
+
case 16:
|
|
13659
|
+
duration = Duration.Sixteenth;
|
|
13660
|
+
break;
|
|
13661
|
+
case 32:
|
|
13662
|
+
duration = Duration.ThirtySecond;
|
|
13663
|
+
break;
|
|
13664
|
+
default:
|
|
13665
|
+
importer.addSemanticDiagnostic({
|
|
13666
|
+
code: AlphaTexDiagnosticCode.AT209,
|
|
13667
|
+
message: `Value is out of valid range. Allowed range: 4,8,16 or 32, Actual Value: ${durationValue}`,
|
|
13668
|
+
severity: AlphaTexDiagnosticsSeverity.Error,
|
|
13669
|
+
start: metaData.arguments.arguments[0].start,
|
|
13670
|
+
end: metaData.arguments.arguments[0].end
|
|
13671
|
+
});
|
|
13672
|
+
return ApplyNodeResult.NotAppliedSemanticError;
|
|
13673
|
+
}
|
|
13674
|
+
for (let i = 1; i < metaData.arguments.arguments.length; i++) {
|
|
13675
|
+
const groupSize = metaData.arguments.arguments[i].value;
|
|
13676
|
+
if (groupSize < 1) {
|
|
13677
|
+
importer.addSemanticDiagnostic({
|
|
13678
|
+
code: AlphaTexDiagnosticCode.AT209,
|
|
13679
|
+
message: `Value is out of valid range. Allowed range: >0, Actual Value: ${durationValue}`,
|
|
13680
|
+
severity: AlphaTexDiagnosticsSeverity.Error,
|
|
13681
|
+
start: metaData.arguments.arguments[i].start,
|
|
13682
|
+
end: metaData.arguments.arguments[i].end
|
|
13683
|
+
});
|
|
13684
|
+
return ApplyNodeResult.NotAppliedSemanticError;
|
|
13685
|
+
}
|
|
13686
|
+
groupSizes.push(metaData.arguments.arguments[i].value);
|
|
13687
|
+
}
|
|
13688
|
+
if (!masterBar.beamingRules) {
|
|
13689
|
+
masterBar.beamingRules = new BeamingRules();
|
|
13690
|
+
}
|
|
13691
|
+
masterBar.beamingRules.groups.set(duration, groupSizes);
|
|
13692
|
+
return ApplyNodeResult.Applied;
|
|
13693
|
+
}
|
|
13449
13694
|
static _handleAccidentalMode(importer, args) {
|
|
13450
13695
|
const accidentalMode = AlphaTex1LanguageHandler._parseEnumValue(importer, args, 'accidental mode', AlphaTex1EnumMappings.alphaTexAccidentalMode);
|
|
13451
13696
|
if (accidentalMode === undefined) {
|
|
@@ -15038,6 +15283,15 @@
|
|
|
15038
15283
|
])));
|
|
15039
15284
|
}
|
|
15040
15285
|
}
|
|
15286
|
+
if (masterBar.beamingRules) {
|
|
15287
|
+
for (const [k, v] of masterBar.beamingRules.groups) {
|
|
15288
|
+
const args = Atnf.args([Atnf.number(k)], true);
|
|
15289
|
+
for (const i of v) {
|
|
15290
|
+
args.arguments.push(Atnf.number(i));
|
|
15291
|
+
}
|
|
15292
|
+
nodes.push(Atnf.meta('beaming', args));
|
|
15293
|
+
}
|
|
15294
|
+
}
|
|
15041
15295
|
if ((masterBar.index > 0 && masterBar.tripletFeel !== masterBar.previousMasterBar?.tripletFeel) ||
|
|
15042
15296
|
(masterBar.index === 0 && masterBar.tripletFeel !== TripletFeel.NoTripletFeel)) {
|
|
15043
15297
|
nodes.push(Atnf.identMeta('tf', AlphaTex1EnumMappings.tripletFeelReversed.get(masterBar.tripletFeel)));
|
|
@@ -23038,6 +23292,8 @@
|
|
|
23038
23292
|
}
|
|
23039
23293
|
}
|
|
23040
23294
|
_parseMasterBarXProperties(masterBar, node) {
|
|
23295
|
+
let beamingRuleDuration = Number.NaN;
|
|
23296
|
+
let beamingRuleGroups = undefined;
|
|
23041
23297
|
for (const c of node.childElements()) {
|
|
23042
23298
|
switch (c.localName) {
|
|
23043
23299
|
case 'XProperty':
|
|
@@ -23046,10 +23302,32 @@
|
|
|
23046
23302
|
case '1124073984':
|
|
23047
23303
|
masterBar.displayScale = GpifParser._parseFloatSafe(c.findChildElement('Double')?.innerText, 1);
|
|
23048
23304
|
break;
|
|
23305
|
+
case '1124139010':
|
|
23306
|
+
beamingRuleDuration = GpifParser._parseIntSafe(c.findChildElement('Int')?.innerText, Number.NaN);
|
|
23307
|
+
break;
|
|
23308
|
+
default:
|
|
23309
|
+
const idNumeric = GpifParser._parseIntSafe(id, 0);
|
|
23310
|
+
if (idNumeric >= 1124139264 && idNumeric <= 1124139295) {
|
|
23311
|
+
const groupIndex = idNumeric - 1124139264;
|
|
23312
|
+
const groupSize = GpifParser._parseIntSafe(c.findChildElement('Int')?.innerText, Number.NaN);
|
|
23313
|
+
if (beamingRuleGroups === undefined) {
|
|
23314
|
+
beamingRuleGroups = [];
|
|
23315
|
+
}
|
|
23316
|
+
while (beamingRuleGroups.length < groupIndex + 1) {
|
|
23317
|
+
beamingRuleGroups.push(0);
|
|
23318
|
+
}
|
|
23319
|
+
beamingRuleGroups[groupIndex] = groupSize;
|
|
23320
|
+
}
|
|
23321
|
+
break;
|
|
23049
23322
|
}
|
|
23050
23323
|
break;
|
|
23051
23324
|
}
|
|
23052
23325
|
}
|
|
23326
|
+
if (!Number.isNaN(beamingRuleDuration) && beamingRuleGroups) {
|
|
23327
|
+
const rules = new BeamingRules();
|
|
23328
|
+
rules.groups.set(beamingRuleDuration, beamingRuleGroups);
|
|
23329
|
+
masterBar.beamingRules = rules;
|
|
23330
|
+
}
|
|
23053
23331
|
}
|
|
23054
23332
|
_parseBeatProperties(node, beat) {
|
|
23055
23333
|
let isWhammy = false;
|
|
@@ -36585,6 +36863,43 @@
|
|
|
36585
36863
|
}
|
|
36586
36864
|
}
|
|
36587
36865
|
|
|
36866
|
+
/**
|
|
36867
|
+
* @internal
|
|
36868
|
+
*/
|
|
36869
|
+
class BeamingRulesSerializer {
|
|
36870
|
+
static fromJson(obj, m) {
|
|
36871
|
+
if (!m) {
|
|
36872
|
+
return;
|
|
36873
|
+
}
|
|
36874
|
+
JsonHelper.forEach(m, (v, k) => BeamingRulesSerializer.setProperty(obj, k, v));
|
|
36875
|
+
}
|
|
36876
|
+
static toJson(obj) {
|
|
36877
|
+
if (!obj) {
|
|
36878
|
+
return null;
|
|
36879
|
+
}
|
|
36880
|
+
const o = new Map();
|
|
36881
|
+
{
|
|
36882
|
+
const m = new Map();
|
|
36883
|
+
o.set("groups", m);
|
|
36884
|
+
for (const [k, v] of obj.groups) {
|
|
36885
|
+
m.set(k.toString(), v);
|
|
36886
|
+
}
|
|
36887
|
+
}
|
|
36888
|
+
return o;
|
|
36889
|
+
}
|
|
36890
|
+
static setProperty(obj, property, v) {
|
|
36891
|
+
switch (property) {
|
|
36892
|
+
case "groups":
|
|
36893
|
+
obj.groups = new Map();
|
|
36894
|
+
JsonHelper.forEach(v, (v, k) => {
|
|
36895
|
+
obj.groups.set(JsonHelper.parseEnum(k, Duration), v);
|
|
36896
|
+
});
|
|
36897
|
+
return true;
|
|
36898
|
+
}
|
|
36899
|
+
return false;
|
|
36900
|
+
}
|
|
36901
|
+
}
|
|
36902
|
+
|
|
36588
36903
|
/**
|
|
36589
36904
|
* @internal
|
|
36590
36905
|
*/
|
|
@@ -36763,6 +37078,9 @@
|
|
|
36763
37078
|
o.set("timesignaturenumerator", obj.timeSignatureNumerator);
|
|
36764
37079
|
o.set("timesignaturedenominator", obj.timeSignatureDenominator);
|
|
36765
37080
|
o.set("timesignaturecommon", obj.timeSignatureCommon);
|
|
37081
|
+
if (obj.beamingRules) {
|
|
37082
|
+
o.set("beamingrules", BeamingRulesSerializer.toJson(obj.beamingRules));
|
|
37083
|
+
}
|
|
36766
37084
|
o.set("isfreetime", obj.isFreeTime);
|
|
36767
37085
|
o.set("tripletfeel", obj.tripletFeel);
|
|
36768
37086
|
if (obj.section) {
|
|
@@ -36815,6 +37133,15 @@
|
|
|
36815
37133
|
case "timesignaturecommon":
|
|
36816
37134
|
obj.timeSignatureCommon = v;
|
|
36817
37135
|
return true;
|
|
37136
|
+
case "beamingrules":
|
|
37137
|
+
if (v) {
|
|
37138
|
+
obj.beamingRules = new BeamingRules();
|
|
37139
|
+
BeamingRulesSerializer.fromJson(obj.beamingRules, v);
|
|
37140
|
+
}
|
|
37141
|
+
else {
|
|
37142
|
+
obj.beamingRules = undefined;
|
|
37143
|
+
}
|
|
37144
|
+
return true;
|
|
36818
37145
|
case "isfreetime":
|
|
36819
37146
|
obj.isFreeTime = v;
|
|
36820
37147
|
return true;
|
|
@@ -61473,6 +61800,7 @@
|
|
|
61473
61800
|
class BeamingHelper {
|
|
61474
61801
|
_staff;
|
|
61475
61802
|
_renderer;
|
|
61803
|
+
_beamingRuleLookup;
|
|
61476
61804
|
voice = null;
|
|
61477
61805
|
beats = [];
|
|
61478
61806
|
shortestDuration = Duration.QuadrupleWhole;
|
|
@@ -61506,10 +61834,11 @@
|
|
|
61506
61834
|
static beatHasFlag(beat) {
|
|
61507
61835
|
return (!beat.deadSlapped && !beat.isRest && (beat.duration > Duration.Quarter || beat.graceType !== GraceType.None));
|
|
61508
61836
|
}
|
|
61509
|
-
constructor(staff, renderer) {
|
|
61837
|
+
constructor(staff, renderer, beamingRuleLookup) {
|
|
61510
61838
|
this._staff = staff;
|
|
61511
61839
|
this._renderer = renderer;
|
|
61512
61840
|
this.beats = [];
|
|
61841
|
+
this._beamingRuleLookup = beamingRuleLookup;
|
|
61513
61842
|
}
|
|
61514
61843
|
alignWithBeats() {
|
|
61515
61844
|
for (const v of this.drawingInfos.values()) {
|
|
@@ -61564,7 +61893,7 @@
|
|
|
61564
61893
|
switch (this.beats[this.beats.length - 1].beamingMode) {
|
|
61565
61894
|
case BeatBeamingMode.Auto:
|
|
61566
61895
|
case BeatBeamingMode.ForceSplitOnSecondaryToNext:
|
|
61567
|
-
add =
|
|
61896
|
+
add = this._canJoin(this.beats[this.beats.length - 1], beat);
|
|
61568
61897
|
break;
|
|
61569
61898
|
case BeatBeamingMode.ForceSplitToNext:
|
|
61570
61899
|
add = false;
|
|
@@ -61636,8 +61965,7 @@
|
|
|
61636
61965
|
this._highestNoteCompareValueInHelper = highestValueForNote;
|
|
61637
61966
|
}
|
|
61638
61967
|
}
|
|
61639
|
-
|
|
61640
|
-
static _canJoin(b1, b2) {
|
|
61968
|
+
_canJoin(b1, b2) {
|
|
61641
61969
|
// is this a voice we can join with?
|
|
61642
61970
|
if (!b1 ||
|
|
61643
61971
|
!b2 ||
|
|
@@ -61675,19 +62003,10 @@
|
|
|
61675
62003
|
return true;
|
|
61676
62004
|
}
|
|
61677
62005
|
}
|
|
61678
|
-
//
|
|
61679
|
-
|
|
61680
|
-
|
|
61681
|
-
|
|
61682
|
-
if (m1.masterBar.timeSignatureNumerator % 3 === 0) {
|
|
61683
|
-
divisionLength += (MidiUtils.QuarterTime / 2) | 0;
|
|
61684
|
-
}
|
|
61685
|
-
break;
|
|
61686
|
-
}
|
|
61687
|
-
// check if they are on the same division
|
|
61688
|
-
const division1 = ((divisionLength + start1) / divisionLength) | 0 | 0;
|
|
61689
|
-
const division2 = ((divisionLength + start2) / divisionLength) | 0 | 0;
|
|
61690
|
-
return division1 === division2;
|
|
62006
|
+
// check if they are on the same group as per rule definitions
|
|
62007
|
+
const groupId1 = this._beamingRuleLookup.calculateGroupIndex(start1);
|
|
62008
|
+
const groupId2 = this._beamingRuleLookup.calculateGroupIndex(start2);
|
|
62009
|
+
return groupId1 === groupId2;
|
|
61691
62010
|
}
|
|
61692
62011
|
static _canJoinDuration(d) {
|
|
61693
62012
|
switch (d) {
|
|
@@ -61854,6 +62173,61 @@
|
|
|
61854
62173
|
}
|
|
61855
62174
|
}
|
|
61856
62175
|
|
|
62176
|
+
/**
|
|
62177
|
+
* @internal
|
|
62178
|
+
*/
|
|
62179
|
+
class BeamingRuleLookup {
|
|
62180
|
+
_division = 0;
|
|
62181
|
+
_slots = [];
|
|
62182
|
+
_barDuration;
|
|
62183
|
+
constructor(barDuration, division, slots) {
|
|
62184
|
+
this._division = division;
|
|
62185
|
+
this._slots = slots;
|
|
62186
|
+
this._barDuration = barDuration;
|
|
62187
|
+
}
|
|
62188
|
+
calculateGroupIndex(beatStartTime) {
|
|
62189
|
+
// no slots -> all have their own group based (use the start time as index)
|
|
62190
|
+
if (this._slots.length === 0) {
|
|
62191
|
+
return beatStartTime;
|
|
62192
|
+
}
|
|
62193
|
+
// rollover within the bar.
|
|
62194
|
+
beatStartTime = beatStartTime % this._barDuration;
|
|
62195
|
+
const slotIndex = Math.floor(beatStartTime / this._division);
|
|
62196
|
+
return this._slots[slotIndex];
|
|
62197
|
+
}
|
|
62198
|
+
static build(masterBar, ruleDuration, ruleGroups) {
|
|
62199
|
+
const totalDuration = masterBar.calculateDuration(false);
|
|
62200
|
+
const division = MidiUtils.toTicks(ruleDuration);
|
|
62201
|
+
const slotCount = totalDuration / division;
|
|
62202
|
+
// should only happen in case of improper data.
|
|
62203
|
+
if (slotCount < 0 || ruleGroups.length === 0) {
|
|
62204
|
+
return new BeamingRuleLookup(0, 0, []);
|
|
62205
|
+
}
|
|
62206
|
+
let groupIndex = 0;
|
|
62207
|
+
let remainingSlots = ruleGroups[groupIndex];
|
|
62208
|
+
const slots = [];
|
|
62209
|
+
for (let i = 0; i < slotCount; i++) {
|
|
62210
|
+
if (groupIndex < ruleGroups.length) {
|
|
62211
|
+
slots.push(groupIndex);
|
|
62212
|
+
remainingSlots--;
|
|
62213
|
+
if (remainingSlots <= 0) {
|
|
62214
|
+
groupIndex++;
|
|
62215
|
+
if (groupIndex < ruleGroups.length) {
|
|
62216
|
+
remainingSlots = ruleGroups[groupIndex];
|
|
62217
|
+
}
|
|
62218
|
+
}
|
|
62219
|
+
}
|
|
62220
|
+
else {
|
|
62221
|
+
// no groups defined for the remaining slots: all slots are treated
|
|
62222
|
+
// as unjoined
|
|
62223
|
+
slots.push(groupIndex);
|
|
62224
|
+
groupIndex++;
|
|
62225
|
+
}
|
|
62226
|
+
}
|
|
62227
|
+
return new BeamingRuleLookup(totalDuration, division, slots);
|
|
62228
|
+
}
|
|
62229
|
+
}
|
|
62230
|
+
|
|
61857
62231
|
/**
|
|
61858
62232
|
* @internal
|
|
61859
62233
|
*/
|
|
@@ -61870,6 +62244,19 @@
|
|
|
61870
62244
|
initialize() {
|
|
61871
62245
|
const barRenderer = this._renderer;
|
|
61872
62246
|
const bar = this._renderer.bar;
|
|
62247
|
+
const masterBar = bar.masterBar;
|
|
62248
|
+
const beamingRules = masterBar.actualBeamingRules ?? BarHelpers._findOrBuildDefaultBeamingRules(masterBar);
|
|
62249
|
+
const rule = beamingRules.findRule(bar.shortestDuration);
|
|
62250
|
+
// NOTE: moste rules have only one group definition, so its better to reuse the unique id
|
|
62251
|
+
// than compute a potentially shorter id here.
|
|
62252
|
+
const key = `beaming_${beamingRules.uniqueId}_${rule[0]}`;
|
|
62253
|
+
let beamingRuleLookup = this._renderer.scoreRenderer.layout.beamingRuleLookups.has(key)
|
|
62254
|
+
? this._renderer.scoreRenderer.layout.beamingRuleLookups.get(key)
|
|
62255
|
+
: undefined;
|
|
62256
|
+
if (!beamingRuleLookup) {
|
|
62257
|
+
beamingRuleLookup = BeamingRuleLookup.build(masterBar, rule[0], rule[1]);
|
|
62258
|
+
this._renderer.scoreRenderer.layout.beamingRuleLookups.set(key, beamingRuleLookup);
|
|
62259
|
+
}
|
|
61873
62260
|
let currentBeamHelper = null;
|
|
61874
62261
|
let currentGraceBeamHelper = null;
|
|
61875
62262
|
for (let i = 0, j = bar.voices.length; i < j; i++) {
|
|
@@ -61895,7 +62282,7 @@
|
|
|
61895
62282
|
helperForBeat.finish();
|
|
61896
62283
|
}
|
|
61897
62284
|
// if not possible, create the next beaming helper
|
|
61898
|
-
helperForBeat = new BeamingHelper(bar.staff, barRenderer);
|
|
62285
|
+
helperForBeat = new BeamingHelper(bar.staff, barRenderer, beamingRuleLookup);
|
|
61899
62286
|
helperForBeat.preferredBeamDirection = this.preferredBeamDirection;
|
|
61900
62287
|
helperForBeat.checkBeat(b);
|
|
61901
62288
|
if (b.graceType !== GraceType.None) {
|
|
@@ -61918,6 +62305,69 @@
|
|
|
61918
62305
|
currentGraceBeamHelper = null;
|
|
61919
62306
|
}
|
|
61920
62307
|
}
|
|
62308
|
+
static _defaultBeamingRules;
|
|
62309
|
+
static _findOrBuildDefaultBeamingRules(masterBar) {
|
|
62310
|
+
let defaultBeamingRules = BarHelpers._defaultBeamingRules;
|
|
62311
|
+
if (!defaultBeamingRules) {
|
|
62312
|
+
defaultBeamingRules = new Map([
|
|
62313
|
+
BeamingRules.createSimple(2, 16, Duration.Sixteenth, [1, 1]),
|
|
62314
|
+
BeamingRules.createSimple(1, 8, Duration.Eighth, [1]),
|
|
62315
|
+
BeamingRules.createSimple(1, 4, Duration.Quarter, [1]),
|
|
62316
|
+
BeamingRules.createSimple(3, 16, Duration.Sixteenth, [3]),
|
|
62317
|
+
BeamingRules.createSimple(4, 16, Duration.Sixteenth, [2, 2]),
|
|
62318
|
+
BeamingRules.createSimple(2, 8, Duration.Eighth, [1, 1]),
|
|
62319
|
+
BeamingRules.createSimple(5, 16, Duration.Sixteenth, [3, 2]),
|
|
62320
|
+
BeamingRules.createSimple(6, 16, Duration.Sixteenth, [3, 3]),
|
|
62321
|
+
BeamingRules.createSimple(3, 8, Duration.Eighth, [3]),
|
|
62322
|
+
BeamingRules.createSimple(4, 8, Duration.Eighth, [2, 2]),
|
|
62323
|
+
BeamingRules.createSimple(2, 4, Duration.Quarter, [1, 1]),
|
|
62324
|
+
BeamingRules.createSimple(9, 16, Duration.Sixteenth, [3, 3, 3]),
|
|
62325
|
+
BeamingRules.createSimple(5, 8, Duration.Eighth, [3, 2]),
|
|
62326
|
+
BeamingRules.createSimple(12, 16, Duration.Sixteenth, [3, 3, 3, 3]),
|
|
62327
|
+
BeamingRules.createSimple(6, 8, Duration.Eighth, [3, 3, 3]),
|
|
62328
|
+
BeamingRules.createSimple(3, 4, Duration.Quarter, [1, 1, 1]),
|
|
62329
|
+
BeamingRules.createSimple(7, 8, Duration.Eighth, [4, 3]),
|
|
62330
|
+
BeamingRules.createSimple(8, 8, Duration.Eighth, [3, 3, 2]),
|
|
62331
|
+
BeamingRules.createSimple(4, 4, Duration.Quarter, [1, 1, 1, 1]),
|
|
62332
|
+
BeamingRules.createSimple(9, 8, Duration.Eighth, [3, 3, 3]),
|
|
62333
|
+
BeamingRules.createSimple(10, 8, Duration.Eighth, [4, 3, 3]),
|
|
62334
|
+
BeamingRules.createSimple(5, 4, Duration.Quarter, [1, 1, 1, 1, 1]),
|
|
62335
|
+
BeamingRules.createSimple(12, 8, Duration.Eighth, [3, 3, 3, 3]),
|
|
62336
|
+
BeamingRules.createSimple(6, 4, Duration.Quarter, [1, 1, 1, 1, 1, 1]),
|
|
62337
|
+
BeamingRules.createSimple(15, 8, Duration.Eighth, [3, 3, 3, 3, 3, 3]),
|
|
62338
|
+
BeamingRules.createSimple(8, 4, Duration.Quarter, [1, 1, 1, 1, 1, 1, 1, 1]),
|
|
62339
|
+
BeamingRules.createSimple(18, 8, Duration.Eighth, [3, 3, 3, 3, 3, 3])
|
|
62340
|
+
].map(r => [`${r.timeSignatureNumerator}_${r.timeSignatureDenominator}`, r]));
|
|
62341
|
+
BarHelpers._defaultBeamingRules = defaultBeamingRules;
|
|
62342
|
+
}
|
|
62343
|
+
const key = `${masterBar.timeSignatureNumerator}_${masterBar.timeSignatureDenominator}`;
|
|
62344
|
+
if (defaultBeamingRules.has(key)) {
|
|
62345
|
+
return defaultBeamingRules.get(key);
|
|
62346
|
+
}
|
|
62347
|
+
// NOTE: this is the old alphaTab logic how we used to beamed bars.
|
|
62348
|
+
// we either group in quarters, or in 3x8ths depending on the key signature
|
|
62349
|
+
let divisionLength = MidiUtils.QuarterTime;
|
|
62350
|
+
switch (masterBar.timeSignatureDenominator) {
|
|
62351
|
+
case 8:
|
|
62352
|
+
if (masterBar.timeSignatureNumerator % 3 === 0) {
|
|
62353
|
+
divisionLength += (MidiUtils.QuarterTime / 2) | 0;
|
|
62354
|
+
}
|
|
62355
|
+
break;
|
|
62356
|
+
}
|
|
62357
|
+
const numberOfDivisions = Math.ceil(masterBar.calculateDuration(false) / divisionLength);
|
|
62358
|
+
const notesPerDivision = (divisionLength / MidiUtils.QuarterTime) * 2;
|
|
62359
|
+
const fallback = new BeamingRules();
|
|
62360
|
+
const groups = [];
|
|
62361
|
+
for (let i = 0; i < numberOfDivisions; i++) {
|
|
62362
|
+
groups.push(notesPerDivision);
|
|
62363
|
+
}
|
|
62364
|
+
fallback.groups.set(Duration.Eighth, groups);
|
|
62365
|
+
fallback.timeSignatureNumerator = masterBar.timeSignatureNumerator;
|
|
62366
|
+
fallback.timeSignatureDenominator = masterBar.timeSignatureDenominator;
|
|
62367
|
+
fallback.finish();
|
|
62368
|
+
defaultBeamingRules.set(key, fallback);
|
|
62369
|
+
return fallback;
|
|
62370
|
+
}
|
|
61921
62371
|
getBeamingHelperForBeat(beat) {
|
|
61922
62372
|
return this._beamHelperLookup.has(beat.id) ? this._beamHelperLookup.get(beat.id) : undefined;
|
|
61923
62373
|
}
|
|
@@ -65850,6 +66300,7 @@
|
|
|
65850
66300
|
this.renderer = renderer;
|
|
65851
66301
|
}
|
|
65852
66302
|
slurRegistry = new SlurRegistry();
|
|
66303
|
+
beamingRuleLookups = new Map();
|
|
65853
66304
|
resize() {
|
|
65854
66305
|
this._lazyPartials.clear();
|
|
65855
66306
|
this.slurRegistry.clear();
|
|
@@ -65858,6 +66309,7 @@
|
|
|
65858
66309
|
layoutAndRender() {
|
|
65859
66310
|
this._lazyPartials.clear();
|
|
65860
66311
|
this.slurRegistry.clear();
|
|
66312
|
+
this.beamingRuleLookups.clear();
|
|
65861
66313
|
this._barRendererLookup.clear();
|
|
65862
66314
|
this.profile = Environment.staveProfiles.get(this.renderer.settings.display.staveProfile);
|
|
65863
66315
|
const score = this.renderer.score;
|
|
@@ -78045,6 +78497,9 @@
|
|
|
78045
78497
|
key.addElement('Sharps').innerText = 'Sharps';
|
|
78046
78498
|
masterBarNode.addElement('Time').innerText =
|
|
78047
78499
|
`${masterBar.timeSignatureNumerator}/${masterBar.timeSignatureDenominator}`;
|
|
78500
|
+
if (masterBar.actualBeamingRules) {
|
|
78501
|
+
this._writeBarXProperties(masterBarNode, masterBar);
|
|
78502
|
+
}
|
|
78048
78503
|
if (masterBar.isFreeTime) {
|
|
78049
78504
|
masterBarNode.addElement('FreeTime');
|
|
78050
78505
|
}
|
|
@@ -78154,6 +78609,29 @@
|
|
|
78154
78609
|
}
|
|
78155
78610
|
this._writeFermatas(masterBarNode, masterBar);
|
|
78156
78611
|
}
|
|
78612
|
+
_writeBarXProperties(masterBarNode, masterBar) {
|
|
78613
|
+
const properties = masterBarNode.addElement('XProperties');
|
|
78614
|
+
const beamingRules = masterBar.actualBeamingRules;
|
|
78615
|
+
if (beamingRules) {
|
|
78616
|
+
// prefer 8th note rule (that's what GP mostly has)
|
|
78617
|
+
const rule = beamingRules.findRule(Duration.Eighth);
|
|
78618
|
+
// NOTE: it's not clear if guitar pro supports quarter rules
|
|
78619
|
+
// for that case we better convert this to an "8th" note rule.
|
|
78620
|
+
let durationProp = rule[0];
|
|
78621
|
+
let groupSizeFactor = 1;
|
|
78622
|
+
if (rule[0] === Duration.Quarter) {
|
|
78623
|
+
durationProp = 8;
|
|
78624
|
+
groupSizeFactor = 2;
|
|
78625
|
+
}
|
|
78626
|
+
this._writeSimpleXPropertyNode(properties, '1124139010', 'Int', durationProp.toString());
|
|
78627
|
+
const startGroupid = 1124139264;
|
|
78628
|
+
let i = 0;
|
|
78629
|
+
while (i < rule[1].length) {
|
|
78630
|
+
this._writeSimpleXPropertyNode(properties, (startGroupid + i).toString(), 'Int', (rule[1][i] * groupSizeFactor).toString());
|
|
78631
|
+
i++;
|
|
78632
|
+
}
|
|
78633
|
+
}
|
|
78634
|
+
}
|
|
78157
78635
|
_writeFermatas(parent, masterBar) {
|
|
78158
78636
|
const fermataCount = masterBar.fermata?.size ?? 0;
|
|
78159
78637
|
if (fermataCount === 0) {
|