@coderline/alphatab 1.3.0-alpha.849 → 1.3.0-alpha.856
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.d.ts +24 -0
- package/dist/alphaTab.js +321 -143
- package/dist/alphaTab.min.js +1 -1
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +321 -143
- package/package.json +2 -2
package/dist/alphaTab.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* alphaTab v1.3.0-alpha.
|
|
2
|
+
* alphaTab v1.3.0-alpha.856 (develop, build 856)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2023, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -2023,6 +2023,7 @@ class Note {
|
|
|
2023
2023
|
this.maxBendPoint = null;
|
|
2024
2024
|
/**
|
|
2025
2025
|
* Gets or sets the fret on which this note is played on the instrument.
|
|
2026
|
+
* 0 is the nut.
|
|
2026
2027
|
*/
|
|
2027
2028
|
this.fret = -1;
|
|
2028
2029
|
/**
|
|
@@ -2370,28 +2371,43 @@ class Note {
|
|
|
2370
2371
|
return 0;
|
|
2371
2372
|
}
|
|
2372
2373
|
get realValue() {
|
|
2373
|
-
|
|
2374
|
-
if (this.isStringed) {
|
|
2375
|
-
if (this.harmonicType === HarmonicType.Natural) {
|
|
2376
|
-
realValue = this.harmonicPitch + this.stringTuning - this.beat.voice.bar.staff.transpositionPitch;
|
|
2377
|
-
}
|
|
2378
|
-
else {
|
|
2379
|
-
realValue += this.harmonicPitch;
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
return realValue;
|
|
2374
|
+
return this.calculateRealValue(true, true);
|
|
2383
2375
|
}
|
|
2384
2376
|
get realValueWithoutHarmonic() {
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2377
|
+
return this.calculateRealValue(true, false);
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* Calculates the real note value of this note as midi key respecting the given options.
|
|
2381
|
+
* @param applyTranspositionPitch Whether or not to apply the transposition pitch of the current staff.
|
|
2382
|
+
* @param applyHarmonic Whether or not to apply harmonic pitches to the note.
|
|
2383
|
+
* @returns The calculated note value as midi key.
|
|
2384
|
+
*/
|
|
2385
|
+
calculateRealValue(applyTranspositionPitch, applyHarmonic) {
|
|
2386
|
+
const transpositionPitch = applyTranspositionPitch ? this.beat.voice.bar.staff.transpositionPitch : 0;
|
|
2387
|
+
if (applyHarmonic) {
|
|
2388
|
+
let realValue = this.calculateRealValue(applyTranspositionPitch, false);
|
|
2389
|
+
if (this.isStringed) {
|
|
2390
|
+
if (this.harmonicType === HarmonicType.Natural) {
|
|
2391
|
+
realValue = this.harmonicPitch + this.stringTuning - transpositionPitch;
|
|
2392
|
+
}
|
|
2393
|
+
else {
|
|
2394
|
+
realValue += this.harmonicPitch;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
return realValue;
|
|
2390
2398
|
}
|
|
2391
|
-
|
|
2392
|
-
|
|
2399
|
+
else {
|
|
2400
|
+
if (this.isPercussion) {
|
|
2401
|
+
return this.percussionArticulation;
|
|
2402
|
+
}
|
|
2403
|
+
if (this.isStringed) {
|
|
2404
|
+
return this.fret + this.stringTuning - transpositionPitch;
|
|
2405
|
+
}
|
|
2406
|
+
if (this.isPiano) {
|
|
2407
|
+
return this.octave * 12 + this.tone - transpositionPitch;
|
|
2408
|
+
}
|
|
2409
|
+
return 0;
|
|
2393
2410
|
}
|
|
2394
|
-
return 0;
|
|
2395
2411
|
}
|
|
2396
2412
|
get harmonicPitch() {
|
|
2397
2413
|
if (this.harmonicType === HarmonicType.None || !this.isStringed) {
|
|
@@ -13317,6 +13333,7 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
13317
13333
|
this.ensureVoices(bar);
|
|
13318
13334
|
}
|
|
13319
13335
|
}
|
|
13336
|
+
let chordsByIdForTrack = new Map();
|
|
13320
13337
|
if (masterBar) {
|
|
13321
13338
|
let attributesParsed = false;
|
|
13322
13339
|
for (let c of element.childNodes) {
|
|
@@ -13338,7 +13355,7 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
13338
13355
|
}
|
|
13339
13356
|
break;
|
|
13340
13357
|
case 'harmony':
|
|
13341
|
-
this.parseHarmony(c, track);
|
|
13358
|
+
this.parseHarmony(c, track, chordsByIdForTrack);
|
|
13342
13359
|
break;
|
|
13343
13360
|
case 'sound':
|
|
13344
13361
|
// TODO
|
|
@@ -13478,127 +13495,23 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
13478
13495
|
staff.tuning[staff.tuning.length - line] = tuning;
|
|
13479
13496
|
}
|
|
13480
13497
|
}
|
|
13481
|
-
parseHarmony(element, track) {
|
|
13482
|
-
let
|
|
13483
|
-
let
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
for (let c of element.childNodes) {
|
|
13487
|
-
if (c.nodeType === XmlNodeType.Element) {
|
|
13488
|
-
switch (c.localName) {
|
|
13498
|
+
parseHarmony(element, track, chordsByIdForTrack) {
|
|
13499
|
+
let chord = new Chord();
|
|
13500
|
+
for (let childNode of element.childNodes) {
|
|
13501
|
+
if (childNode.nodeType === XmlNodeType.Element) {
|
|
13502
|
+
switch (childNode.localName) {
|
|
13489
13503
|
case 'root':
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
switch (parseInt(c.innerText)) {
|
|
13498
|
-
case -2:
|
|
13499
|
-
rootAlter = ' bb';
|
|
13500
|
-
break;
|
|
13501
|
-
case -1:
|
|
13502
|
-
rootAlter = ' b';
|
|
13503
|
-
break;
|
|
13504
|
-
case 0:
|
|
13505
|
-
rootAlter = '';
|
|
13506
|
-
break;
|
|
13507
|
-
case 1:
|
|
13508
|
-
rootAlter = ' #';
|
|
13509
|
-
break;
|
|
13510
|
-
case 2:
|
|
13511
|
-
rootAlter = ' ##';
|
|
13512
|
-
break;
|
|
13513
|
-
}
|
|
13514
|
-
break;
|
|
13515
|
-
}
|
|
13516
|
-
}
|
|
13517
|
-
}
|
|
13504
|
+
chord.name = this.parseHarmonyRoot(childNode);
|
|
13505
|
+
break;
|
|
13506
|
+
case 'kind':
|
|
13507
|
+
chord.name = chord.name + this.parseHarmonyKind(childNode);
|
|
13508
|
+
break;
|
|
13509
|
+
case 'frame':
|
|
13510
|
+
this.parseHarmonyFrame(childNode, chord);
|
|
13518
13511
|
break;
|
|
13519
13512
|
}
|
|
13520
13513
|
}
|
|
13521
13514
|
}
|
|
13522
|
-
let chord = new Chord();
|
|
13523
|
-
chord.name = rootStep + rootAlter;
|
|
13524
|
-
// TODO: find proper names for the rest
|
|
13525
|
-
// switch (kind)
|
|
13526
|
-
// {
|
|
13527
|
-
// // triads
|
|
13528
|
-
// case "major":
|
|
13529
|
-
// break;
|
|
13530
|
-
// case "minor":
|
|
13531
|
-
// chord.Name += "m";
|
|
13532
|
-
// break;
|
|
13533
|
-
// // Sevenths
|
|
13534
|
-
// case "augmented":
|
|
13535
|
-
// break;
|
|
13536
|
-
// case "diminished":
|
|
13537
|
-
// break;
|
|
13538
|
-
// case "dominant":
|
|
13539
|
-
// break;
|
|
13540
|
-
// case "major-seventh":
|
|
13541
|
-
// chord.Name += "7M";
|
|
13542
|
-
// break;
|
|
13543
|
-
// case "minor-seventh":
|
|
13544
|
-
// chord.Name += "m7";
|
|
13545
|
-
// break;
|
|
13546
|
-
// case "diminished-seventh":
|
|
13547
|
-
// break;
|
|
13548
|
-
// case "augmented-seventh":
|
|
13549
|
-
// break;
|
|
13550
|
-
// case "half-diminished":
|
|
13551
|
-
// break;
|
|
13552
|
-
// case "major-minor":
|
|
13553
|
-
// break;
|
|
13554
|
-
// // Sixths
|
|
13555
|
-
// case "major-sixth":
|
|
13556
|
-
// break;
|
|
13557
|
-
// case "minor-sixth":
|
|
13558
|
-
// break;
|
|
13559
|
-
// // Ninths
|
|
13560
|
-
// case "dominant-ninth":
|
|
13561
|
-
// break;
|
|
13562
|
-
// case "major-ninth":
|
|
13563
|
-
// break;
|
|
13564
|
-
// case "minor-ninth":
|
|
13565
|
-
// break;
|
|
13566
|
-
// // 11ths
|
|
13567
|
-
// case "dominant-11th":
|
|
13568
|
-
// break;
|
|
13569
|
-
// case "major-11th":
|
|
13570
|
-
// break;
|
|
13571
|
-
// case "minor-11th":
|
|
13572
|
-
// break;
|
|
13573
|
-
// // 13ths
|
|
13574
|
-
// case "dominant-13th":
|
|
13575
|
-
// break;
|
|
13576
|
-
// case "major-13th":
|
|
13577
|
-
// break;
|
|
13578
|
-
// case "minor-13th":
|
|
13579
|
-
// break;
|
|
13580
|
-
// // Suspended
|
|
13581
|
-
// case "suspended-second":
|
|
13582
|
-
// break;
|
|
13583
|
-
// case "suspended-fourth":
|
|
13584
|
-
// break;
|
|
13585
|
-
// // Functional sixths
|
|
13586
|
-
// case "Neapolitan":
|
|
13587
|
-
// break;
|
|
13588
|
-
// case "Italian":
|
|
13589
|
-
// break;
|
|
13590
|
-
// case "French":
|
|
13591
|
-
// break;
|
|
13592
|
-
// case "German":
|
|
13593
|
-
// break;
|
|
13594
|
-
// // Other
|
|
13595
|
-
// case "pedal":
|
|
13596
|
-
// break;
|
|
13597
|
-
// case "power":
|
|
13598
|
-
// break;
|
|
13599
|
-
// case "Tristan":
|
|
13600
|
-
// break;
|
|
13601
|
-
// }
|
|
13602
13515
|
// var degree = element.GetElementsByTagName("degree");
|
|
13603
13516
|
// if (degree.Length > 0)
|
|
13604
13517
|
// {
|
|
@@ -13615,9 +13528,199 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
13615
13528
|
// }
|
|
13616
13529
|
// }
|
|
13617
13530
|
this._currentChord = ModelUtils.newGuid();
|
|
13531
|
+
const chordKey = chord.uniqueId;
|
|
13532
|
+
if (chordsByIdForTrack.has(chordKey)) {
|
|
13533
|
+
// check if the chord is already present
|
|
13534
|
+
chord.showDiagram = false;
|
|
13535
|
+
}
|
|
13618
13536
|
for (let staff of track.staves) {
|
|
13619
13537
|
staff.addChord(this._currentChord, chord);
|
|
13620
13538
|
}
|
|
13539
|
+
chordsByIdForTrack.set(chordKey, chord);
|
|
13540
|
+
}
|
|
13541
|
+
parseHarmonyRoot(xmlNode) {
|
|
13542
|
+
let rootStep = '';
|
|
13543
|
+
let rootAlter = '';
|
|
13544
|
+
for (let rootChild of xmlNode.childNodes) {
|
|
13545
|
+
if (rootChild.nodeType === XmlNodeType.Element) {
|
|
13546
|
+
switch (rootChild.localName) {
|
|
13547
|
+
case 'root-step':
|
|
13548
|
+
rootStep = rootChild.innerText;
|
|
13549
|
+
break;
|
|
13550
|
+
case 'root-alter':
|
|
13551
|
+
switch (parseInt(xmlNode.innerText)) {
|
|
13552
|
+
case -2:
|
|
13553
|
+
rootAlter = 'bb';
|
|
13554
|
+
break;
|
|
13555
|
+
case -1:
|
|
13556
|
+
rootAlter = 'b';
|
|
13557
|
+
break;
|
|
13558
|
+
case 0:
|
|
13559
|
+
rootAlter = '';
|
|
13560
|
+
break;
|
|
13561
|
+
case 1:
|
|
13562
|
+
rootAlter = '#';
|
|
13563
|
+
break;
|
|
13564
|
+
case 2:
|
|
13565
|
+
rootAlter = '##';
|
|
13566
|
+
break;
|
|
13567
|
+
}
|
|
13568
|
+
break;
|
|
13569
|
+
}
|
|
13570
|
+
}
|
|
13571
|
+
}
|
|
13572
|
+
return rootStep + rootAlter;
|
|
13573
|
+
}
|
|
13574
|
+
parseHarmonyKind(xmlNode) {
|
|
13575
|
+
const kindText = xmlNode.getAttribute('text');
|
|
13576
|
+
let resultKind = '';
|
|
13577
|
+
if (kindText) {
|
|
13578
|
+
// the abbreviation is already provided
|
|
13579
|
+
resultKind = kindText;
|
|
13580
|
+
}
|
|
13581
|
+
else {
|
|
13582
|
+
const kindContent = xmlNode.innerText;
|
|
13583
|
+
switch (kindContent) {
|
|
13584
|
+
// triads
|
|
13585
|
+
case 'major':
|
|
13586
|
+
resultKind = '';
|
|
13587
|
+
break;
|
|
13588
|
+
case 'minor':
|
|
13589
|
+
resultKind = 'm';
|
|
13590
|
+
break;
|
|
13591
|
+
// Sevenths
|
|
13592
|
+
case 'augmented':
|
|
13593
|
+
resultKind = '+';
|
|
13594
|
+
break;
|
|
13595
|
+
case 'diminished':
|
|
13596
|
+
resultKind = '\u25CB';
|
|
13597
|
+
break;
|
|
13598
|
+
case 'dominant':
|
|
13599
|
+
resultKind = '7';
|
|
13600
|
+
break;
|
|
13601
|
+
case 'major-seventh':
|
|
13602
|
+
resultKind = '7M';
|
|
13603
|
+
break;
|
|
13604
|
+
case 'minor-seventh':
|
|
13605
|
+
resultKind = 'm7';
|
|
13606
|
+
break;
|
|
13607
|
+
case 'diminished-seventh':
|
|
13608
|
+
resultKind = '\u25CB7';
|
|
13609
|
+
break;
|
|
13610
|
+
case 'augmented-seventh':
|
|
13611
|
+
resultKind = '+7';
|
|
13612
|
+
break;
|
|
13613
|
+
case 'half-diminished':
|
|
13614
|
+
resultKind = '\u2349';
|
|
13615
|
+
break;
|
|
13616
|
+
case 'major-minor':
|
|
13617
|
+
resultKind = 'mMaj';
|
|
13618
|
+
break;
|
|
13619
|
+
// Sixths
|
|
13620
|
+
case 'major-sixth':
|
|
13621
|
+
resultKind = 'maj6';
|
|
13622
|
+
break;
|
|
13623
|
+
case 'minor-sixth':
|
|
13624
|
+
resultKind = 'm6';
|
|
13625
|
+
break;
|
|
13626
|
+
// Ninths
|
|
13627
|
+
case 'dominant-ninth':
|
|
13628
|
+
resultKind = '9';
|
|
13629
|
+
break;
|
|
13630
|
+
case 'major-ninth':
|
|
13631
|
+
resultKind = 'maj9';
|
|
13632
|
+
break;
|
|
13633
|
+
case 'minor-ninth':
|
|
13634
|
+
resultKind = 'm9';
|
|
13635
|
+
break;
|
|
13636
|
+
// 11ths
|
|
13637
|
+
case 'dominant-11th':
|
|
13638
|
+
resultKind = '11';
|
|
13639
|
+
break;
|
|
13640
|
+
case 'major-11th':
|
|
13641
|
+
resultKind = 'maj11';
|
|
13642
|
+
break;
|
|
13643
|
+
case 'minor-11th':
|
|
13644
|
+
resultKind = 'm11';
|
|
13645
|
+
break;
|
|
13646
|
+
// 13ths
|
|
13647
|
+
case 'dominant-13th':
|
|
13648
|
+
resultKind = '13';
|
|
13649
|
+
break;
|
|
13650
|
+
case 'major-13th':
|
|
13651
|
+
resultKind = 'maj13';
|
|
13652
|
+
break;
|
|
13653
|
+
case 'minor-13th':
|
|
13654
|
+
resultKind = 'm13';
|
|
13655
|
+
break;
|
|
13656
|
+
// Suspended
|
|
13657
|
+
case 'suspended-second':
|
|
13658
|
+
resultKind = 'sus2';
|
|
13659
|
+
break;
|
|
13660
|
+
case 'suspended-fourth':
|
|
13661
|
+
resultKind = 'sus4';
|
|
13662
|
+
break;
|
|
13663
|
+
// TODO: find proper names for the rest
|
|
13664
|
+
// Functional sixths
|
|
13665
|
+
// case "Neapolitan":
|
|
13666
|
+
// break;
|
|
13667
|
+
// case "Italian":
|
|
13668
|
+
// break;
|
|
13669
|
+
// case "French":
|
|
13670
|
+
// break;
|
|
13671
|
+
// case "German":
|
|
13672
|
+
// break;
|
|
13673
|
+
// // Other
|
|
13674
|
+
// case "pedal":
|
|
13675
|
+
// break;
|
|
13676
|
+
// case "power":
|
|
13677
|
+
// break;
|
|
13678
|
+
// case "Tristan":
|
|
13679
|
+
// break;
|
|
13680
|
+
}
|
|
13681
|
+
}
|
|
13682
|
+
return resultKind;
|
|
13683
|
+
}
|
|
13684
|
+
parseHarmonyFrame(xmlNode, chord) {
|
|
13685
|
+
for (let frameChild of xmlNode.childNodes) {
|
|
13686
|
+
if (frameChild.nodeType === XmlNodeType.Element) {
|
|
13687
|
+
switch (frameChild.localName) {
|
|
13688
|
+
case 'frame-strings':
|
|
13689
|
+
const stringsCount = parseInt(frameChild.innerText);
|
|
13690
|
+
chord.strings = new Array(stringsCount);
|
|
13691
|
+
for (let i = 0; i < stringsCount; i++) {
|
|
13692
|
+
// set strings unplayed as default
|
|
13693
|
+
chord.strings[i] = -1;
|
|
13694
|
+
}
|
|
13695
|
+
break;
|
|
13696
|
+
case 'first-fret':
|
|
13697
|
+
chord.firstFret = parseInt(frameChild.innerText);
|
|
13698
|
+
break;
|
|
13699
|
+
case 'frame-note':
|
|
13700
|
+
let stringNo = null;
|
|
13701
|
+
let fretNo = null;
|
|
13702
|
+
for (let noteChild of frameChild.childNodes) {
|
|
13703
|
+
switch (noteChild.localName) {
|
|
13704
|
+
case 'string':
|
|
13705
|
+
stringNo = parseInt(noteChild.innerText);
|
|
13706
|
+
break;
|
|
13707
|
+
case 'fret':
|
|
13708
|
+
fretNo = parseInt(noteChild.innerText);
|
|
13709
|
+
if (stringNo && fretNo >= 0) {
|
|
13710
|
+
chord.strings[stringNo - 1] = fretNo;
|
|
13711
|
+
}
|
|
13712
|
+
break;
|
|
13713
|
+
case 'barre':
|
|
13714
|
+
if (stringNo && fretNo && noteChild.getAttribute('type') === 'start') {
|
|
13715
|
+
chord.barreFrets.push(fretNo);
|
|
13716
|
+
}
|
|
13717
|
+
break;
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
break;
|
|
13721
|
+
}
|
|
13722
|
+
}
|
|
13723
|
+
}
|
|
13621
13724
|
}
|
|
13622
13725
|
parseBarline(element, masterBar) {
|
|
13623
13726
|
for (let c of element.childNodes) {
|
|
@@ -13884,9 +13987,9 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
13884
13987
|
if (!slurNumber) {
|
|
13885
13988
|
slurNumber = '1';
|
|
13886
13989
|
}
|
|
13887
|
-
// slur numbers are unique in the way that they have the same ID across
|
|
13888
|
-
// staffs/tracks etc. as long they represent the logically same slur.
|
|
13889
|
-
// but in our case it must be globally unique to link the correct notes.
|
|
13990
|
+
// slur numbers are unique in the way that they have the same ID across
|
|
13991
|
+
// staffs/tracks etc. as long they represent the logically same slur.
|
|
13992
|
+
// but in our case it must be globally unique to link the correct notes.
|
|
13890
13993
|
// adding the staff ID should be enough to achieve this
|
|
13891
13994
|
slurNumber = beat.voice.bar.staff.index + '_' + slurNumber;
|
|
13892
13995
|
switch (c.getAttribute('type')) {
|
|
@@ -18922,6 +19025,14 @@ class MidiFileGenerator {
|
|
|
18922
19025
|
* at a given midi tick position.
|
|
18923
19026
|
*/
|
|
18924
19027
|
this.tickLookup = new MidiTickLookup();
|
|
19028
|
+
/**
|
|
19029
|
+
* Gets or sets whether transposition pitches should be applied to the individual midi events or not.
|
|
19030
|
+
*/
|
|
19031
|
+
this.applyTranspositionPitches = true;
|
|
19032
|
+
/**
|
|
19033
|
+
* Gets the transposition pitches for the individual midi channels.
|
|
19034
|
+
*/
|
|
19035
|
+
this.transpositionPitches = new Map();
|
|
18925
19036
|
this._currentTripletFeel = null;
|
|
18926
19037
|
this.vibratoResolution = 16;
|
|
18927
19038
|
this._score = score;
|
|
@@ -18933,6 +19044,7 @@ class MidiFileGenerator {
|
|
|
18933
19044
|
* Starts the generation of the midi file.
|
|
18934
19045
|
*/
|
|
18935
19046
|
generate() {
|
|
19047
|
+
this.transpositionPitches.clear();
|
|
18936
19048
|
// initialize tracks
|
|
18937
19049
|
for (const track of this._score.tracks) {
|
|
18938
19050
|
this.generateTrack(track);
|
|
@@ -18978,7 +19090,22 @@ class MidiFileGenerator {
|
|
|
18978
19090
|
this._programsPerChannel.set(channel, program);
|
|
18979
19091
|
}
|
|
18980
19092
|
}
|
|
19093
|
+
static buildTranspositionPitches(score, settings) {
|
|
19094
|
+
const transpositionPitches = new Map();
|
|
19095
|
+
for (const track of score.tracks) {
|
|
19096
|
+
const transpositionPitch = track.index < settings.notation.transpositionPitches.length
|
|
19097
|
+
? settings.notation.transpositionPitches[track.index]
|
|
19098
|
+
: 0;
|
|
19099
|
+
transpositionPitches.set(track.playbackInfo.primaryChannel, transpositionPitch);
|
|
19100
|
+
transpositionPitches.set(track.playbackInfo.secondaryChannel, transpositionPitch);
|
|
19101
|
+
}
|
|
19102
|
+
return transpositionPitches;
|
|
19103
|
+
}
|
|
18981
19104
|
generateChannel(track, channel, playbackInfo) {
|
|
19105
|
+
const transpositionPitch = track.index < this._settings.notation.transpositionPitches.length
|
|
19106
|
+
? this._settings.notation.transpositionPitches[track.index]
|
|
19107
|
+
: 0;
|
|
19108
|
+
this.transpositionPitches.set(channel, transpositionPitch);
|
|
18982
19109
|
let volume = MidiFileGenerator.toChannelShort(playbackInfo.volume);
|
|
18983
19110
|
let balance = MidiFileGenerator.toChannelShort(playbackInfo.balance);
|
|
18984
19111
|
this._handler.addControlChange(track.index, 0, channel, ControllerType.VolumeCoarse, volume);
|
|
@@ -19198,7 +19325,7 @@ class MidiFileGenerator {
|
|
|
19198
19325
|
generateNote(note, beatStart, beatDuration, brushInfo) {
|
|
19199
19326
|
const track = note.beat.voice.bar.staff.track;
|
|
19200
19327
|
const staff = note.beat.voice.bar.staff;
|
|
19201
|
-
let noteKey = note.
|
|
19328
|
+
let noteKey = note.calculateRealValue(this.applyTranspositionPitches, true);
|
|
19202
19329
|
if (note.isPercussion) {
|
|
19203
19330
|
const articulation = PercussionMapper.getArticulation(note);
|
|
19204
19331
|
if (articulation) {
|
|
@@ -19476,7 +19603,7 @@ class MidiFileGenerator {
|
|
|
19476
19603
|
case SlideOutType.Shift:
|
|
19477
19604
|
playedBendPoints.push(new BendPoint(shiftSlideDurationOffset, 0));
|
|
19478
19605
|
// normal note values are in 1/2 tones, bends are in 1/4 tones
|
|
19479
|
-
const dy = (note.slideTarget.
|
|
19606
|
+
const dy = (note.slideTarget.calculateRealValue(this.applyTranspositionPitches, true) - note.calculateRealValue(this.applyTranspositionPitches, true)) * 2;
|
|
19480
19607
|
playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, dy));
|
|
19481
19608
|
break;
|
|
19482
19609
|
case SlideOutType.OutDown:
|
|
@@ -20015,6 +20142,7 @@ class TinySoundFont {
|
|
|
20015
20142
|
this._mutedChannels = new Map();
|
|
20016
20143
|
this._soloChannels = new Map();
|
|
20017
20144
|
this._isAnySolo = false;
|
|
20145
|
+
this._transpositionPitches = new Map();
|
|
20018
20146
|
this.currentTempo = 0;
|
|
20019
20147
|
this.timeSignatureNumerator = 0;
|
|
20020
20148
|
this.timeSignatureDenominator = 0;
|
|
@@ -20076,8 +20204,30 @@ class TinySoundFont {
|
|
|
20076
20204
|
resetChannelStates() {
|
|
20077
20205
|
this._mutedChannels = new Map();
|
|
20078
20206
|
this._soloChannels = new Map();
|
|
20207
|
+
this.applyTranspositionPitches(new Map());
|
|
20079
20208
|
this._isAnySolo = false;
|
|
20080
20209
|
}
|
|
20210
|
+
applyTranspositionPitches(transpositionPitches) {
|
|
20211
|
+
// dynamically adjust actively playing voices to the new pitch they have.
|
|
20212
|
+
// we are not updating the used preset and regions though.
|
|
20213
|
+
const previousTransposePitches = this._transpositionPitches;
|
|
20214
|
+
for (const voice of this._voices) {
|
|
20215
|
+
if (voice.playingChannel >= 0 && voice.playingChannel !== 9 /*percussion*/) {
|
|
20216
|
+
let pitchDifference = 0;
|
|
20217
|
+
if (previousTransposePitches.has(voice.playingChannel)) {
|
|
20218
|
+
pitchDifference -= previousTransposePitches.get(voice.playingChannel);
|
|
20219
|
+
}
|
|
20220
|
+
if (transpositionPitches.has(voice.playingChannel)) {
|
|
20221
|
+
pitchDifference += transpositionPitches.get(voice.playingChannel);
|
|
20222
|
+
}
|
|
20223
|
+
voice.playingKey += pitchDifference;
|
|
20224
|
+
if (this._channels) {
|
|
20225
|
+
voice.updatePitchRatio(this._channels.channelList[voice.playingChannel], this.outSampleRate);
|
|
20226
|
+
}
|
|
20227
|
+
}
|
|
20228
|
+
}
|
|
20229
|
+
this._transpositionPitches = transpositionPitches;
|
|
20230
|
+
}
|
|
20081
20231
|
dispatchEvent(synthEvent) {
|
|
20082
20232
|
this._midiEventQueue.enqueue(synthEvent);
|
|
20083
20233
|
}
|
|
@@ -20492,6 +20642,9 @@ class TinySoundFont {
|
|
|
20492
20642
|
if (!this._channels || channel > this._channels.channelList.length) {
|
|
20493
20643
|
return;
|
|
20494
20644
|
}
|
|
20645
|
+
if (this._transpositionPitches.has(channel)) {
|
|
20646
|
+
key += this._transpositionPitches.get(channel);
|
|
20647
|
+
}
|
|
20495
20648
|
this._channels.activeChannel = channel;
|
|
20496
20649
|
this.noteOn(this._channels.channelList[channel].presetIndex, key, vel);
|
|
20497
20650
|
}
|
|
@@ -20501,6 +20654,9 @@ class TinySoundFont {
|
|
|
20501
20654
|
* @param key note value between 0 and 127 (60 being middle C)
|
|
20502
20655
|
*/
|
|
20503
20656
|
channelNoteOff(channel, key) {
|
|
20657
|
+
if (this._transpositionPitches.has(channel)) {
|
|
20658
|
+
key += this._transpositionPitches.get(channel);
|
|
20659
|
+
}
|
|
20504
20660
|
const matches = [];
|
|
20505
20661
|
let matchFirst = null;
|
|
20506
20662
|
let matchLast = null;
|
|
@@ -20689,6 +20845,9 @@ class TinySoundFont {
|
|
|
20689
20845
|
* @param pitchWheel pitch wheel position 0 to 16383 (default 8192 unpitched)
|
|
20690
20846
|
*/
|
|
20691
20847
|
channelSetPerNotePitchWheel(channel, key, pitchWheel) {
|
|
20848
|
+
if (this._transpositionPitches.has(channel)) {
|
|
20849
|
+
key += this._transpositionPitches.get(channel);
|
|
20850
|
+
}
|
|
20692
20851
|
const c = this.channelInit(channel);
|
|
20693
20852
|
if (c.perNotePitchWheel.has(key) && c.perNotePitchWheel.get(key) === pitchWheel) {
|
|
20694
20853
|
return;
|
|
@@ -21486,6 +21645,9 @@ class AlphaSynth {
|
|
|
21486
21645
|
this.midiLoadFailed.trigger(e);
|
|
21487
21646
|
}
|
|
21488
21647
|
}
|
|
21648
|
+
applyTranspositionPitches(transpositionPitches) {
|
|
21649
|
+
this._synthesizer.applyTranspositionPitches(transpositionPitches);
|
|
21650
|
+
}
|
|
21489
21651
|
setChannelMute(channel, mute) {
|
|
21490
21652
|
this._synthesizer.channelSetMute(channel, mute);
|
|
21491
21653
|
}
|
|
@@ -23174,6 +23336,9 @@ class AlphaSynthWebWorker {
|
|
|
23174
23336
|
cmd: 'alphaSynth.destroyed'
|
|
23175
23337
|
});
|
|
23176
23338
|
break;
|
|
23339
|
+
case 'alphaSynth.applyTranspositionPitches':
|
|
23340
|
+
this._player.applyTranspositionPitches(new Map(JSON.parse(data.transpositionPitches)));
|
|
23341
|
+
break;
|
|
23177
23342
|
}
|
|
23178
23343
|
}
|
|
23179
23344
|
onPositionChanged(e) {
|
|
@@ -24963,6 +25128,7 @@ class AlphaTabApiBase {
|
|
|
24963
25128
|
* Applies any changes that were done to the settings object and informs the {@link renderer} about any new values to consider.
|
|
24964
25129
|
*/
|
|
24965
25130
|
updateSettings() {
|
|
25131
|
+
var _a;
|
|
24966
25132
|
const score = this.score;
|
|
24967
25133
|
if (score) {
|
|
24968
25134
|
ModelUtils.applyPitchOffsets(this.settings, score);
|
|
@@ -24971,6 +25137,9 @@ class AlphaTabApiBase {
|
|
|
24971
25137
|
// enable/disable player if needed
|
|
24972
25138
|
if (this.settings.player.enablePlayer) {
|
|
24973
25139
|
this.setupPlayer();
|
|
25140
|
+
if (score) {
|
|
25141
|
+
(_a = this.player) === null || _a === void 0 ? void 0 : _a.applyTranspositionPitches(MidiFileGenerator.buildTranspositionPitches(score, this.settings));
|
|
25142
|
+
}
|
|
24974
25143
|
}
|
|
24975
25144
|
else {
|
|
24976
25145
|
this.destroyPlayer();
|
|
@@ -25341,10 +25510,13 @@ class AlphaTabApiBase {
|
|
|
25341
25510
|
let midiFile = new MidiFile();
|
|
25342
25511
|
let handler = new AlphaSynthMidiFileHandler(midiFile);
|
|
25343
25512
|
let generator = new MidiFileGenerator(this.score, this.settings, handler);
|
|
25513
|
+
// we pass the transposition pitches separately to alphaSynth.
|
|
25514
|
+
generator.applyTranspositionPitches = false;
|
|
25344
25515
|
generator.generate();
|
|
25345
25516
|
this._tickCache = generator.tickLookup;
|
|
25346
25517
|
this.onMidiLoad(midiFile);
|
|
25347
25518
|
this.player.loadMidiFile(midiFile);
|
|
25519
|
+
this.player.applyTranspositionPitches(generator.transpositionPitches);
|
|
25348
25520
|
}
|
|
25349
25521
|
/**
|
|
25350
25522
|
* Changes the volume of the given tracks.
|
|
@@ -27018,6 +27190,12 @@ class AlphaSynthWebWorkerApi {
|
|
|
27018
27190
|
midi: JsonConverter.midiFileToJsObject(midi)
|
|
27019
27191
|
});
|
|
27020
27192
|
}
|
|
27193
|
+
applyTranspositionPitches(transpositionPitches) {
|
|
27194
|
+
this._synth.postMessage({
|
|
27195
|
+
cmd: 'alphaSynth.applyTranspositionPitches',
|
|
27196
|
+
transpositionPitches: JSON.stringify(Array.from(transpositionPitches.entries()))
|
|
27197
|
+
});
|
|
27198
|
+
}
|
|
27021
27199
|
setChannelMute(channel, mute) {
|
|
27022
27200
|
this._synth.postMessage({
|
|
27023
27201
|
cmd: 'alphaSynth.setChannelMute',
|
|
@@ -42315,8 +42493,8 @@ class CoreSettings {
|
|
|
42315
42493
|
// </auto-generated>
|
|
42316
42494
|
class VersionInfo {
|
|
42317
42495
|
}
|
|
42318
|
-
VersionInfo.version = '1.3.0-alpha.
|
|
42319
|
-
VersionInfo.date = '2023-12-
|
|
42496
|
+
VersionInfo.version = '1.3.0-alpha.856';
|
|
42497
|
+
VersionInfo.date = '2023-12-12T01:25:35.593Z';
|
|
42320
42498
|
|
|
42321
42499
|
var index$5 = /*#__PURE__*/Object.freeze({
|
|
42322
42500
|
__proto__: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderline/alphatab",
|
|
3
|
-
"version": "1.3.0-alpha.
|
|
3
|
+
"version": "1.3.0-alpha.856",
|
|
4
4
|
"description": "alphaTab is a music notation and guitar tablature rendering library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"guitar",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"rollup-plugin-dts": "^6.1.0",
|
|
81
81
|
"rollup-plugin-license": "^3.2.0",
|
|
82
82
|
"terser": "^5.24.0",
|
|
83
|
-
"tsx": "^
|
|
83
|
+
"tsx": "^4.6.2",
|
|
84
84
|
"typescript": "^5.2.2"
|
|
85
85
|
},
|
|
86
86
|
"files": [
|