@coderline/alphatab
Version:
alphaTab is a music notation and guitar tablature rendering library
1,573 lines (1,552 loc) • 2.64 MB
JavaScript
/*!
* alphaTab v1.6.3 (, build 22)
*
* Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Integrated Libraries:
*
* Library: TinySoundFont
* License: MIT
* Copyright: Copyright (C) 2017, 2018 Bernhard Schelling
* URL: https://github.com/schellingb/TinySoundFont
* Purpose: SoundFont loading and Audio Synthesis
*
* Library: SFZero
* License: MIT
* Copyright: Copyright (C) 2012 Steve Folta ()
* URL: https://github.com/stevefolta/SFZero
* Purpose: TinySoundFont is based on SFZEro
*
* Library: Haxe Standard Library
* License: MIT
* Copyright: Copyright (C)2005-2025 Haxe Foundation
* URL: https://github.com/HaxeFoundation/haxe/tree/development/std
* Purpose: XML Parser & Zip Inflate Algorithm
*
* Library: SharpZipLib
* License: MIT
* Copyright: Copyright © 2000-2018 SharpZipLib Contributors
* URL: https://github.com/icsharpcode/SharpZipLib
* Purpose: Zip Deflate Algorithm for writing compressed Zips
*
* Library: NVorbis
* License: MIT
* Copyright: Copyright (c) 2020 Andrew Ward
* URL: https://github.com/NVorbis/NVorbis
* Purpose: Vorbis Stream Decoding
*
* Library: libvorbis
* License: BSD-3-Clause
* Copyright: Copyright (c) 2002-2020 Xiph.org Foundation
* URL: https://github.com/xiph/vorbis
* Purpose: NVorbis adopted some code from libvorbis.
*
* @preserve
* @license
*/
/**
* A very basic polyfill of the ResizeObserver which triggers
* a the callback on window resize for all registered targets.
* @target web
*/
class ResizeObserverPolyfill {
constructor(callback) {
this._targets = new Set();
this._callback = callback;
window.addEventListener('resize', this.onWindowResize.bind(this), false);
}
observe(target) {
this._targets.add(target);
}
unobserve(target) {
this._targets.delete(target);
}
disconnect() {
this._targets.clear();
}
onWindowResize() {
const entries = [];
for (const t of this._targets) {
entries.push({
target: t,
// not used by alphaTab
contentRect: undefined,
borderBoxSize: undefined,
contentBoxSize: [],
devicePixelContentBoxSize: []
});
}
this._callback(entries, this);
}
}
/**
* A polyfill of the InsersectionObserver
* @target web
*/
class IntersectionObserverPolyfill {
constructor(callback) {
this._elements = [];
let timer = null;
const oldCheck = this.check.bind(this);
this.check = () => {
if (!timer) {
timer = setTimeout(() => {
oldCheck();
timer = null;
}, 100);
}
};
this._callback = callback;
window.addEventListener('resize', this.check, true);
document.addEventListener('scroll', this.check, true);
}
observe(target) {
if (this._elements.indexOf(target) >= 0) {
return;
}
this._elements.push(target);
this.check();
}
unobserve(target) {
this._elements = this._elements.filter(item => {
return item !== target;
});
}
check() {
const entries = [];
for (const element of this._elements) {
const rect = element.getBoundingClientRect();
const isVisible = rect.top + rect.height >= 0 &&
rect.top <= window.innerHeight &&
rect.left + rect.width >= 0 &&
rect.left <= window.innerWidth;
if (isVisible) {
entries.push({
target: element,
isIntersecting: true
});
}
}
if (entries.length) {
this._callback(entries, this);
}
}
}
/*@target web*/
(() => {
if (typeof Symbol.dispose === 'undefined') {
Symbol.dispose = Symbol('Symbol.dispose');
}
if (typeof window !== 'undefined') {
// ResizeObserver API does not yet exist so long on Safari (only start 2020 with iOS Safari 13.7 and Desktop 13.1)
// so we better add a polyfill for it
if (!('ResizeObserver' in globalThis)) {
globalThis.ResizeObserver = ResizeObserverPolyfill;
}
// IntersectionObserver API does not on older iOS versions
// so we better add a polyfill for it
if (!('IntersectionObserver' in globalThis)) {
globalThis.IntersectionObserver = IntersectionObserverPolyfill;
}
if (!('replaceChildren' in Element.prototype)) {
Element.prototype.replaceChildren = function (...nodes) {
this.innerHTML = '';
this.append(...nodes);
};
Document.prototype.replaceChildren = Element.prototype.replaceChildren;
DocumentFragment.prototype.replaceChildren = Element.prototype.replaceChildren;
}
}
if (!('replaceAll' in String.prototype)) {
String.prototype.replaceAll = function (str, newStr) {
return this.replace(new RegExp(str, 'g'), newStr);
};
}
})();
/**
* Lists all layout modes that are supported.
*/
var LayoutMode;
(function (LayoutMode) {
/**
* The bars are aligned in an [vertically endless page-style fashion](https://alphatab.net/docs/showcase/layouts#page-layout)
*/
LayoutMode[LayoutMode["Page"] = 0] = "Page";
/**
* Bars are aligned horizontally in [one horizontally endless system (row)](https://alphatab.net/docs/showcase/layouts#horizontal-layout)
*/
LayoutMode[LayoutMode["Horizontal"] = 1] = "Horizontal";
})(LayoutMode || (LayoutMode = {}));
/**
* Lists all stave profiles controlling which staves are shown.
*/
var StaveProfile;
(function (StaveProfile) {
/**
* The profile is auto detected by the track configurations.
*/
StaveProfile[StaveProfile["Default"] = 0] = "Default";
/**
* Standard music notation and guitar tablature are rendered.
*/
StaveProfile[StaveProfile["ScoreTab"] = 1] = "ScoreTab";
/**
* Only standard music notation is rendered.
*/
StaveProfile[StaveProfile["Score"] = 2] = "Score";
/**
* Only guitar tablature is rendered.
*/
StaveProfile[StaveProfile["Tab"] = 3] = "Tab";
/**
* Only guitar tablature is rendered, but also rests and time signatures are not shown.
* This profile is typically used in multi-track scenarios.
*/
StaveProfile[StaveProfile["TabMixed"] = 4] = "TabMixed";
})(StaveProfile || (StaveProfile = {}));
/**
* This public class provides names for all general midi instruments.
*/
class GeneralMidi {
static getValue(name) {
if (!GeneralMidi._values) {
GeneralMidi._values = new Map();
}
name = name.toLowerCase().replaceAll(' ', '');
return GeneralMidi._values.has(name) ? GeneralMidi._values.get(name) : 0;
}
static isPiano(program) {
return program <= 7 || (program >= 16 && program <= 23);
}
static isGuitar(program) {
return (program >= 24 && program <= 39) || program === 105 || program === 43;
}
}
GeneralMidi._values = new Map([
['acousticgrandpiano', 0],
['brightacousticpiano', 1],
['electricgrandpiano', 2],
['honkytonkpiano', 3],
['electricpiano1', 4],
['electricpiano2', 5],
['harpsichord', 6],
['clavinet', 7],
['celesta', 8],
['glockenspiel', 9],
['musicbox', 10],
['vibraphone', 11],
['marimba', 12],
['xylophone', 13],
['tubularbells', 14],
['dulcimer', 15],
['drawbarorgan', 16],
['percussiveorgan', 17],
['rockorgan', 18],
['churchorgan', 19],
['reedorgan', 20],
['accordion', 21],
['harmonica', 22],
['tangoaccordion', 23],
['acousticguitarnylon', 24],
['acousticguitarsteel', 25],
['electricguitarjazz', 26],
['electricguitarclean', 27],
['electricguitarmuted', 28],
['overdrivenguitar', 29],
['distortionguitar', 30],
['guitarharmonics', 31],
['acousticbass', 32],
['electricbassfinger', 33],
['electricbasspick', 34],
['fretlessbass', 35],
['slapbass1', 36],
['slapbass2', 37],
['synthbass1', 38],
['synthbass2', 39],
['violin', 40],
['viola', 41],
['cello', 42],
['contrabass', 43],
['tremolostrings', 44],
['pizzicatostrings', 45],
['orchestralharp', 46],
['timpani', 47],
['stringensemble1', 48],
['stringensemble2', 49],
['synthstrings1', 50],
['synthstrings2', 51],
['choiraahs', 52],
['voiceoohs', 53],
['synthvoice', 54],
['orchestrahit', 55],
['trumpet', 56],
['trombone', 57],
['tuba', 58],
['mutedtrumpet', 59],
['frenchhorn', 60],
['brasssection', 61],
['synthbrass1', 62],
['synthbrass2', 63],
['sopranosax', 64],
['altosax', 65],
['tenorsax', 66],
['baritonesax', 67],
['oboe', 68],
['englishhorn', 69],
['bassoon', 70],
['clarinet', 71],
['piccolo', 72],
['flute', 73],
['recorder', 74],
['panflute', 75],
['blownbottle', 76],
['shakuhachi', 77],
['whistle', 78],
['ocarina', 79],
['lead1square', 80],
['lead2sawtooth', 81],
['lead3calliope', 82],
['lead4chiff', 83],
['lead5charang', 84],
['lead6voice', 85],
['lead7fifths', 86],
['lead8bassandlead', 87],
['pad1newage', 88],
['pad2warm', 89],
['pad3polysynth', 90],
['pad4choir', 91],
['pad5bowed', 92],
['pad6metallic', 93],
['pad7halo', 94],
['pad8sweep', 95],
['fx1rain', 96],
['fx2soundtrack', 97],
['fx3crystal', 98],
['fx4atmosphere', 99],
['fx5brightness', 100],
['fx6goblins', 101],
['fx7echoes', 102],
['fx8scifi', 103],
['sitar', 104],
['banjo', 105],
['shamisen', 106],
['koto', 107],
['kalimba', 108],
['bagpipe', 109],
['fiddle', 110],
['shanai', 111],
['tinklebell', 112],
['agogo', 113],
['steeldrums', 114],
['woodblock', 115],
['taikodrum', 116],
['melodictom', 117],
['synthdrum', 118],
['reversecymbal', 119],
['guitarfretnoise', 120],
['breathnoise', 121],
['seashore', 122],
['birdtweet', 123],
['telephonering', 124],
['helicopter', 125],
['applause', 126],
['gunshot', 127]
]);
/**
* Lists the different modes on how the brackets/braces are drawn and extended.
*/
var BracketExtendMode;
(function (BracketExtendMode) {
/**
* Do not draw brackets
*/
BracketExtendMode[BracketExtendMode["NoBrackets"] = 0] = "NoBrackets";
/**
* Groups staves into bracket (or braces for grand staff).
*/
BracketExtendMode[BracketExtendMode["GroupStaves"] = 1] = "GroupStaves";
/**
* Groups similar instruments in multi-track rendering into brackets.
* The braces of tracks with grand-staffs break any brackets.
* Similar instruments means actually the same "midi program". No custom grouping is currently done.
*/
BracketExtendMode[BracketExtendMode["GroupSimilarInstruments"] = 2] = "GroupSimilarInstruments";
})(BracketExtendMode || (BracketExtendMode = {}));
/**
* Lists the different policies on how to display the track names.
*/
var TrackNamePolicy;
(function (TrackNamePolicy) {
/**
* Track names are hidden everywhere.
*/
TrackNamePolicy[TrackNamePolicy["Hidden"] = 0] = "Hidden";
/**
* Track names are displayed on the first system.
*/
TrackNamePolicy[TrackNamePolicy["FirstSystem"] = 1] = "FirstSystem";
/**
* Track names are displayed on all systems.
*/
TrackNamePolicy[TrackNamePolicy["AllSystems"] = 2] = "AllSystems";
})(TrackNamePolicy || (TrackNamePolicy = {}));
/**
* Lists the different modes what text to display for track names.
*/
var TrackNameMode;
(function (TrackNameMode) {
/**
* Full track names are displayed {@link Track.name}
*/
TrackNameMode[TrackNameMode["FullName"] = 0] = "FullName";
/**
* Short Track names (abbreviations) are displayed {@link Track.shortName}
*/
TrackNameMode[TrackNameMode["ShortName"] = 1] = "ShortName";
})(TrackNameMode || (TrackNameMode = {}));
/**
* Lists the different orientations modes how to render the track names.
*/
var TrackNameOrientation;
(function (TrackNameOrientation) {
/**
* Text is shown horizontally (left-to-right)
*/
TrackNameOrientation[TrackNameOrientation["Horizontal"] = 0] = "Horizontal";
/**
* Vertically rotated (bottom-to-top)
*/
TrackNameOrientation[TrackNameOrientation["Vertical"] = 1] = "Vertical";
})(TrackNameOrientation || (TrackNameOrientation = {}));
/**
* This class represents the rendering stylesheet.
* It contains settings which control the display of the score when rendered.
* @json
* @json_strict
*/
class RenderStylesheet {
constructor() {
/**
* Whether dynamics are hidden.
*/
this.hideDynamics = false;
/**
* The mode in which brackets and braces are drawn.
*/
this.bracketExtendMode = BracketExtendMode.GroupStaves;
/**
* Whether to draw the // sign to separate systems.
*/
this.useSystemSignSeparator = false;
/**
* Whether to show the tuning.
*/
this.globalDisplayTuning = true;
/**
* Whether to show the tuning.(per-track)
*/
this.perTrackDisplayTuning = null;
/**
* Whether to show the chord diagrams on top.
*/
this.globalDisplayChordDiagramsOnTop = true;
/**
* Whether to show the chord diagrams on top. (per-track)
*/
this.perTrackChordDiagramsOnTop = null;
/**
* The policy where to show track names when a single track is rendered.
*/
this.singleTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
/**
* The policy where to show track names when a multiple tracks are rendered.
*/
this.multiTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
/**
* The mode what text to display for the track name on the first system
*/
this.firstSystemTrackNameMode = TrackNameMode.ShortName;
/**
* The mode what text to display for the track name on the first system
*/
this.otherSystemsTrackNameMode = TrackNameMode.ShortName;
/**
* The orientation of the the track names on the first system
*/
this.firstSystemTrackNameOrientation = TrackNameOrientation.Vertical;
/**
* The orientation of the the track names on other systems
*/
this.otherSystemsTrackNameOrientation = TrackNameOrientation.Vertical;
/**
* If multi track: Whether to render multiple subsequent empty (or rest-only) bars together as multi-bar rest.
*/
this.multiTrackMultiBarRest = false;
/**
* If single track: Whether to render multiple subsequent empty (or rest-only) bars together as multi-bar rest.
*/
this.perTrackMultiBarRest = null;
}
}
/**
* This public class can store the information about a group of measures which are repeated
*/
class RepeatGroup {
constructor() {
/**
* All masterbars repeated within this group
*/
this.masterBars = [];
/**
* the masterbars which opens the group.
*/
this.opening = null;
/**
* a list of masterbars which close the group.
*/
this.closings = [];
/**
* true if the repeat group was closed well
*/
this.isClosed = false;
}
/**
* a list of masterbars which open the group.
* @deprecated There can only be one opening, use the opening property instead
*/
get openings() {
const opening = this.opening;
return opening ? [opening] : [];
}
/**
* Gets whether this repeat group is really opened as a repeat.
*/
get isOpened() {
return this.opening?.isRepeatStart === true;
}
addMasterBar(masterBar) {
if (this.opening === null) {
this.opening = masterBar;
}
this.masterBars.push(masterBar);
masterBar.repeatGroup = this;
if (masterBar.isRepeatEnd) {
this.closings.push(masterBar);
this.isClosed = true;
}
}
}
/**
* Defines the custom styles for an element in the music sheet (like bars, voices, notes etc).
*/
class ElementStyle {
constructor() {
/**
* Changes the color of the specified sub-element within the element this style container belongs to.
* Null indicates that a certain element should use the default color from {@link RenderingResources}
* even if some "higher level" element changes colors.
*/
this.colors = new Map();
// TODO: replace NotationSettings.elements by adding a visibility here?
}
}
/**
* This public enumeration lists all supported Clefs.
*/
var Clef;
(function (Clef) {
/**
* Neutral clef.
*/
Clef[Clef["Neutral"] = 0] = "Neutral";
/**
* C3 clef
*/
Clef[Clef["C3"] = 1] = "C3";
/**
* C4 clef
*/
Clef[Clef["C4"] = 2] = "C4";
/**
* F4 clef
*/
Clef[Clef["F4"] = 3] = "F4";
/**
* G2 clef
*/
Clef[Clef["G2"] = 4] = "G2";
})(Clef || (Clef = {}));
/**
* Lists all ottavia.
*/
var Ottavia;
(function (Ottavia) {
/**
* 2 octaves higher
*/
Ottavia[Ottavia["_15ma"] = 0] = "_15ma";
/**
* 1 octave higher
*/
Ottavia[Ottavia["_8va"] = 1] = "_8va";
/**
* Normal
*/
Ottavia[Ottavia["Regular"] = 2] = "Regular";
/**
* 1 octave lower
*/
Ottavia[Ottavia["_8vb"] = 3] = "_8vb";
/**
* 2 octaves lower.
*/
Ottavia[Ottavia["_15mb"] = 4] = "_15mb";
})(Ottavia || (Ottavia = {}));
/**
* Lists all simile mark types as they are assigned to bars.
*/
var SimileMark;
(function (SimileMark) {
/**
* No simile mark is applied
*/
SimileMark[SimileMark["None"] = 0] = "None";
/**
* A simple simile mark. The previous bar is repeated.
*/
SimileMark[SimileMark["Simple"] = 1] = "Simple";
/**
* A double simile mark. This value is assigned to the first
* bar of the 2 repeat bars.
*/
SimileMark[SimileMark["FirstOfDouble"] = 2] = "FirstOfDouble";
/**
* A double simile mark. This value is assigned to the second
* bar of the 2 repeat bars.
*/
SimileMark[SimileMark["SecondOfDouble"] = 3] = "SecondOfDouble";
})(SimileMark || (SimileMark = {}));
/**
* This public enumeration lists all available key signatures
*/
var KeySignature;
(function (KeySignature) {
/**
* Cb (7 flats)
*/
KeySignature[KeySignature["Cb"] = -7] = "Cb";
/**
* Gb (6 flats)
*/
KeySignature[KeySignature["Gb"] = -6] = "Gb";
/**
* Db (5 flats)
*/
KeySignature[KeySignature["Db"] = -5] = "Db";
/**
* Ab (4 flats)
*/
KeySignature[KeySignature["Ab"] = -4] = "Ab";
/**
* Eb (3 flats)
*/
KeySignature[KeySignature["Eb"] = -3] = "Eb";
/**
* Bb (2 flats)
*/
KeySignature[KeySignature["Bb"] = -2] = "Bb";
/**
* F (1 flat)
*/
KeySignature[KeySignature["F"] = -1] = "F";
/**
* C (no signs)
*/
KeySignature[KeySignature["C"] = 0] = "C";
/**
* G (1 sharp)
*/
KeySignature[KeySignature["G"] = 1] = "G";
/**
* D (2 sharp)
*/
KeySignature[KeySignature["D"] = 2] = "D";
/**
* A (3 sharp)
*/
KeySignature[KeySignature["A"] = 3] = "A";
/**
* E (4 sharp)
*/
KeySignature[KeySignature["E"] = 4] = "E";
/**
* B (5 sharp)
*/
KeySignature[KeySignature["B"] = 5] = "B";
/**
* F# (6 sharp)
*/
KeySignature[KeySignature["FSharp"] = 6] = "FSharp";
/**
* C# (7 sharp)
*/
KeySignature[KeySignature["CSharp"] = 7] = "CSharp";
})(KeySignature || (KeySignature = {}));
/**
* This public enumeration lists all available types of KeySignatures
*/
var KeySignatureType;
(function (KeySignatureType) {
/**
* Major
*/
KeySignatureType[KeySignatureType["Major"] = 0] = "Major";
/**
* Minor
*/
KeySignatureType[KeySignatureType["Minor"] = 1] = "Minor";
})(KeySignatureType || (KeySignatureType = {}));
/**
* The different pedal marker types.
*/
var SustainPedalMarkerType;
(function (SustainPedalMarkerType) {
/**
* Indicates that the pedal should be pressed from this time on.
*/
SustainPedalMarkerType[SustainPedalMarkerType["Down"] = 0] = "Down";
/**
* Indicates that the pedal should be held on this marker (used when the pedal is held for the whole bar)
*/
SustainPedalMarkerType[SustainPedalMarkerType["Hold"] = 1] = "Hold";
/**
* indicates that the pedal should be lifted up at this time.
*/
SustainPedalMarkerType[SustainPedalMarkerType["Up"] = 2] = "Up";
})(SustainPedalMarkerType || (SustainPedalMarkerType = {}));
/**
* A marker on whether a sustain pedal starts or ends.
* @json
* @json_strict
*/
class SustainPedalMarker {
constructor() {
/**
* The relative position of pedal markers within the bar.
*/
this.ratioPosition = 0;
/**
* Whether what should be done with the pedal at this point
*/
this.pedalType = SustainPedalMarkerType.Down;
/**
* The next pedal marker for linking the related markers together to a "down -> hold -> up" or "down -> up" sequence.
* Always null for "up" markers.
* @json_ignore
*/
this.nextPedalMarker = null;
/**
* The previous pedal marker for linking the related markers together to a "down -> hold -> up" or "down -> up" sequence.
* Always null for "down" markers.
* @json_ignore
*/
this.previousPedalMarker = null;
}
}
/**
* Lists all graphical sub elements within a {@link Bar} which can be styled via {@link Bar.style}
*/
var BarSubElement;
(function (BarSubElement) {
/**
* The repeat signs on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationRepeats"] = 0] = "StandardNotationRepeats";
/**
* The repeat signs on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsRepeats"] = 1] = "GuitarTabsRepeats";
/**
* The repeat signs on the slash staff.
*/
BarSubElement[BarSubElement["SlashRepeats"] = 2] = "SlashRepeats";
/**
* The repeat signs on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedRepeats"] = 3] = "NumberedRepeats";
/**
* The bar numbers on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationBarNumber"] = 4] = "StandardNotationBarNumber";
/**
* The bar numbers on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsBarNumber"] = 5] = "GuitarTabsBarNumber";
/**
* The bar numbers on the slash staff.
*/
BarSubElement[BarSubElement["SlashBarNumber"] = 6] = "SlashBarNumber";
/**
* The bar numbers on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedBarNumber"] = 7] = "NumberedBarNumber";
/**
* The bar lines on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationBarLines"] = 8] = "StandardNotationBarLines";
/**
* The bar lines on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsBarLines"] = 9] = "GuitarTabsBarLines";
/**
* The bar lines on the slash staff.
*/
BarSubElement[BarSubElement["SlashBarLines"] = 10] = "SlashBarLines";
/**
* The bar lines on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedBarLines"] = 11] = "NumberedBarLines";
/**
* The clefs on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationClef"] = 12] = "StandardNotationClef";
/**
* The clefs on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsClef"] = 13] = "GuitarTabsClef";
/**
* The key signatures on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationKeySignature"] = 14] = "StandardNotationKeySignature";
/**
* The key signatures on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedKeySignature"] = 15] = "NumberedKeySignature";
/**
* The time signatures on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationTimeSignature"] = 16] = "StandardNotationTimeSignature";
/**
* The time signatures on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsTimeSignature"] = 17] = "GuitarTabsTimeSignature";
/**
* The time signatures on the slash staff.
*/
BarSubElement[BarSubElement["SlashTimeSignature"] = 18] = "SlashTimeSignature";
/**
* The time signature on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedTimeSignature"] = 19] = "NumberedTimeSignature";
/**
* The staff lines on the standard notation staff.
*/
BarSubElement[BarSubElement["StandardNotationStaffLine"] = 20] = "StandardNotationStaffLine";
/**
* The staff lines on the guitar tab staff.
*/
BarSubElement[BarSubElement["GuitarTabsStaffLine"] = 21] = "GuitarTabsStaffLine";
/**
* The staff lines on the slash staff.
*/
BarSubElement[BarSubElement["SlashStaffLine"] = 22] = "SlashStaffLine";
/**
* The staff lines on the numbered notation staff.
*/
BarSubElement[BarSubElement["NumberedStaffLine"] = 23] = "NumberedStaffLine";
})(BarSubElement || (BarSubElement = {}));
/**
* Defines the custom styles for bars.
* @json
* @json_strict
*/
class BarStyle extends ElementStyle {
}
/**
* Lists all bar line styles.
*/
var BarLineStyle;
(function (BarLineStyle) {
/**
* No special custom line style, automatic handling (e.g. last bar might be LightHeavy)
*/
BarLineStyle[BarLineStyle["Automatic"] = 0] = "Automatic";
BarLineStyle[BarLineStyle["Dashed"] = 1] = "Dashed";
BarLineStyle[BarLineStyle["Dotted"] = 2] = "Dotted";
BarLineStyle[BarLineStyle["Heavy"] = 3] = "Heavy";
BarLineStyle[BarLineStyle["HeavyHeavy"] = 4] = "HeavyHeavy";
BarLineStyle[BarLineStyle["HeavyLight"] = 5] = "HeavyLight";
BarLineStyle[BarLineStyle["LightHeavy"] = 6] = "LightHeavy";
BarLineStyle[BarLineStyle["LightLight"] = 7] = "LightLight";
BarLineStyle[BarLineStyle["None"] = 8] = "None";
BarLineStyle[BarLineStyle["Regular"] = 9] = "Regular";
BarLineStyle[BarLineStyle["Short"] = 10] = "Short";
BarLineStyle[BarLineStyle["Tick"] = 11] = "Tick";
})(BarLineStyle || (BarLineStyle = {}));
/**
* A bar is a single block within a track, also known as Measure.
* @json
* @json_strict
*/
class Bar {
constructor() {
/**
* Gets or sets the unique id of this bar.
*/
this.id = Bar._globalBarId++;
/**
* Gets or sets the zero-based index of this bar within the staff.
* @json_ignore
*/
this.index = 0;
/**
* Gets or sets the next bar that comes after this bar.
* @json_ignore
*/
this.nextBar = null;
/**
* Gets or sets the previous bar that comes before this bar.
* @json_ignore
*/
this.previousBar = null;
/**
* Gets or sets the clef on this bar.
*/
this.clef = Clef.G2;
/**
* Gets or sets the ottava applied to the clef.
*/
this.clefOttava = Ottavia.Regular;
/**
* Gets or sets the list of voices contained in this bar.
* @json_add addVoice
*/
this.voices = [];
/**
* Gets or sets the simile mark on this bar.
*/
this.simileMark = SimileMark.None;
/**
* Gets a value indicating whether this bar contains multiple voices with notes.
* @json_ignore
*/
this.isMultiVoice = false;
/**
* A relative scale for the size of the bar when displayed. The scale is relative
* within a single line (system). The sum of all scales in one line make the total width,
* and then this individual scale gives the relative size.
*/
this.displayScale = 1;
/**
* An absolute width of the bar to use when displaying in single track display scenarios.
*/
this.displayWidth = -1;
/**
* The sustain pedal markers within this bar.
*/
this.sustainPedals = [];
this._isEmpty = true;
this._isRestOnly = true;
/**
* The bar line to draw on the left side of the bar.
* @remarks
* Note that the combination with {@link barLineRight} of the previous bar matters.
* If this bar has a Regular/Automatic style but the previous bar is customized, no additional line is drawn by this bar.
* If both bars have a custom style, both bar styles are drawn.
*/
this.barLineLeft = BarLineStyle.Automatic;
/**
* The bar line to draw on the right side of the bar.
* @remarks
* Note that the combination with {@link barLineLeft} of the next bar matters.
* If this bar has a Regular/Automatic style but the next bar is customized, no additional line is drawn by this bar.
* If both bars have a custom style, both bar styles are drawn.
*/
this.barLineRight = BarLineStyle.Automatic;
/**
* Gets or sets the key signature used on all bars.
*/
this.keySignature = KeySignature.C;
/**
* Gets or sets the type of key signature (major/minor)
*/
this.keySignatureType = KeySignatureType.Major;
}
/**
* @internal
*/
static resetIds() {
Bar._globalBarId = 0;
}
get masterBar() {
return this.staff.track.score.masterBars[this.index];
}
/**
* Whether this bar is fully empty (not even having rests).
*/
get isEmpty() {
return this._isEmpty;
}
/**
* Whether this bar has any changes applied which are not related to the voices in it.
* (e.g. new key signatures)
*/
get hasChanges() {
if (this.index === 0) {
return true;
}
const hasChangesToPrevious = this.keySignature !== this.previousBar.keySignature ||
this.keySignatureType !== this.previousBar.keySignatureType ||
this.clef !== this.previousBar.clef ||
this.clefOttava !== this.previousBar.clefOttava;
if (hasChangesToPrevious) {
return true;
}
return (this.simileMark !== SimileMark.None ||
this.sustainPedals.length > 0 ||
this.barLineLeft !== BarLineStyle.Automatic ||
this.barLineRight !== BarLineStyle.Automatic);
}
/**
* Whether this bar is empty or has only rests.
*/
get isRestOnly() {
return this._isRestOnly;
}
/**
* The bar line to draw on the left side of the bar with an "automatic" type resolved to the actual one.
* @param isFirstOfSystem Whether the bar is the first one in the system.
*/
getActualBarLineLeft(isFirstOfSystem) {
return Bar.actualBarLine(this, false, isFirstOfSystem);
}
/**
* The bar line to draw on the right side of the bar with an "automatic" type resolved to the actual one.
* @param isFirstOfSystem Whether the bar is the first one in the system.
*/
getActualBarLineRight() {
return Bar.actualBarLine(this, true, false /* not relevant */);
}
static automaticToActualType(masterBar, isRight, firstOfSystem) {
let actualLineType;
if (isRight) {
if (masterBar.isRepeatEnd) {
actualLineType = BarLineStyle.LightHeavy;
}
else if (!masterBar.nextMasterBar) {
actualLineType = BarLineStyle.LightHeavy;
}
else if (masterBar.isFreeTime) {
actualLineType = BarLineStyle.Dashed;
}
else if (masterBar.isDoubleBar) {
actualLineType = BarLineStyle.LightLight;
}
else {
actualLineType = BarLineStyle.Regular;
}
}
else {
if (masterBar.isRepeatStart) {
actualLineType = BarLineStyle.HeavyLight;
}
else if (firstOfSystem) {
actualLineType = BarLineStyle.Regular;
}
else {
actualLineType = BarLineStyle.None;
}
}
return actualLineType;
}
static actualBarLine(bar, isRight, firstOfSystem) {
const masterBar = bar.masterBar;
const requestedLineType = isRight ? bar.barLineRight : bar.barLineLeft;
let actualLineType;
if (requestedLineType === BarLineStyle.Automatic) {
actualLineType = Bar.automaticToActualType(masterBar, isRight, firstOfSystem);
}
else {
actualLineType = requestedLineType;
}
return actualLineType;
}
addVoice(voice) {
voice.bar = this;
voice.index = this.voices.length;
this.voices.push(voice);
}
finish(settings, sharedDataBag = null) {
this.isMultiVoice = false;
this._isEmpty = true;
this._isRestOnly = true;
for (let i = 0, j = this.voices.length; i < j; i++) {
const voice = this.voices[i];
voice.finish(settings, sharedDataBag);
if (i > 0 && !voice.isEmpty) {
this.isMultiVoice = true;
}
if (!voice.isEmpty) {
this._isEmpty = false;
}
if (!voice.isRestOnly) {
this._isRestOnly = false;
}
}
// chain sustain pedal markers (and merge overlaps)
const sustainPedals = this.sustainPedals;
if (sustainPedals.length > 0) {
let previousMarker = null;
this.sustainPedals = [];
if (this.previousBar && this.previousBar.sustainPedals.length > 0) {
previousMarker = this.previousBar.sustainPedals[this.previousBar.sustainPedals.length - 1];
}
const isDown = previousMarker !== null && previousMarker.pedalType !== SustainPedalMarkerType.Up;
for (const marker of sustainPedals) {
if (previousMarker && previousMarker.pedalType !== SustainPedalMarkerType.Up) {
//duplicate or out-of-order markers
if (previousMarker.bar === this && marker.ratioPosition <= previousMarker.ratioPosition) {
continue;
}
previousMarker.nextPedalMarker = marker;
marker.previousPedalMarker = previousMarker;
}
if (isDown && marker.pedalType === SustainPedalMarkerType.Down) {
marker.pedalType = SustainPedalMarkerType.Hold;
}
marker.bar = this;
this.sustainPedals.push(marker);
previousMarker = marker;
}
}
else if (this.previousBar && this.previousBar.sustainPedals.length > 0) {
const lastMarker = this.previousBar.sustainPedals[this.previousBar.sustainPedals.length - 1];
if (lastMarker.pedalType !== SustainPedalMarkerType.Up) {
// create hold marker if the last marker on the previous bar is not "up"
const holdMarker = new SustainPedalMarker();
holdMarker.ratioPosition = 0;
holdMarker.bar = this;
holdMarker.pedalType = SustainPedalMarkerType.Hold;
this.sustainPedals.push(holdMarker);
lastMarker.nextPedalMarker = holdMarker;
holdMarker.previousPedalMarker = lastMarker;
}
}
}
calculateDuration() {
let duration = 0;
for (const voice of this.voices) {
const voiceDuration = voice.calculateDuration();
if (voiceDuration > duration) {
duration = voiceDuration;
}
}
return duration;
}
}
Bar._globalBarId = 0;
/**
* Lists all dynamics.
*/
var DynamicValue;
(function (DynamicValue) {
// common dynamics
/**
* pianississimo (very very soft)
*/
DynamicValue[DynamicValue["PPP"] = 0] = "PPP";
/**
* pianissimo (very soft)
*/
DynamicValue[DynamicValue["PP"] = 1] = "PP";
/**
* piano (soft)
*/
DynamicValue[DynamicValue["P"] = 2] = "P";
/**
* mezzo-piano (half soft)
*/
DynamicValue[DynamicValue["MP"] = 3] = "MP";
/**
* mezzo-forte (half loud)
*/
DynamicValue[DynamicValue["MF"] = 4] = "MF";
/**
* forte (loud)
*/
DynamicValue[DynamicValue["F"] = 5] = "F";
/**
* fortissimo (very loud)
*/
DynamicValue[DynamicValue["FF"] = 6] = "FF";
/**
* fortississimo (very very loud)
*/
DynamicValue[DynamicValue["FFF"] = 7] = "FFF";
// special dynamics
DynamicValue[DynamicValue["PPPP"] = 8] = "PPPP";
DynamicValue[DynamicValue["PPPPP"] = 9] = "PPPPP";
DynamicValue[DynamicValue["PPPPPP"] = 10] = "PPPPPP";
DynamicValue[DynamicValue["FFFF"] = 11] = "FFFF";
DynamicValue[DynamicValue["FFFFF"] = 12] = "FFFFF";
DynamicValue[DynamicValue["FFFFFF"] = 13] = "FFFFFF";
/**
* Sforzando
*/
DynamicValue[DynamicValue["SF"] = 14] = "SF";
/**
* SforzandoPiano
*/
DynamicValue[DynamicValue["SFP"] = 15] = "SFP";
/**
* SforzandoPianissimo
*/
DynamicValue[DynamicValue["SFPP"] = 16] = "SFPP";
/**
* FortePiano
*/
DynamicValue[DynamicValue["FP"] = 17] = "FP";
/**
* Rinforzando 1
*/
DynamicValue[DynamicValue["RF"] = 18] = "RF";
/**
* Rinforzando 2
*/
DynamicValue[DynamicValue["RFZ"] = 19] = "RFZ";
/**
* Sforzato
*/
DynamicValue[DynamicValue["SFZ"] = 20] = "SFZ";
/**
* SforzatoFF
*/
DynamicValue[DynamicValue["SFFZ"] = 21] = "SFFZ";
/**
* Forzando
*/
DynamicValue[DynamicValue["FZ"] = 22] = "FZ";
/**
* Niente
*/
DynamicValue[DynamicValue["N"] = 23] = "N";
/**
* Poco forte
*/
DynamicValue[DynamicValue["PF"] = 24] = "PF";
/**
* SforzatoPiano
*/
DynamicValue[DynamicValue["SFZP"] = 25] = "SFZP";
})(DynamicValue || (DynamicValue = {}));
class MidiUtils {
/**
* Converts the given midi tick duration into milliseconds.
* @param ticks The duration in midi ticks
* @param tempo The current tempo in BPM.
* @returns The converted duration in milliseconds.
*/
static ticksToMillis(ticks, tempo) {
return (ticks * (60000.0 / (tempo * MidiUtils.QuarterTime))) | 0;
}
/**
* Converts the given midi tick duration into milliseconds.
* @param millis The duration in milliseconds
* @param tempo The current tempo in BPM.
* @returns The converted duration in midi ticks.
*/
static millisToTicks(millis, tempo) {
return (millis / (60000.0 / (tempo * MidiUtils.QuarterTime))) | 0;
}
/**
* Converts a duration value to its ticks equivalent.
*/
static toTicks(duration) {
return MidiUtils.valueToTicks(duration);
}
/**
* Converts a numerical value to its ticks equivalent.
* @param duration the numerical proportion to convert. (i.E. timesignature denominator, note duration,...)
*/
static valueToTicks(duration) {
let denomninator = duration;
if (denomninator < 0) {
denomninator = 1 / -denomninator;
}
return (MidiUtils.QuarterTime * (4.0 / denomninator)) | 0;
}
static applyDot(ticks, doubleDotted) {
if (doubleDotted) {
return ticks + ((ticks / 4) | 0) * 3;
}
return ticks + ((ticks / 2) | 0);
}
static applyTuplet(ticks, numerator, denominator) {
return ((ticks * denominator) / numerator) | 0;
}
static removeTuplet(ticks, numerator, denominator) {
return ((ticks * numerator) / denominator) | 0;
}
static dynamicToVelocity(dynamicValue, adjustment = 0) {
let velocity = 1;
switch (dynamicValue) {
case DynamicValue.PPP:
velocity = MidiUtils.MinVelocity + 0 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.PP:
velocity = MidiUtils.MinVelocity + 1 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.P:
velocity = MidiUtils.MinVelocity + 2 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.MP:
velocity = MidiUtils.MinVelocity + 3 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.MF:
velocity = MidiUtils.MinVelocity + 4 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.F:
velocity = MidiUtils.MinVelocity + 5 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.FF:
velocity = MidiUtils.MinVelocity + 6 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.FFF:
velocity = MidiUtils.MinVelocity + 7 * MidiUtils.VelocityIncrement;
break;
// special
case DynamicValue.PPPP:
velocity = 10;
break;
case DynamicValue.PPPPP:
velocity = 5;
break;
case DynamicValue.PPPPPP:
velocity = 3;
break;
case DynamicValue.FFFF:
velocity = MidiUtils.MinVelocity + 8 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.FFFFF:
velocity = MidiUtils.MinVelocity + 9 * MidiUtils.VelocityIncrement;
break;
case DynamicValue.FFFFFF:
velocity = MidiUtils.MinVelocity + 10 * MidiUtils.VelocityIncrement;
break;
// "forced" variants -> a bit louder than normal, same as FF for us
case DynamicValue.SF:
case DynamicValue.SFP:
case DynamicValue.SFZP:
case DynamicValue.SFPP:
case DynamicValue.SFZ:
case DynamicValue.FZ:
velocity = MidiUtils.MinVelocity + 6 * MidiUtils.VelocityIncrement;
break;
// force -> piano, same as F for us
case DynamicValue.FP:
velocity = MidiUtils.MinVelocity + 5 * MidiUtils.VelocityIncrement;
break;
// "rinforced" varaints -> like "forced" but typically for a whole passage
// not a single note, same as FF for us
case DynamicValue.RF:
case DynamicValue.RFZ:
case DynamicValue.SFFZ:
velocity = MidiUtils.MinVelocity + 5 * MidiUtils.VelocityIncrement;
break;
// almost not hearable but still a value
case DynamicValue.N:
velocity = 1;
break;
// A bit weaker than standard F but stronger than MF
case DynamicValue.PF:
velocity = MidiUtils.MinVelocity + ((4.5 * MidiUtils.VelocityIncrement) | 0);
break;
}
// 0 would means note-off (not played) so we need a minimum of 1 to have still a note played
velocity += adjustment * MidiUtils.VelocityIncrement;
return Math.min(Math.max(velocity, 1), 127);
}
}
MidiUtils.QuarterTime = 960;
MidiUtils.MinVelocity = 15;
MidiUtils.VelocityIncrement = 16;
/**
* This public enumeration lists all types of automations.
*/
var AutomationType;
(function (AutomationType) {
/**
* Tempo change.
*/
AutomationType[AutomationType["Tempo"] = 0] = "Tempo";
/**
* Colume change.
*/
AutomationType[AutomationType["Volume"] = 1] = "Volume";
/**
* Instrument change.
*/
AutomationType[AutomationType["Instrument"] = 2] = "Instrument";
/**
* Balance change.
*/
AutomationType[AutomationType["Balance"] = 3] = "Balance";
/**
* A sync point for synchronizing the internal time axis with an external audio track.
*/
AutomationType[AutomationType["SyncPoint"] = 4] = "SyncPoint";
})(AutomationType || (AutomationType = {}));
/**
* Represents the data of a sync point for synchronizing the internal time axis with
* an external audio file.
* @cloneable
* @json
* @json_strict
*/
class SyncPointData {
constructor() {
/**
* Indicates for which repeat occurence this sync point is valid (e.g. 0 on the first time played, 1 on the second time played)
*/
this.barOccurence = 0;
/**
* The audio offset marking the position within the audio track in milliseconds.
* This information is used to regularly sync (or on seeking) to match a given external audio time axis with the internal time axis.
*/
this.millisecondOffset = 0;
}
}
/**
* Automations are used to change the behaviour of a song.
* @cloneable
* @json
* @json_strict
*/
class Automation {
constructor() {
/**
* Gets or sets whether the automation is applied linear.
*/
this.isLinear = false;
/**
* Gets or sets the type of the automation.
*/
this.type = AutomationType.Tempo;
/**
* Gets or sets the target value of the automation.
*/
this.value = 0;
/**
* Gets or sets the relative position of of the automation.
*/
this.ratioPosition = 0;
/**
* Gets or sets the additional text of the automation.
*/
this.text = '';
}
static buildTempoAutomation(isLinear, ratioPosition, value, reference) {
if (reference < 1 || reference > 5) {
reference = 2;
}
const references = new Float32Array([1, 0.5, 1.0, 1.5, 2.0, 3.0]);
const automation = new Automation();
automation.type = AutomationType.Tempo;
automation.isLinear = isLinear;
automation.ratioPosition = ratioPosition;
automation.value = value * references[reference];
return automation;
}
static buildInstrumentAutomation(isLinear, ratioPosition, value) {
const automation = new Automation();
automation.type = AutomationType.Instrument;
automation.isLinear = isLinear;
automation.ratioPosition = ratioPosition;
automation.value = value;
return automation;
}
}
/**
* A single point of a bending graph. Used to
* describe WhammyBar and String Bending effects.
* @cloneable
* @json
* @json_strict
*/
class BendPoint {
/**
* Initializes a new instance of the {@link BendPoint} class.
* @param offset The offset.
* @param value The value.
*/
constructor(offset = 0, value = 0) {
this.offset = offset;
this.value = value;
}
}
BendPoint.MaxPosition = 60;
BendPoint.MaxValue = 12;
/**
* Lists the different bend styles
*/
var BendStyle;
(function (BendStyle) {
/**
* The bends are as described by the bend points
*/
BendStyle[BendStyle["Default"] = 0] = "Default";
/**
* The bends are gradual over the beat duration.
*/
BendStyle[BendStyle["Gradual"] = 1] = "Gradual";
/**
* The bends are done fast before the next note.
*/
BendStyle[BendStyle["Fast"] = 2] = "Fast";
})(BendStyle || (BendStyle = {}));
/**
* Lists all types of bends
*/
var BendType;
(function (BendType) {
/**
* No bend at all
*/
BendType[BendType["None"] = 0] = "None";
/**
* Individual points define the bends in a flexible manner.
* This system was mainly used in Guitar Pro 3-5
*/
BendType[BendType["Custom"] = 1] = "Custom";
/**
* Simple Bend from an unbended string to a higher note.
*/
BendType[BendType["Bend"] = 2] = "Bend";
/**
* Release of a bend that was started on an earlier note.
*/
BendType[BendType["Release"] = 3] = "Release";
/**
* A bend that starts from an unbended string,
* and also releases the bend after some time.
*/
BendType[BendType["BendRelease"] = 4] = "BendRelease";
/**
* Holds a bend that was started on an earlier note
*/
BendType[BendType["Hold"] = 5] = "Hold";
/**
* A bend that is already started before the note is played then it is held until the end.
*/
BendType[BendType["Prebend"] = 6] = "Prebend";
/**
* A bend that is already started before the note is played and
* bends even further, then it is held until the end.
*/
BendType[BendType["PrebendBend"] = 7] = "PrebendBend";
/**
* A bend that is already started before the note is playe